ScreenshotNeo

BlogHow-to

How to Use ARIA Snapshots for Accessibility Testing

Use Playwright ARIA snapshots to check accessible structure, choose the right scope, review updates safely, and understand what the assertions can prove.

By the ScreenshotNeo team4 October 20267 min read

Playwright ARIA snapshots let you assert that the accessible structure exposed for a page or component matches a YAML template. Use expect(page).toMatchAriaSnapshot() for a page-level contract and expect(locator).toMatchAriaSnapshot() when a component or region is the contract. These checks can catch changes to exposed roles, accessible names, hierarchy, and states or properties included in the template; they do not replace interaction tests or a broader accessibility evaluation.

The matcher was added in Playwright v1.60. Check your installed Playwright version and its current API reference before adopting these examples. See the Playwright API reference and ARIA snapshots guide.

How do I use ARIA snapshots in Playwright?

Add the assertion to a test after bringing the interface into the state whose accessible structure matters. This TypeScript example checks the main region after navigating to account settings:

import { test, expect } from '@playwright/test';

test('account settings exposes its main controls', async ({ page }) => {
  await page.goto('https://example.com/account/settings');

  await expect(page.getByRole('main')).toMatchAriaSnapshot(`
    - heading "Account settings"
    - button "Save changes"
  `);
});

The template is a compact representation of the accessible structure. It uses roles such as heading and button, their accessible names, and their relationship in the tree. Put the assertion after the relevant UI state is ready; for a dialog, for example, open it first and assert its contents within the dialog locator.

Pick a scope that matches the test

  • Page scope: use page when the test owns the page-wide structure and broad structural changes should be visible.
  • Region or component scope: use a locator when the test owns a component, dialog, navigation area, or other focused region. This keeps unrelated page changes from breaking the assertion.

A locator-scoped assertion can look like this:

const dialog = page.getByRole('dialog', { name: 'Delete project' });

await expect(dialog).toMatchAriaSnapshot(`
  - heading "Delete project"
  - button "Cancel"
  - button "Delete"
`);

Use a role-based locator when it expresses the user-facing target clearly. If there are multiple matching regions, narrow the locator so the assertion has one unambiguous owner.

Write a useful snapshot contract

Do not snapshot every exposed detail by default. Decide which semantics are part of the test’s purpose, then constrain those details. A form test may care about its heading, field labels, and submit control. A tab test may care about the selected tab state and the associated panel. A page-shell test may care about landmarks and their order.

Names, states, properties, and hierarchy

Accessible names are often central to whether controls can be identified. Include a name when changing it would break the user-relevant contract. Include a state or property when it matters to the current test, such as whether a tab is selected or a control is expanded. Preserve hierarchy when grouping conveys meaning, such as a dialog containing its title and actions.

A snapshot is order-sensitive. The template describes relationships in sequence, so rearranging represented children can cause a mismatch. An omitted name or attribute leaves that detail unconstrained, which can make a template more tolerant. Choose deliberately: every unconstrained detail is one the assertion will not protect.

Choose child matching strictness

Playwright supports child matching modes:

  • contain is the default: the expected children can be present without requiring the complete child list to match.
  • equal requires the complete child list at the relevant level to match.
  • deep-equal applies exact child matching throughout the nested structure.

Use the default containment when unrelated additions should not break a focused test. Use equal or deep-equal when the complete structure is an explicit part of the contract. Exact matching can make tests more sensitive to intentional or incidental changes, so keep its scope narrow.

Generate, inspect, and store snapshots

There are several ways to establish a starting template. Playwright’s code generator can help produce a starter snapshot; you can also inspect the current structure with page.ariaSnapshot() or locator.ariaSnapshot(), or begin with an empty template and let the assertion report the mismatch.

const snapshot = await page.getByRole('main').ariaSnapshot();
console.log(snapshot);

Keep a short, local assertion inline when it is easiest to read beside the test. Save a named .aria.yml file when a longer snapshot benefits from separate review or reuse. In either case, the test should make clear which UI state the snapshot represents and why its scope and strictness are appropriate.

How do I update an ARIA snapshot safely?

  1. Run the test and inspect the reported diff. Identify which roles, names, states, properties, or relationships changed.
  2. Decide whether the change is intended. A changed accessible name or missing control may indicate a real regression rather than a baseline to refresh.
  3. If the UI change is intentional, update with npx playwright test --update-snapshots.
  4. Review the resulting patch. Confirm that each changed semantic detail is expected and that the test still expresses the intended user-facing contract.
  5. Run the test again without update mode so the assertion verifies the committed template.

Playwright documents patch, three-way, and overwrite snapshot update-source methods. Choose the method that fits your repository workflow, and review generated changes before accepting them. An update command changes the expected result; it does not establish that the new structure is accessible or correct.

What does a Playwright ARIA snapshot test actually check?

A passing assertion means the accessible structure represented to Playwright matched the template under the selected matching rules and chosen scope. Depending on the template, this can check exposed roles, names, hierarchy, and included states or properties.

It does not by itself establish that keyboard operation works, focus moves correctly, the visual interface is understandable, a particular screen reader announces the interface as intended, or all applicable accessibility requirements are met. Combine structural snapshots with interaction tests for keyboard and state behavior, and with appropriate accessibility evaluation for the product and context.

Use native HTML semantics when they provide the appropriate behavior and meaning. WAI-ARIA supplies missing semantics or enhances host-language semantics where needed; it is not a reason to add ARIA indiscriminately. The WAI-ARIA 1.2 Recommendation describes its purpose as conveying author intent to assistive technologies.

Common problems and fixes

Symptom Likely cause What to do
toMatchAriaSnapshot is missing or unrecognized The installed Playwright version predates the v1.60 matcher, or the project uses a different language binding or API version. Check the installed package and the API reference for that version. Upgrade deliberately if the project can adopt the newer API.
The snapshot assertion fails after a UI change A role, accessible name, state, hierarchy, or child order changed; the change may be intentional or a regression. Inspect the diff and the rendered state. Fix unintended semantics; update the template only after validating intentional changes.
A test fails when an unrelated child is added The template uses exact matching or constrains more structure than the test needs. Use containment where additions are acceptable, or narrow the locator to the component contract.
A snapshot passes despite a detail the test should protect The template omits that name, attribute, state, or relationship, or containment permits extra children. Add the relevant detail and choose stricter child matching if the complete list is part of the contract.
The assertion sees an unexpected or incomplete structure The test captured the page before the intended state was ready, or it selected the wrong scope. Perform the action that establishes the state, wait using a meaningful application condition, and verify the locator points to the intended region.
A large snapshot is hard to review The test covers too much page structure or includes details unrelated to its purpose. Split the contract into focused locator assertions and keep only user-relevant semantics in each template.

Performance, reliability, and maintenance

ARIA snapshots are most useful when the tested state is deterministic and the asserted region is no broader than necessary. Stabilize the UI through the same actions and application conditions a user-facing test requires; avoid relying on arbitrary timing where a state-based condition is available. A focused locator generally limits unrelated sources of snapshot churn.

Strictness is a maintenance choice. Containment tolerates additional children, while exact matching makes additions and reordering visible. Neither is universally better: protect the contract the test owns, and avoid snapshots so broad that routine page edits create noisy failures. Generated templates and update commands are starting points for review, not approvals of changed behavior.

Or skip the browser setup

If your accessibility work also needs clean page screenshots for visual review or bug reports, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF, and it can capture full pages or selected elements. Its cookie and consent handling removes known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with the page verdict and billing status reported in response headers. AI agents can use its MCP tools to take screenshots, inspect page information, and capture PDFs.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/account/settings -o shot.webp

See the ScreenshotNeo API documentation for request options. Python and Node.js examples, along with configuration for viewport, full-page capture, selectors, waiting, and output format, are in the documentation.

There are 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo’s free plan.

FAQ

Can an ARIA snapshot replace an accessibility audit?

No. It checks a represented structural contract. Keyboard behavior, focus, visual presentation, assistive technology behavior, and broader requirements need other checks.

Should I snapshot the whole page or a component?

Use the scope the test owns: page scope for a page-wide contract, and a locator for a component or region whose structure should be isolated.

Should snapshots be inline or stored in a file?

Use inline templates when they stay short and local. Use a named .aria.yml file when the template is long enough that separate review is clearer.

Does adding ARIA always improve accessibility?

No. Prefer appropriate native semantics; use ARIA where native semantics are missing or need enhancement.