Skip to content

Chapter 20 · Accessibility Testing and Aria Snapshot ​

Chapter goals: Understand the source and YAML syntax of aria snapshots, learn to assert a page's accessible structure with to_match_aria_snapshot(), and bake accessibility checks into daily tests and CI.

20.1 Why Automate Accessibility Testing ​

Accessibility (a11y) is not a "nice-to-have" — it directly affects whether screen-reader users can use your product, and is increasingly a legal requirement in many regions. More importantly, pages that are machine-friendly tend to be more human-friendly too: a button without a proper role and accessible name is just as much a disaster for test automation as for assistive technology.

Traditional a11y audit tools (like axe) scan for "are there violations?"; Playwright offers a complementary视角: snapshot the page's accessibility tree and assert it as a structural contract — if the semantic structure is wrong, the test turns red.

20.2 Understanding Aria Snapshot: YAML-Formatted Accessibility Tree ​

Aria snapshot is Playwright's YAML representation of an element/page's accessibility tree, available since v1.49. Each node describes one accessible element:

text
- role "name" [attribute=value]
  • role: ARIA or HTML implicit role, e.g. heading, button, listitem;
  • "name": accessible name (exact string; /regex/ for pattern match);
  • [attribute=value]: state attributes like checked, disabled, expanded, level, pressed, selected.

View the current page's snapshot directly in code:

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://playwright.dev/python/docs/intro")
    # Print the accessibility structure of the entire sidebar (YAML string)
    print(page.get_by_role("navigation").aria_snapshot())
    browser.close()

Output looks like:

yaml
- navigation "Docs":
  - list:
    - listitem:
      - link "Intro"
    - listitem:
      - link "Writing tests"

Indentation expresses hierarchical nesting — this is the world a screen reader "sees".

20.3 to_match_aria_snapshot(): Structural Assertions ​

The core assertion is expect(page).to_match_aria_snapshot() (full page) or expect(locator).to_match_aria_snapshot() (local region):

python
from playwright.sync_api import expect

def test_heading_structure(page):
    page.goto("https://example.com")

    # Full-page assertion: heading hierarchy is correct
    expect(page).to_match_aria_snapshot("""
      - heading "Example Domain"
      - paragraph
    """)

def test_nav_structure(page):
    page.goto("https://example.com")

    # Local assertion: care only about the nav area, with [level] attribute check
    expect(page.get_by_role("contentinfo")).to_match_aria_snapshot("""
      - contentinfo:
        - link /更多/
    """)

Four matching rules, all from the official docs:

  1. Case-sensitive, but whitespace is collapsed (indentation and newlines do not affect comparison);
  2. Order-sensitive: node order in the template must match the actual tree;
  3. Partial match supported: omitting a name or attribute checks only the concerned部分;
  4. /regex/ syntax for flexible name matching.

20.4 Baking a11y Checks into CI ​

Run aria snapshot assertions alongside your regular tests — they catch regressions before they reach production:

python
def test_page_accessibility_snapshot(page):
    page.goto("/")
    expect(page).to_match_aria_snapshot()   # Auto-generate baseline on first run

Integrate into CI with --update-snapshots on authorized branches; any dev push that changes the accessible structure will fail the check and force a review.

20.5 Chapter Summary ​

  • Aria snapshot = YAML representation of the accessibility tree; each node has role, name, and state attributes;
  • to_match_aria_snapshot() asserts structural correctness with auto-retry;
  • Matching is case-sensitive, order-sensitive, supports partial match and /regex/;
  • Bake into CI: baseline on main, reject structural regressions on feature branches.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What does an aria snapshot node look like?

2. What happens when you call expect(page).to_match_aria_snapshot() without arguments on the first run?

3. Which matching property is NOT true for aria snapshot comparison?

4. What is the recommended CI strategy for aria snapshot tests?

🛠️ Hands-On Exercises ​

  1. Visit any site; print its aria_snapshot() and manually inspect the YAML tree for missing roles or names.
  2. Write an to_match_aria_snapshot() assertion for a component; change one attribute in the HTML and observe the failure diff.
  3. Add an aria snapshot test to your CI workflow; verify that a structural regression fails the pipeline.

Proceed to Chapter 21: WebSocket and Real-Time Application Testing.