Agent Skillsfugazi/test-automation-skills-agents › a11y-playwright-testing

a11y-playwright-testing

GitHub

基于 Playwright、TypeScript 和 axe-core 的 Web 应用无障碍自动化测试工具,支持 WCAG 2.2 AA 合规验证、键盘导航、焦点管理及 ARIA 语义检查。

skills/a11y-playwright-testing/SKILL.md fugazi/test-automation-skills-agents

Trigger Scenarios

进行 WCAG 合规性扫描 编写键盘导航与焦点管理测试 验证 ARIA 属性及语义结构

Install

npx skills add fugazi/test-automation-skills-agents --skill a11y-playwright-testing -g -y
More Options

Use without installing

npx skills use fugazi/test-automation-skills-agents@a11y-playwright-testing

指定 Agent (Claude Code)

npx skills add fugazi/test-automation-skills-agents --skill a11y-playwright-testing -a claude-code -g -y

安装 repo 全部 skill

npx skills add fugazi/test-automation-skills-agents --all -g -y

预览 repo 内 skill

npx skills add fugazi/test-automation-skills-agents --list

SKILL.md

Frontmatter
{
    "name": "a11y-playwright-testing",
    "license": "Complete terms in LICENSE.txt",
    "description": "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."
}

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:

  1. Scope: Which pages/flows are in scope? What's explicitly excluded?
  2. Standard: WCAG 2.2 AA (default) or specific organizational policy?
  3. Priority: Which components are highest risk (forms, modals, navigation, checkout)?
  4. Exceptions: Known constraints (legacy markup, third-party widgets)?
  5. 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:

  1. Scope narrowly - specific component/route only
  2. Document impact - which WCAG criterion, user impact
  3. Set expiration - owner + remediation date
  4. 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 passesAxeBuilder.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/wcag22aa included in scans (focus-not-obscured, dragging movements, target-size minimums)

Version History

  • 4d874b6 Current 2026-08-20 02:16

    将合规标准从WCAG 2.1升级至2.2 AA,并优化文档结构。

  • 49935c0 2026-07-25 08:22

Same Skill Collection

skills/accessibility-selenium-testing/SKILL.md
skills/api-testing/SKILL.md
skills/grill-me-qa/SKILL.md
skills/playwright-cli/SKILL.md
skills/playwright-e2e-testing/SKILL.md
skills/playwright-regression-testing/SKILL.md
skills/qa-investigation/SKILL.md
skills/qa-manual-istqb/SKILL.md
skills/qa-test-planner/SKILL.md
skills/webapp-playwright-testing/SKILL.md
skills/webapp-selenium-testing/SKILL.md

Metadata

Files
0
Version
db514b5
Hash
27d44074
Indexed
2026-07-25 08:22

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-17 04:58
浙ICP备14020137号-1