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¶
- sources/2025-01-07-slack-automated-accessibility-testing-at-slack — Slack's investigation of baking Axe into Playwright's Locator interaction methods hit exactly this abstraction boundary; landing architecture was the explicit-invocation-via-fixture shape.
Related¶
- systems/playwright — the framework exposing Locator auto-wait.
- patterns/a11y-checks-via-playwright-fixture-extension — the canonical resolution shape.