Skip to content

Auto Waiting

Playwright automatically waits for elements to be ready before actions and retries assertions until they pass. Understanding this mechanism is key to stable tests.

What Gets Auto-Waited

Before click(), Playwright checks element is attached, visible, stable (not animating), enabled, and receives pointer events. Before fill(), editable state is verified.

Assertions poll the same conditions — a test rarely needs waitForTimeout if locators and expectations are well chosen.

// No sleep needed — click waits for button to be actionable
await page.getByRole('button', { name: 'Load data' }).click();
await expect(page.getByRole('row')).toHaveCount(10);

The row count assertion retries until 10 rows appear or timeout.

Actionability Checks

Action          Auto-wait checks
click           visible, stable, enabled, receives events
fill            visible, enabled, editable
check           visible, stable, enabled
selectOption    visible, enabled
  • Locators auto-wait on action — not when merely created.
  • Navigation goto waits for load state (configurable).
  • Auto-wait respects timeout from config or locator action.
  • Disable only deliberately with { force: true }.

Auto-Wait vs Manual Wait

Prefer auto-wait patterns.

Instead of Use
waitForTimeout(3000) expect(locator).toBeVisible()
Sleep after click Assert result state directly
Retry loop in test expect.poll()
Wait for network idle waitForResponse or route + assert UI
Custom DOM polling Web-first assertion on locator
Fixed delay after navigation await expect(page).toHaveURL(...)

Navigation Load States

await page.goto('/app', { waitUntil: 'domcontentloaded' });
await page.goto('/heavy', { waitUntil: 'networkidle' }); // use sparingly

'networkidle' is discouraged for SPAs with websockets — assert UI instead.

Actionability Checks Before Clicks

Playwright verifies elements are attached, visible, stable (not animating), enabled, and not obscured before clicking — all part of auto-waiting without extra code.

Common Mistakes

  • Adding waitForTimeout everywhere 'just in case'.
  • Assuming auto-wait applies to custom JS variables.
  • Using networkidle on apps with persistent connections.
  • Force-clicking instead of waiting for overlay to close.

Key Takeaways

  • Actions wait for actionability; assertions retry until pass.
  • Manual sleeps are a last resort in Playwright.
  • Assert on user-visible outcomes, not arbitrary timing.
  • Understand load states but prefer DOM assertions.

Pro Tip

If a test needs waitForTimeout, treat it as a smell — record a trace and find what condition is missing.