Wait for text to appear

Let a label, message, or heading settle before you assert on it, without guessing a delay.

A button triggers an update and some text lands a moment later. Wait for the text, not for the clock. A web-first assertion polls the page until the string is there, then returns.

Assert the text with auto-retry

toHaveText() and toContainText() re-check the element until it matches or the timeout runs out. In the Playwright\Testing\expect() helper, both match a substring for compatibility. Use toHaveExactText() when the complete text matters.

php
use function Playwright\Testing\expect;

$page->getByRole('button', ['name' => 'Save'])->click();

expect($page->getByRole('status'))->toHaveText('Changes saved');

The click returns before the server responds. The assertion covers that gap on its own, so there is nothing to time by hand.

Make substring intent explicit

When the node holds more than the part you care about, assert the substring:

php
use function Playwright\Testing\expect;

expect($page->getByRole('alert'))->toContainText('3 items updated');

toContainText() makes the substring intent clear. The testing helper also treats toHaveText() as a substring match, while toHaveExactText() compares the complete text content.

Give a slow update more room

The default timeout covers most cases. Raise it on the one slow step rather than for the whole run:

php
use function Playwright\Testing\expect;

expect($page->getByText('Report ready'))->withTimeout(15000)->toHaveText('Report ready');

withTimeout() takes milliseconds.

The sleep trap

php
sleep(2); // waits for the clock, not the text

sleep(2) is wrong twice over: too short when the server lags, wasted time when it is quick. toHaveText() returns the instant the text matches and fails with a clear message when it never does.

Expected result

The assertion returns only after the expected text is present, or fails with a clear timeout message. No fixed delay is needed.

Go next

← All recipes