Skip to content
Latchkey

Playwright "expect(locator).toBeVisible() timeout" in CI

Playwright auto-waited for an element to become visible and the timeout elapsed first. Usually the element renders slower than the expect timeout in CI, is covered by another element, or the selector does not match what is on the page.

What this error means

A web-first assertion fails with "Timed out 5000ms waiting for expect(locator).toBeVisible()." It often passes locally and headed but flakes on a slower CI runner where the element paints late.

Playwright output
Error: Timed out 5000ms waiting for expect(locator).toBeVisible()

Locator: getByRole('button', { name: 'Submit' })
Expected: visible
Received: hidden

Common causes

Element renders slower than the expect timeout in CI

On a loaded runner the UI paints later than locally. The default 5s expect window expires before the element is visible - a timing-only flake.

Element exists but is hidden or covered

The node is in the DOM but display:none, zero-size, or behind an overlay/cookie banner. Playwright correctly reports it as not visible.

Selector does not match the rendered element

A wrong role/name or a markup change means the locator resolves to nothing. This is deterministic, and a longer timeout will not help.

How to fix it

Assert on a real readiness signal

Wait for the network/state that gates the element, and use a resilient role/test-id locator.

cart.spec.ts
await page.goto('/cart');
await page.waitForResponse('**/api/cart');
await expect(page.getByTestId('submit')).toBeVisible();

Raise the timeout for genuinely slow steps

playwright.config.ts
await expect(page.getByTestId('submit')).toBeVisible({ timeout: 15000 });
// or globally in playwright.config.ts: expect: { timeout: 15000 }

How to prevent it

  • Wait on responses/state, never fixed waitForTimeout sleeps.
  • Use role- or test-id-based locators decoupled from styling.
  • Tune the global expect timeout for the slowest CI tier.

Frequently asked questions

What causes ""expect(locator).toBeVisible() ... timeout""?
On a loaded runner the UI paints later than locally. The default 5s expect window expires before the element is visible - a timing-only flake.
How do I fix "expect(locator).toBeVisible() ... timeout"?
Wait for the network/state that gates the element, and use a resilient role/test-id locator.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card