Executive Definition
Accessibility testing is the practice of verifying that a product can be perceived, operated, and understood by people with disabilities — including visual, auditory, motor, and cognitive differences. The primary reference standard is the Web Content Accessibility Guidelines (WCAG), currently at version 2.2, published by the W3C's Web Accessibility Initiative. WCAG organises requirements under four principles: perceivable, operable, understandable, and robust (POUR), and grades them across three conformance levels — A, AA, and AAA.
Most product teams target WCAG 2.2 AA. It is the level referenced by the European Accessibility Act, US Section 508, the UK Public Sector Bodies Accessibility Regulations, and most enterprise procurement checklists. Level A is the minimum floor; AAA is aspirational for public-sector and healthcare products. In 2026, shipping without at least WCAG 2.2 AA is a legal risk in most regulated markets, not just an ethical one.
The testing pyramid has three layers. Automated scanners (axe-core, Lighthouse, WAVE, Pa11y) catch about 30–40% of WCAG failures — missing alt text, insufficient contrast, missing form labels, invalid ARIA. Manual keyboard and screen-reader walkthroughs catch structural and semantic issues machines cannot infer — logical focus order, meaningful heading hierarchy, accessible names for icon buttons. User testing with people who rely on assistive tech is the highest-fidelity layer and catches issues neither automation nor sighted testers will notice.
Skipping any layer produces a false-confidence report. Teams that ship with only automated scans have compliant contrast ratios and unreachable modals. Teams that rely only on manual audits catch structural issues but miss regressions between releases. The credible pattern is automation in CI (axe-core in Playwright), scheduled manual audits per major feature, and user testing on flagship releases.
Accessibility testing pays dividends beyond compliance. Semantic HTML, keyboard reachability, and clear labelling improve SEO, reduce automation test flakiness (because selectors become role-based), and make the product usable in constrained contexts — bright sun, small screens, high-latency networks. Treat accessibility as part of the definition of done rather than a pre-launch audit, and the cost drops to near-zero over a release cycle.
Architecture & Production Code
A production accessibility programme runs on three tracks in parallel: automated CI checks, manual audits per feature, and periodic user testing. The tracks feed a single accessibility issue backlog.
┌────────────────────────────────────────────┐
│ Track 1 — CI axe-core scan (every PR) │
│ - fails build on new violations │
│ - reports contrast, labels, ARIA │
└────────────────────┬───────────────────────┘
│
┌────────────────────┴───────────────────────┐
│ Track 2 — Manual audit (per major feature) │
│ - keyboard-only walkthrough │
│ - NVDA + VoiceOver read-through │
│ - zoom to 200%, prefers-reduced-motion │
└────────────────────┬───────────────────────┘
│
┌────────────────────┴───────────────────────┐
│ Track 3 — Assistive tech user testing │
│ - screen-reader users on flagship flows │
│ - motor-impaired users on primary tasks │
└────────────────────┬───────────────────────┘
▼
┌───────────────┐
│ A11y backlog │
│ (Jira tag) │
└───────────────┘The CI track is the safety net. Every pull request runs axe-core against key pages and fails the build if new violations appear. Do not gate on the total count (that punishes anyone who touches legacy pages); gate on delta from main.
The manual track is where structural issues surface. A tester walks the flow with only the keyboard, then with NVDA (Windows) or VoiceOver (macOS/iOS) muted for sighted users. Zoom the page to 200% and verify no content is cut off; enable prefers-reduced-motion and confirm no auto-playing animation persists.
The user-testing track is what turns compliance into usability. Recruit through Fable, AccessWorks, or your local disability employment network. Two sessions per flagship release find problems that no scanner or sighted audit ever will.
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
const CRITICAL_PAGES = [
{ name: "home", url: "/" },
{ name: "checkout", url: "/checkout" },
{ name: "settings", url: "/settings" },
];
for (const page of CRITICAL_PAGES) {
test(`${page.name} has no WCAG 2.2 AA violations`, async ({ page: p }) => {
await p.goto(page.url);
await p.waitForLoadState("networkidle");
const results = await new AxeBuilder({ page: p })
.withTags(["wcag2a", "wcag2aa", "wcag22aa"])
.disableRules(["region"]) // handled by layout template
.analyze();
// Fail on delta rather than total: attach for reporting,
// assert critical severity is zero on new PRs.
const critical = results.violations.filter(v => v.impact === "critical");
expect(critical, JSON.stringify(critical, null, 2)).toHaveLength(0);
});
}
// tests/a11y-keyboard.spec.ts
test("checkout form is fully keyboard operable", async ({ page }) => {
await page.goto("/checkout");
await page.keyboard.press("Tab"); // skip link
await page.keyboard.press("Tab"); // first field
await expect(page.getByLabel("Email")).toBeFocused();
await page.keyboard.type("qa@example.com");
await page.keyboard.press("Tab");
await expect(page.getByLabel("Card number")).toBeFocused();
});Automated vs Manual vs User Accessibility Testing
| Aspect | Automated (axe/Lighthouse) | Manual audit | User testing |
|---|---|---|---|
| WCAG coverage | 30–40% | 70–80% | 95%+ real-world |
| Runs per release | Every commit | Per major feature | Per flagship release |
| Cost per run | Cents | Hours of QA time | Recruit + honoraria |
| Best at catching | Contrast, labels, ARIA | Focus order, semantics | Task success, frustration |
| Misses | Meaning, focus order | Novel assistive tech quirks | Nothing systemic |
| Skip at your peril | Regressions ship silently | Whole classes of defect ship | Real users are excluded |
The three layers are complementary. Automation prevents regression on solved problems; manual audits catch the semantic issues machines cannot infer; user testing validates that the product actually works. Any programme missing a layer ships something broken.
Production Debugging Scenarios
Accessibility failures usually cluster around a handful of misconceptions. Recognising them speeds triage.
Custom component has ARIA but no keyboard support
- Symptom
- Screen reader announces 'button — Sort by date' but the button does not respond to Enter or Space.
- Root cause
- role='button' was added to a div without wiring onKeyDown for Enter and Space.
- Fix
- Prefer a real <button>. If a div is unavoidable, handle both Enter and Space in onKeyDown and set tabIndex={0}.
Contrast passes AAA but fails in dark mode
- Symptom
- Lighthouse reports 4.5:1 contrast; users report unreadable text after switching themes.
- Root cause
- Only the light theme was scanned; dark-theme contrast tokens drifted.
- Fix
- Run axe against every theme variant. Add tokens to a contrast-check test that iterates through data-theme attributes.
Modal traps focus but not tab order
- Symptom
- Tab moves focus outside the modal to the page underneath.
- Root cause
- The modal used autoFocus but no focus trap; last element's Tab did not loop.
- Fix
- Use a focus-trap library (focus-trap-react, radix Dialog) or manually manage Tab from the last focusable element back to the first.
Practice this concept in a real QA interview
Run a live mock with our AI Interview Coach, tune your resume with the ATS Resume Reviewer, and screen live listings on the QA Jobs Radar.