Skip to contentPlayForge

Why does my Playwright test time out, and which timeout is it?

Written by Jatin Thacker, Automation Architect · Updated

Playwright has separate timeouts for the whole test (30 seconds by default), for each assertion (5 seconds) and, optionally, for each action, and the error message names the one that ran out. Read the first line of the error before changing any number.

This answer is one piece of Chapter 13: Waiting and Synchronisation.

  • Auto-Waiting Deep Dive
  • Explicit Waiting Methods
  • Handling Race Conditions
  • Controlling the Clock
  • Practice and interview questions: Waiting & Synchronization

"The test timed out" can mean three different limits:

  • Test timeout, 30 seconds by default: the whole test, including fixtures. Change it with timeout in the config or test.setTimeout(). The error reads Test timeout of ...ms exceeded.
  • Expect timeout, 5 seconds by default: each web-first assertion. Change it with expect: { timeout } or { timeout } on the assertion. The error names the matcher and shows a Timeout: line.
  • Action timeout, none by default: each click, fill and so on. Set it with use: { actionTimeout } or { timeout } on the action. The error reads locator.click: Timeout ...ms exceeded.

Because actions have no limit of their own by default, an action that can never succeed waits until the test timeout ends the test.

The example triggers each one on the same button, which an overlay covers so a click never lands. The first test only sets a 5-second test timeout, so the click runs into it. The second gives the click its own 2 seconds. The third waits 2 seconds for a result that never appears.

The fix is rarely a bigger number. The call log usually says why it waited, here intercepts pointer events.

which-timeout.spec.js(https://practice.learnplayforge.com)
import { test, expect } from '@playwright/test'; // On traps.html section 5 an overlay covers this button, so a click never lands. const url = '/traps.html?mock=static&seed=42'; test('test timeout', async ({ page }) => { test.setTimeout(5000); await page.goto(url); await page.getByTestId('covered-button').click(); }); test('action timeout', async ({ page }) => { await page.goto(url); await page.getByTestId('covered-button').click({ timeout: 2000 }); }); test('expect timeout', async ({ page }) => { await page.goto(url); await expect(page.getByTestId('covered-result')) .toHaveText('Shipment released.', { timeout: 2000 }); });
Output
  1) which-timeout.spec.js:6:1 › test timeout

    Test timeout of 5000ms exceeded.

    Error: locator.click: Test timeout of 5000ms exceeded.

  2) which-timeout.spec.js:12:1 › action timeout

    TimeoutError: locator.click: Timeout 2000ms exceeded.

  3) which-timeout.spec.js:17:1 › expect timeout

    Error: expect(locator).toHaveText(expected) failed

    Locator:  getByTestId('covered-result')
    Expected: "Shipment released."
    Received: "Not released."
    Timeout:  2000ms

  3 failed
Source:Timeouts
Test yourself
Your config sets no timeouts. A click() waits on a button that never becomes clickable. What stops it?

Practised in the full course: the drill Flakiness: Test Timeouts.

See the chapter

AI can write the test now. The job is knowing whether it checks anything. That's what the course teaches, one chapter at a time.

163 lessons · 226 drills · start free

← All questions

Training a team? Talk to us.