playwright expect().toBeVisible() failed: element never appeared
Diagnoses a failed Playwright toBeVisible assertion when the element never appears, walking through attached-vs-visible checks, app-state fixes, and timeout adjustments. Use it when expect(locator).toBeVisible() fails. Not for click interception by overlays, general locator timeouts on actions, or elements that need frameLocator scoping.
TL;DR
toBeVisible auto-retries for the assertion timeout (default 5s), so a failure means the element never became visible in that window. Confirm the locator matches something attached to the DOM first, then fix the app state or timing that keeps it hidden. Raising the timeout is the last resort, not the first.
Error
Error: expect(locator).toBeVisible() failed
Locator: getByRole('dialog', { name: 'Confirm delete' })
Expected: visible
Received: hiddenSteps
- Temporarily change the assertion to
toBeAttached()and re-run. Expected: this tells you whether the locator is wrong (still fails) or the element exists but stays hidden. - If not attached: fix the locator using the trace viewer's DOM snapshot. Expected:
toBeAttached()passes. - If attached but hidden: drive the UI state that reveals it (click the opener, wait for the API response with
waitForResponse), or check for a CSS or overlay issue in manual reproduction. Expected: the element becomes visible when you reproduce by hand. - If the UI is just slow, extend the assertion:
await expect(dialog).toBeVisible({ timeout: 10000 }). Expected: the assertion passes on slow runs.
When to use
expect(locator).toBeVisible()fails after the full assertion timeout.- A dialog, toast, or dropdown never shows up in the test.
- You need to separate "wrong locator" from "right locator, hidden element".
When not to use
- The element is visible but a click is intercepted (that is a pointer-events problem, not visibility).
- An action like
click()times out rather than an assertion. - The element is inside an iframe (scope with
frameLocatorfirst).
Tool compatibility
- Playwright 1.40 through 1.5x,
@playwright/testrunner. - Web-first assertions (
toBeVisible,toBeAttached,toBeHidden) all share the same retry behavior.
Variant phrasings
expect locator toBeVisible timed out after 5000ms
Same failure with timeout wording. Same steps: check attached first.
element is not visible in playwright assertion
Usually the same toBeVisible failure. Confirm the locator matches a node before debugging visibility.
Why it happens
toBeVisible requires a non-empty bounding box and no visibility: hidden. Common causes are unmet app state (the dialog never opened, the data never loaded), the element rendering at zero size or off-screen, or a wrong locator matching a hidden duplicate node.
Edge cases
- The locator matches a hidden duplicate while the visible node has a different name: tighten the name or scope the locator.
- Mid-animation: the element is transitioning, assert on a stable parent or wait for the animation to settle.
- toBeVisible passes but the click misses: an overlay is intercepting pointer events, a different failure mode.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_edoH9Hs89peHLsx2CKL3DQ
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.