
a11y-playwright-testing
Accessibility testing for web applications using Playwright (@playwright/test), TypeScript, and axe-core. Use to write, run, or debug WCAG 2.2 AA checks, keyboard and focus tests, ARIA/semantic validation, accessible names, form labels, color contrast, or screen-reader test patterns. Keywords: accessibility, WCAG, axe-core, keyboard navigation, focus management, ARIA.
- Installs
- 139
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/fugazi/test-automation-skills-agents --skill a11y-playwright-testing- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads a11y-playwright-testing automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Playwright Accessibility Testing (TypeScript)
Comprehensive toolkit for automated accessibility testing using Playwright with TypeScript and axe-core. Enables WCAG 2.2 Level AA compliance verification (superset of 2.1), keyboard operability testing, semantic validation, and accessibility regression prevention.
Activation: This skill is triggered when working with accessibility testing, WCAG compliance, axe-core scans, keyboard navigation tests, focus management, ARIA validation, or screen reader compatibility.
When to Use This Skill
- Automated a11y scans with axe-core for WCAG 2.2 AA compliance
- Keyboard navigation tests for Tab/Enter/Space/Escape/Arrow key operability
- Focus management validation for dialogs, menus, and dynamic content
- Semantic structure assertions for landmarks, headings, and ARIA
- Form accessibility testing for labels, errors, and instructions
- Color contrast and visual accessibility verification
- Screen reader compatibility testing patterns
Do NOT Use For
- Selenium/Java accessibility testing (use
accessibility-selenium-testing). - Authoring Playwright functional/UI E2E specs (use
playwright-e2e-testing). - Full conformance sign-off — automated axe scans catch ~30-40% of issues; manual audit + assistive-tech testing is still required.
Prerequisites
| Requirement | Details |
|---|---|
| Node.js | v18+ recommended |
| Playwright | @playwright/test installed |
| axe-core | @axe-core/playwright package |
| TypeScript | Configured in project |
Quick Setup
# Add axe-core to existing Playwright project
npm install -D @axe-core/playwright axe-core
First Questions to Ask
Before writing accessibility tests, clarify:
- Scope: Which pages/flows are in scope? What's explicitly excluded?
- Standard: WCAG 2.2 AA (default) or specific organizational policy?
- Priority: Which components are highest risk (forms, modals, navigation, checkout)?
- Exceptions: Known constraints (legacy markup, third-party widgets)?
- Assistive Tech: Which screen readers/browsers need manual testing?
Core Principles
1. Automation Limitations
[!] Critical: Automated tooling can detect ~30-40% of accessibility issues. Use automation to prevent regressions and catch common failures; manual audits are required for full WCAG conformance.
2. Semantic HTML First
Prefer native HTML semantics over ARIA. Use ARIA only when native elements cannot achieve the required semantics.
// [ok] Semantic HTML - inherently accessible
await page.getByRole("button", { name: "Submit" }).click();
// [no] ARIA override - requires manual keyboard/focus handling
await page.locator('[role="button"]').click(); // Often a <div>
3. Locator Strategy as A11y Signal
If you cannot locate an element by role or label, it's often an accessibility defect.
| Locator Success | Accessibility Signal |
|---|---|
getByRole('button', { name: 'Submit' }) [ok] | Button has accessible name |
getByLabel('Email') [ok] | Input properly labeled |
getByRole('navigation') [ok] | Landmark exists |
locator('.submit-btn') [!] | May lack accessible name |
Key Workflows
Automated Axe Scan (WCAG 2.2 AA)
import AxeBuilder from "@axe-core/playwright";
import { test, expect } from "@playwright/test";
test("page has no WCAG 2.2 AA violations", async ({ page }) => {
await page.goto("/");
const results = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
Scoped Axe Scan (Component-Level)
test("form component is accessible", async ({ page }) => {
await page.goto("/contact");
const results = await new AxeBuilder({ page })
.include("#contact-form") // Scope to specific component
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
Keyboard Navigation Test
test("form is keyboard navigable", async ({ page }) => {
await page.goto("/login");
// Tab to first field
await page.keyboard.press("Tab");
await expect(page.getByLabel("Email")).toBeFocused();
// Tab to password
await page.keyboard.press("Tab");
await expect(page.getByLabel("Password")).toBeFocused();
// Tab to submit button
await page.keyboard.press("Tab");
await expect(page.getByRole("button", { name: "Sign in" })).toBeFocused();
// Submit with Enter
await page.keyboard.press("Enter");
await expect(page).toHaveURL(/dashboard/);
});
Dialog Focus Management
test("dialog traps and returns focus", async ({ page }) => {
await page.goto("/settings");
const trigger = page.getByRole("button", { name: "Delete account" });
// Open dialog
await trigger.click();
const dialog = page.getByRole("dialog");
await expect(dialog).toBeVisible();
// Focus should be inside dialog
await expect(dialog.getByRole("button", { name: "Cancel" })).toBeFocused();
// Tab should stay trapped in dialog
await page.keyboard.press("Tab");
await expect(dialog.getByRole("button", { name: "Confirm" })).toBeFocused();
await page.keyboard.press("Tab");
await expect(dialog.getByRole("button", { name: "Cancel" })).toBeFocused();
// Escape closes and returns focus to trigger
await page.keyboard.press("Escape");
await expect(dialog).toBeHidden();
await expect(trigger).toBeFocused();
});
Skip Link Validation
test("skip link moves focus to main content", async ({ page }) => {
await page.goto("/");
// First Tab should focus skip link
await page.keyboard.press("Tab");
const skipLink = page.getByRole("link", { name: /skip to (main|content)/i });
await expect(skipLink).toBeFocused();
// Activating skip link moves focus to main
await page.keyboard.press("Enter");
await expect(page.locator('#main, [role="main"]').first()).toBeFocused();
});
POUR Principles Reference
| Principle | Focus Areas | Example Tests |
|---|---|---|
| Perceivable | Alt text, captions, contrast, structure | Image alternatives, color contrast ratio |
| Operable | Keyboard, focus, timing, navigation | Tab order, focus visibility, skip links |
| Understandable | Labels, instructions, errors, consistency | Form labels, error messages, predictable behavior |
| Robust | Valid HTML, ARIA, name/role/value | Semantic structure, accessible names |
Axe-Core Tags
Default: wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22a, wcag22aa (WCAG 2.2 AA). Use best-practice for additional checks. See references/axe-tags-reference.md for full tag list.
Exception Handling
When exceptions are unavoidable:
- Scope narrowly - specific component/route only
- Document impact - which WCAG criterion, user impact
- Set expiration - owner + remediation date
- Track ticket - link to remediation issue
// [no] Avoid: Global rule disable
new AxeBuilder({ page }).disableRules(["color-contrast"]);
// [ok] Better: Scoped exclusion with documentation
new AxeBuilder({ page })
.exclude("#third-party-widget") // Known issue: JIRA-1234, fix by Q2
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa"])
.analyze();
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Axe finds 0 violations but app fails manual audit | Automation covers ~30-40% | Add manual testing checklist |
| False positive on dynamic content | Content not fully rendered | Wait for stable state before scan |
| Color contrast fails incorrectly | Background image/gradient | Use exclude for known false positives |
| Cannot find element by role | Missing semantic HTML | Fix markup - this is a real bug |
| Focus not visible | Missing :focus styles | Add visible focus indicator CSS |
| Dialog focus not trapped | Missing focus trap logic | Implement focus trap (see snippets) |
| Skip link doesn't work | Target missing tabindex="-1" | Add tabindex to main content |
CLI Quick Reference
| Command | Description |
|---|---|
npx playwright test --grep "a11y" | Run accessibility tests only |
npx playwright test --headed | Run with visible browser for debugging |
npx playwright test --debug | Step through with Inspector |
PWDEBUG=1 npx playwright test | Debug mode with pause |
Red Flags
- Treating a clean axe scan as full WCAG conformance — automation covers only ~30-40% of criteria.
- Globally disabling rules (e.g.,
color-contrast) instead of scoped.exclude()with a documented ticket. - Scanning before the page reaches a stable state — async content yields false "0 violations".
- Skipping keyboard/focus tests because axe passed — focus order and traps need explicit tests.
References
| Document | Content |
|---|---|
| Snippets: Setup & Scanning | axe-core setup, helper, and scanning patterns |
| Snippets: Keyboard, Focus, Semantic | Keyboard navigation, focus management, semantic structure |
| Snippets: Visual, Names, Checklist | Visual accessibility, accessible names, critical pages |
| WCAG 2.2 AA Checklist | Manual audit checklist by POUR principle |
| ARIA Patterns: Widgets Part 1 | Fundamentals, dialog, tabs, menu widgets |
| ARIA Patterns: Widgets Part 2 | Accordion, combobox, live regions, tooltip |
| ARIA Patterns: Mistakes & Reference | Common ARIA mistakes and roles quick reference |
External Resources
| Resource | URL |
|---|---|
| WCAG 2.2 Specification | https://www.w3.org/TR/WCAG22/ |
| WCAG Quick Reference | https://www.w3.org/WAI/WCAG22/quickref/ |
| WAI-ARIA Authoring Practices | https://www.w3.org/WAI/ARIA/apg/ |
| axe-core Rules | https://dequeuniversity.com/rules/axe/ |
Verification
- axe-core audit passes —
AxeBuilder.analyze()returns zero critical violations - Keyboard navigation tested — All interactive elements reachable via Tab; focus order is logical
- Color contrast sufficient — WCAG 2.2 AA minimum contrast ratios met (4.5:1 normal text, 3:1 large text)
- WCAG 2.2 AA conformance — Tags
wcag22a/wcag22aaincluded in scans (focus-not-obscured, dragging movements, target-size minimums)
FAQ
What does the a11y-playwright-testing skill do?
Accessibility testing for web applications using Playwright (@playwright/test), TypeScript, and axe-core. Use to write, run, or debug WCAG 2.2 AA checks, keyboard and focus tests, ARIA/semantic validation, accessible names, form labels, color contrast, or screen-reader test patterns. Keywords: accessibility, WCAG, axe-core, keyboard navigation, focus management, ARIA.
How do I install a11y-playwright-testing?
Run npx skills add https://github.com/fugazi/test-automation-skills-agents --skill a11y-playwright-testing in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/a11y-playwright-testing/ (personal) or .claude/skills/a11y-playwright-testing/ (project).
Which AI agents can use a11y-playwright-testing?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is a11y-playwright-testing safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains a11y-playwright-testing?
It is published by fugazi in fugazi/test-automation-skills-agents. It has 139 recorded installs.
More from fugazi/test-automation-skills-agents
playwright-e2e-testing
fugazi/test-automation-skills-agents
Author and maintain versioned Playwright (@playwright/test) TypeScript UI specs for browser user flows. Use when asked to create, run, debug, or refactor E2E tests, form/navigation/auth flows, responsive checks, UI mocking, fixtures, Page Objects, or visual comparisons. Use api-testing for standalone REST/GraphQL contracts and playwright-cli for live browser sessions. Keywords: E2E spec, Playwright test, POM, fixtures, UI regression.
qa-manual-istqb
fugazi/test-automation-skills-agents
Open the skill to read its SKILL.md instructions.
qa-test-planner
fugazi/test-automation-skills-agents
Open the skill to read its SKILL.md instructions.
api-testing
fugazi/test-automation-skills-agents
Open the skill to read its SKILL.md instructions.
webapp-playwright-testing
fugazi/test-automation-skills-agents
Open the skill to read its SKILL.md instructions.
playwright-regression-testing
fugazi/test-automation-skills-agents
Govern Playwright TypeScript regression suites across many tests. Use when asked to plan, select, tier, execute, or optimize suites with risk/change analysis, tags, CI/CD, sharding, flaky-test management, or suite-health metrics; not for authoring one UI spec. Keywords: regression strategy, smoke tests, test selection, CI pipeline, flaky tests, test sharding, impact analysis, git diff.
Popular testing & qa skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
grilling
mattpocock/skills
Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
migrate-to-shoehorn
mattpocock/skills
Migrate test files from as type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace as in tests, or needs partial test data.
run-train
lllllllama/rigorpilot-skills
Rigor Train skill for deep learning research repositories. Use when a documented or selected training command should be run conservatively for startup verification, short-run verification, full kickoff, or resume, with command, config, seed, log, checkpoint, status, and metric evidence written to standardized trainoutputs/. Do not use for environment setup, exploratory sweeps, speculative idea implementation, or end-to-end orchestration.
test-driven-development
obra/superpowers
Use when implementing any feature or bugfix, before writing implementation code
finishing-a-development-branch
obra/superpowers
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work