## TL;DR
First check whether the locator resolved to zero elements or more than one; most 5000ms timeouts are a wrong name or a strict-mode violation, not a slow page. Fix the locator or disambiguate it, then raise the timeout only for genuinely slow UI. Blindly bumping the timeout hides broken selectors.

## Error
```text
TimeoutError: locator.click: Timeout 5000ms exceeded.
Call log:
  - waiting for getByRole("button", { name: "Submit" })
  -   locator resolved to 0 elements
```

## Steps
1. Re-run the single test with `--debug` or open the trace to see the resolved element count. Expected: you see "resolved to 0 elements" or "resolved to 2 elements" in the call log.
2. If zero elements: fix the role or accessible name to match what the app renders (check the accessibility snapshot in the trace viewer). Expected: the locator resolves to exactly 1 element.
3. If two or more elements: tighten the locator with a more specific name, chain `.first()`, or scope it inside a parent locator. Expected: the locator resolves to exactly 1 element.
4. Only now, if the element is real but slow, pass an explicit timeout: `page.getByRole('button', { name: 'Submit' }).click({ timeout: 15000 })`, or set `timeout` under `use` in the config. Expected: the test passes consistently on slow runs.

## When to use
- An action (click, fill, check) or assertion on a getByRole locator fails with a 5000ms timeout.
- The call log shows the locator resolved to 0 or 2+ elements.
- You need to decide between fixing the selector and raising the timeout.

## When not to use
- The timeout is on a network request or API call, not a locator.
- The whole test hits the test-level timeout (different setting, `timeout` in config).
- You are waiting on navigation or a URL change rather than an element.

## Tool compatibility
- Playwright 1.40 through 1.5x, `@playwright/test` runner.
- Applies to Chromium, Firefox, and WebKit identically.

## Variant phrasings
### locator.getByRole timed out waiting for element
Same failure surfaced on a different action (fill, check, hover). Same diagnosis steps.
### waiting for getByRole resolved to 0 elements
The call-log line that tells you the selector matched nothing. Fix the role or the accessible name.

## Why it happens
The default action timeout is 5000ms, and the locator keeps waiting for the element to become actionable (attached, visible, stable, enabled). Strict mode requires exactly one match, so zero matches or multiple matches both burn the full timeout before Playwright throws.

## Edge cases
- Passes locally, fails in CI: CI is slower, raise the timeout or fix a race instead of blaming the selector.
- Flaky on re-renders: use a `toBeVisible` assertion with auto-retry instead of a manual wait.
- Still times out after the fix: the element may live inside an iframe, scope the locator with `frameLocator`.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_oqj3dM9VLaCK5apWwq2Xww
