e2e-tests/playwright/docs/accessibility/index.md
Welcome to Mattermost's accessibility testing documentation. This guide covers how to write comprehensive accessibility tests that ensure our application meets WCAG 2.1 AA compliance standards and provides an inclusive experience for all users.
specs/accessibility/@accessibility and feature-specific tagsaxe fixture for scanning, toMatchAriaSnapshot for semantic structureAccessibility tests follow a hierarchical organization by product area:
specs/accessibility/
├── common/ # Shared components across products
│ ├── login.spec.ts
│ ├── reset_password.spec.ts
│ └── signup_user_complete.spec.ts
├── channels/ # Channels product area
│ ├── settings_dialog/ # Settings dialog page/component
│ │ ├── notifications.spec.ts
│ │ ├── settings.spec.ts
│ │ └── notifications.spec.ts-snapshots-a11y/ # Aria snapshots
│ │ ├── desktop-and-mobile-section.yml
│ │ ├── email-notifications-section.yml
│ │ └── keywords-that-get-highlighted-section.yml
│ ├── account_menu_keyboard.spec.ts
│ ├── intro_channel.spec.ts
│ └── theme_settings.spec.ts
└── [future-products]/ # Boards, Playbooks, etc.
└── [page-or-component]/
└── test.spec.ts
channels/, boards/, playbooks/settings_dialog/, channel_header/, post_menu/notifications.spec.ts, theme_picker.spec.ts[component-name]-section.yml, [feature-name]-modal.ymlAccessibility tests should cover these key areas:
/**
* @objective Clear description of what accessibility aspect is being verified
*
* @precondition Special setup conditions (omit if using standard setup)
*/
test('descriptive test title', {tag: ['@accessibility', '@feature_tag']}, async ({pw, axe}) => {
// # Setup user and navigate to target
const {user} = await pw.initSetup();
const {page, channelsPage} = await pw.testBrowser.login(user);
await channelsPage.goto();
// # Navigate to component under test
await page.getByRole('button', {name: 'Settings'}).click();
// # Perform accessibility interaction (keyboard navigation, etc.)
await page.keyboard.press('Tab');
const targetElement = page.getByRole('dialog', {name: 'Settings'});
await pw.toBeFocusedWithFocusVisible(targetElement);
// * Verify accessibility compliance with automated scan
const results = await axe.builder(page).include('[role="dialog"]').analyze();
expect(results.violations).toHaveLength(0);
// * Verify semantic structure with aria snapshot
await expect(targetElement).toMatchAriaSnapshot({
name: 'component-state.yml',
});
});
Aria snapshots capture the accessibility tree structure, ensuring proper semantic markup and screen reader experience.
Use External .yml Files (Recommended):
const notificationsPanel = page.getByRole('region', {name: 'Notifications'});
await expect(notificationsPanel).toMatchAriaSnapshot({
name: 'notifications-panel.yml',
});
Use Inline Snapshots:
await expect(element).toMatchAriaSnapshot(`
- tabpanel "notifications":
- heading "Notifications" [level=3]
- link "Learn more":
- /url: https://example.com/notifications?uid=${user.id}&sid=${clientConfig.DiagnosticId}
- button "Edit Desktop notifications"
`);
[test-file].spec.ts-snapshots-a11y/desktop-notifications-section.yml, keywords-modal-expanded.ymlWhen UI structure changes, update aria snapshots:
# Update all accessibility snapshots
npm run test:a11y-update-snapshots
# Update specific test snapshots
npm run test -- specs/accessibility/channels/settings_dialog/notifications.spec.ts --update-snapshots
# Update all snapshots including visual snapshots
npm run test:update-snapshots
All accessibility tests must include:
@accessibility - Primary accessibility identifier@settings, @notifications, @login, etc.@snapshots - For tests including aria snapshotsFor visual verification needs beyond accessibility tree structure (such as focus indicators, high contrast mode, or visual layout validation), consider adding visual screenshot tests at specs/visual/. Visual tests complement accessibility testing by capturing the actual rendered appearance.
See the main README.md for visual testing guidelines and setup.
specs/accessibility/ for patterns