Playwright Auto-wait and Timeout

This chapter provides an in-depth introduction to Playwright's auto-wait mechanism, as well as complete knowledge of manual waiting and timeout configuration.


Why do we need auto-wait

Modern web applications rely heavily on asynchronous rendering, and page content does not load completely in an instant.

In traditional testing frameworks, developers have to writesleeporwaitForThese wait operations are not flexible enough—they either wait too long and slow down the tests, or wait too little and cause flaky tests.

Playwright builds waiting logic into every Locator and Action, fundamentally solving this problem.


Three-layer auto-wait system

Layer 1: Locator Auto-wait

When you create a Locator, Playwright does not search for the element immediately; instead, it starts searching and automatically waits when you perform an action or assertion.

Example

// Create a Locator (the element will not be looked up at this point)
const btn = page.getByRole('button', { name: 'Delayed button' });

// Automatically wait for the button to appear when clicking (waits up to the action timeout)
await btn.click();

Layer 2: Action Operability Check

Before performing an action (click, fill, etc.), Playwright ensures that the element is: Attached → Visible → Stable → Receives Events → Enabled.

Layer 3: Automatic Retry of Assertions

After an assertion fails, it does not immediately report an error; instead, it keeps retrying until the condition is met or a timeout occurs.

Example

// This assertion will keep retrying for 5 seconds until the text appears or times out
await expect(page.getByText('Data loading complete')).toBeVisible();

Manual Waiting Methods

In special scenarios where auto-wait is insufficient, Playwright also provides manual waiting methods.

page.waitForTimeout(ms) — Fixed Wait

Example

// Fixed wait for 2 seconds (generally not recommended)
await page.waitForTimeout(2000);

Try to avoid using it.waitForTimeoutFixed waiting is extremely unstable under device performance differences. Prefer the followingwaitForURL、waitForResponseevent-driven waits.

page.waitForURL() — Wait for URL Change

Example

// Wait for exact URL match
await page.waitForURL('https://www.example.com/dashboard');

// Wait for URL to contain a specific pattern
await page.waitForURL(/dashboard/);

page.waitForLoadState() — Wait for Load State

Example

// Wait for the load event
await page.waitForLoadState('load');

// Wait for DOMContentLoaded
await page.waitForLoadState('domcontentloaded');

// Wait for network idle
await page.waitForLoadState('networkidle');

page.waitForResponse() — Wait for Network Response

Example

// Wait for a specific API response
const response = await page.waitForResponse(
  resp => resp.url().includes('/api/data') && resp.status() === 200
);

// Get response data
const data = await response.json();

page.waitForEvent() — Wait for Event

Example

// Wait for the popup to appear
const dialogPromise = page.waitForEvent('dialog');
await page.getByRole('button', { name: 'Delete' }).click();
const dialog = await dialogPromise;
await dialog.accept();

// Wait for a new page to open
const pagePromise = page.context().waitForEvent('page');
await page.getByRole('link', { name: 'Open in new window' }).click();
const newPage = await pagePromise;

Timeout Configuration Explained

Playwright has 4 types of timeouts, each acting on a different layer:

Timeout TypeConfiguration File LocationDefault ValueApplies To
Test timeouttimeout30000msEntire test case
Expect timeoutexpect.timeout5000msAssertion retry
Action timeoutuse.actionTimeoutNone (unlimited)Element operations (click, fill, etc.)
Navigation timeoutuse.navigationTimeoutNone (unlimited)Page navigation (goto, goBack, etc.)

Global Configuration

Example

// File path: playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  // Total timeout for each test (milliseconds)
  timeout: 60000,

  // Timeout for assertion automatic retry
  expect: {
    timeout: 10000,
  },

  use: {
    // Timeout for each action (click, fill, etc.)
    actionTimeout: 15000,

    // Timeout for each navigation
    navigationTimeout: 30000,
  },
});

Per-call Settings (Higher Priority than Global Configuration)

Example

// Set total timeout for a single test
test.setTimeout(120000);

// Set timeout for a single action
await page.getByRole('button').click({ timeout: 30000 });

// Set timeout for a single navigation
await page.goto('https://www.example.com/', { timeout: 60000 });

Timeout Priority

Per-call settings > Global config file settings > Default values.


Suggestions for Setting Timeouts Reasonably

ScenarioRecommended TimeoutDescription
Local DevelopmentDefault valuesLocal services respond quickly; default values are sufficient.
CI Environment2–3 times the default valueCI machine performance fluctuates significantly.
Slow PagesactionTimeout: 15000Large forms, complex pages
Third-party service callstest.setTimeout(120000)External API responses are slow.
Other Extensions