← Back to libraryQuestion 172 of 273
🎭PlaywrightIntermediate

Diagnosing Auto-Wait Failures & Flakiness

📌 Definition:

Even with auto-waiting, tests can fail or flake when an actionability check never becomes true (element stays hidden, disabled, or covered), when the locator is ambiguous, or when the test races an animation or network call. Diagnosing means reading Playwright's precise error and the trace rather than adding blind sleeps.

📖 Detailed Explanation:

When an action times out, Playwright's error states exactly which check failed — e.g. 'element is not visible', 'element is outside of the viewport', 'element intercepts pointer events' (something is on top of it), or 'locator resolved to 2 elements' (strictness violation). Each points to a real cause: a modal overlay, a sticky header covering the target, a lazy-loaded element, or a genuinely disabled control. The fix is almost never a longer sleep; it's addressing the condition — waiting for the overlay to disappear, scrolling into view (which click does automatically), disambiguating the locator, or waiting for the network response the UI depends on. The Trace Viewer's DOM snapshots before/after the failing step usually reveal the cause instantly.

🔑 Key Points:
  • Read the error: it names the failing actionability check (visible, stable, enabled, intercepts pointer events)
  • 'intercepts pointer events' = another element (overlay/toast/sticky header) is on top
  • 'resolved to N elements' = strictness violation; the locator is ambiguous
  • Race conditions usually mean asserting/acting before a needed network response
  • Use the trace, not a longer waitForTimeout, to find the true cause
🌍 Real-World Example:

A click on 'Submit' fails with 'element intercepts pointer events'. The trace shows a cookie-consent banner overlapping the button. The fix isn't a sleep — it's dismissing the banner (or asserting it's gone) before clicking, so the button is actually reachable.

📎 Code Example:
// FLAKY: acting before the overlay clears
await page.getByRole('button', { name: 'Submit' }).click(); // 'intercepts pointer events'

// FIX: remove the blocker first, then act
await page.getByRole('button', { name: 'Accept cookies' }).click();
await expect(page.getByRole('dialog', { name: 'Cookies' })).toBeHidden();
await page.getByRole('button', { name: 'Submit' }).click();

// FIX for a data-dependent action: wait for the response it relies on
await Promise.all([
  page.waitForResponse(r => r.url().includes('/api/validate') && r.ok()),
  page.getByRole('button', { name: 'Continue' }).click(),
]);
🎯 Scenario-Based Interview Question:

Scenario: A test flakes ~1 in 10 runs with 'Timeout exceeded ... element intercepts pointer events' on a button that's clearly visible in the screenshot. What's happening and how do you fix it properly?