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;
}