Poll until a condition is met

Let assertions retry for you, and write a bounded polling loop only for a condition no assertion covers.

Most waits are already handled for you: web-first assertions poll the page until it reaches the expected state. Write your own loop only when the condition is not something an assertion can express. When you do, bound it with a timeout and fail with a clear message. Never guess with a fixed sleep().

First, let the assertion retry

Before writing any loop, check whether an assertion already covers the case. expect() polls on its own, and you can tune both ends of that polling.

php
use function Playwright\Testing\expect;

expect($page->getByRole('status'))
    ->withTimeout(20000)
    ->withPollInterval(250)
    ->toHaveText('Ready');

withTimeout() sets the budget in milliseconds. withPollInterval() sets how often it re-checks. For text, counts, values, and visibility, this is all you need.

Poll a condition no assertion covers

When the condition is arbitrary, for example a value you compute from several reads, write a bounded loop. Track a deadline, re-check on each pass, and pause a short interval between passes.

php
$deadline = microtime(true) + 10.0; // 10 second budget
$pollMs = 200;

do {
    $count = $page->getByRole('row')->count();
    $total = (int) $page->getByTestId('total')->innerText();

    if ($count === $total) {
        break;
    }

    if (microtime(true) >= $deadline) {
        throw new RuntimeException(
            "Row count {$count} never matched reported total {$total}"
        );
    }

    usleep($pollMs * 1000);
} while (true);

The loop re-reads the page each pass, so it sees fresh state. The deadline caps the wait. The exception message names what failed, so a timeout tells you why.

Why this is not a fixed sleep

usleep() here is the gap between checks, not the wait itself. The loop exits the moment the condition holds, and never runs past the deadline. A fixed sleep(10) is different in kind: it always waits the full ten seconds, and still offers no proof the condition is true when it wakes up.

php
sleep(10); // always slow, and never checks anything

Pitfalls

  • Keep the poll interval short, but not zero. A tight busy loop hammers the transport for no gain.
  • Always set a deadline. A loop with no timeout hangs the whole run when the condition never holds.
  • Prefer an assertion whenever one fits. The loop is the fallback, not the default.

Expected result

The loop exits as soon as the named condition is true, or fails with a message that includes the last observed values. It should never hang indefinitely.

Go next

← All recipes