Skip to content

CONCEPT Cited by 1 source

Playwright Locator auto-wait

Definition

Playwright's Locator is the object representing a way to find an element on a page. Unlike a static handle, it re-resolves the selector on each action and builds in auto-waiting: before any interaction (click, fill, hover), Playwright automatically waits for the element to be attached to the DOM, visible, stable (not animating), and enabled. This makes test code stable against async rendering without explicit waitForX calls sprinkled throughout.

// Auto-wait is implicit:
await page.locator('button[data-testid="submit"]').click();
// Playwright waits for: attached → visible → stable → enabled → clickable
// before dispatching the click.

This abstraction is what makes Playwright tests robust. It is also what blocks whole-page-audit integrations from being embedded into interaction primitives.

The tension with whole-page audits

Whole-page audits (accessibility, visual regression, performance snapshots) need to run when the entire page or key component tree is fully rendered. Locator auto-wait only guarantees the specific element's readiness — the rest of the page may still be loading, hydrating, or running post-render effects.

If you bake a whole-page audit into Locator.click() (canonical example: run Axe after every click), you get:

  • Audits running at the wrong time — the clicked button is ready, but a modal that opens in response is not yet rendered. The Axe audit misses the modal's a11y violations entirely, or flags false-positives from the half-rendered state.
  • Unreliable audit results — the same test run twice produces different violation lists because the audit point is non-deterministic relative to async rendering.

The failed alternatives

Slack explored using deprecated waitForElement-style APIs to control audit timing; Playwright's own docs discourage these. Verbatim: "These older methods are less optimized, causing performance degradation, potential duplication of errors, and conflicts with the abstraction model that Playwright follows."

The tension is abstraction-level mismatch: Locator is an element-level abstraction, whole-page audits are a page-level concern.

The canonical resolution

Don't bake whole-page audits into Locator interaction methods. Instead, expose them as an explicit test-author-invoked helper on a custom Playwright fixture, called at page-ready moments the author knows:

await page.locator('nav .settings').click();
await page.waitForURL(/settings/);
await slack.utils.a11y.runAxeAndSaveViolations();  // explicit

The test author retains control over when the audit runs, at a point they know the page is ready. The fixture provides the ergonomics without breaking the auto-wait abstraction.

Generalisation

Any whole-X validation (where X is page / component tree / visual state / performance snapshot) faces the same tension against element-level auto-wait primitives:

  • Visual regression screenshots need the full page rendered.
  • Performance snapshots (Largest Contentful Paint, layout shifts) need the page to have settled.
  • Memory / leak audits need all post-click effects to have run.

The canonical resolution in every case is explicit invocation at page-ready moments rather than auto-triggering inside element-level interaction primitives.

Seen in

Last updated · 470 distilled / 1,213 read