Modern QA2026Accessibility Trees via Playwright — tiles
Log inJoin
26 / 74 · 10 Visual & Accessibility Testing · axe-core Integration← prev⊞ allnext →☰ Read as one page

5.3Accessibility Trees via Playwright

Playwright can access the browser's accessibility tree, which represents what assistive technologies actually see:

// tests/accessibility/tree-inspection.spec.ts
import { test, expect } from '@playwright/test';

test('navigation has correct accessible structure', async ({ page }) => {
    await page.goto('/');

    // Get the full accessibility tree snapshot
    const snapshot = await page.accessibility.snapshot();

    // Find the navigation landmark
    const nav = findNode(snapshot, { role: 'navigation' });
    expect(nav).not.toBeNull();
    expect(nav.name).toBe('Main navigation');

    // Verify all nav links are present and accessible
    const links = nav.children.filter((child: any) => child.role === 'link');
    const linkNames = links.map((l: any) => l.name);
    expect(linkNames).toContain('Home');
    expect(linkNames).toContain('Products');
    expect(linkNames).toContain('Cart');
    expect(linkNames).toContain('Account');
});

test('form has proper label associations', async ({ page }) => {
    await page.goto('/register');

    const snapshot = await page.accessibility.snapshot();

    // Find all text inputs in the accessibility tree
    const inputs = findAllNodes(snapshot, { role: 'textbox' });

    for (const input of inputs) {
        // Every text input must have a name (label)
        expect(input.name).toBeTruthy();
        expect(input.name.length).toBeGreaterThan(0);
        // Name should not be a placeholder (common mistake)
        expect(input.name).not.toMatch(/enter|type here/i);
    }
});

function findNode(root: any, criteria: any): any {
    if (Object.entries(criteria).every(([k, v]) => root[k] === v)) return root;
    for (const child of root.children || []) {
        const found = findNode(child, criteria);
        if (found) return found;
    }
    return null;
}

function findAllNodes(root: any, criteria: any): any[] {
    const results: any[] = [];
    if (Object.entries(criteria).every(([k, v]) => root[k] === v)) results.push(root);
    for (const child of root.children || []) {
        results.push(...findAllNodes(child, criteria));
    }
    return results;
}