All challenges · Core Interactions

Challenge 13 of 29 · Building fluency · Core Interactions

Wait for Dynamic Content Without Sleeps

Start something that finishes later, without adding a fixed delay. You learn why Playwright waits for you and why sleeps make tests slow and flaky.

Skills you will practise

  • auto-waiting
  • no fixed sleeps
  • delayed content

The concept

Modern pages load data after the first render: a spinner appears, a request finishes, results arrive. A fixed delay such as waitForTimeout(5000) guesses how long that takes. Guess too short and the test fails on a slow CI runner; guess too long and every run wastes time.

Playwright is built to avoid guessing. Actions like click() and fill() auto-wait for the element to be attached, visible, stable, enabled and able to receive events. Web-first assertions such as expect(locator).toBeVisible() or toHaveText() keep retrying until the condition is true or the timeout (5 seconds by default) is reached.

So the rule is: wait for a state, not for a time. Describe what “done” looks like and assert on it.

The fragile version

Fragile
await page.getByRole('button', { name: 'Load results' }).click();
await page.waitForTimeout(5000);
const text = await page.locator('#results').textContent();
expect(text).toContain('3 results');

Why it breaks: The sleep is either too long (slow) or too short (flaky), and textContent() reads once with no retry.

A robust Playwright version

Robust
await page.getByRole('button', { name: 'Load results' }).click();
await expect(page.getByText('3 results')).toBeVisible();
// Need more than 5s? Raise the timeout for this check only:
await expect(page.getByRole('status')).toHaveText('Done', { timeout: 15000 });

The test finishes as soon as the content arrives and only fails if it genuinely never does.

This is a general example on a made-up page, not the challenge’s reference solution.

Common mistakes

  • Leaving waitForTimeout in committed tests; the Playwright docs say it is for debugging only.
  • Mixing non-retrying reads (textContent, isVisible) with plain expect.
  • Raising the global timeout instead of the one slow check.

FAQ

Is waitForTimeout bad in Playwright?

For real tests, yes. It is meant for debugging; prefer web-first assertions.

What does Playwright auto-wait for?

Before actions it checks the element is visible, stable, enabled and receives events, depending on the action.

How do I wait for a spinner to disappear?

await expect(spinner).toBeHidden().

Try it

Practise this in Challenge 13. You write the code in the browser editor with no setup. It runs in a fresh Chromium, a hidden validator checks what actually happened, and you get pass or fail, the logs and a video of the run. Create a free account to open the practice page and its hints. The reference solution and the hidden validator are shown only after you pass. We never publish solutions here.

Practise this challenge free