L5 · Non-functional depth
L5Core4 min read

Accessibility: WCAG 2.2, axe, screen readers

Automated tooling finds perhaps a third of real accessibility problems. The rest needs someone who has actually navigated the product by keyboard and heard it read aloud. High-value, still scarce, increasingly a legal requirement.

Accessibility bugs rarely show up in a normal test pass because most test suites never check for them. A button with no label, a modal that traps focus, or contrast too low to read all pass a functional test cleanly while still locking real users out.

This guide covers the WCAG standard, the POUR principles behind it, and how to add automated axe-core checks to a QA suite. The goal is catching these gaps before release, similar in spirit to performance testing tools that catch a different class of invisible regression.

WCAG levels: A, AA, AAA

The Web Content Accessibility Guidelines (WCAG) define three conformance levels, each building on the last.

  • Level A: the baseline. Missing this means some users cannot use the product at all, such as images with no alt text or content that only works with a mouse.
  • Level AA: the practical target for almost every product and the one referenced by most legal requirements (ADA, EN 301 549, Section 508). It covers color contrast ratios, resizable text, and consistent navigation.
  • Level AAA: the strictest level, often impractical for full sites since some criteria conflict with certain content types. Most teams apply AAA selectively rather than site-wide.

WCAG 2.1 added mobile and low-vision criteria on top of 2.0. WCAG 2.2, published in late 2023, added nine new success criteria including focus appearance and consistent help placement. Target AA unless a contract or regulation names AAA explicitly.

The POUR principles

Every WCAG success criterion falls under one of four principles, and they are a useful mental model even before you memorize specific rules.

  • Perceivable: information must be presentable in ways users can perceive, such as text alternatives for images and captions for video.
  • Operable: all functionality must work via keyboard alone, with no time limits that can't be extended.
  • Understandable: content and interface behavior must be predictable, with clear labels and error messages.
  • Robust: content must work with current and future assistive technology, which mostly means valid, semantic HTML.

Automated testing with axe-core

axe-core is the open source rules engine behind most automated accessibility tooling, including the Chrome DevTools Accessibility panel. It scans rendered DOM against WCAG success criteria and returns violations with the failing element, the rule broken, and a fix link.

Three wrappers make it easy to drop into existing suites:

  • jest-axe: for component and unit tests, asserting expect(results).toHaveNoViolations() on rendered output.
  • cypress-axe: for Cypress end-to-end tests, running a scan after each page or flow with cy.checkA11y().
  • @axe-core/playwright: for Playwright, using AxeBuilder to scan a page or a specific region.
a11y.spec.js
const { test, expect } = require('@playwright/test')
const AxeBuilder = require('@axe-core/playwright').default

test('checkout page has no serious a11y violations', async ({ page }) => {
  await page.goto('/checkout')

  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa'])
    .analyze()

  const serious = results.violations.filter(
    (v) => v.impact === 'serious' || v.impact === 'critical',
  )

  expect(serious).toEqual([])
})

What automated tools catch, and what they miss

Industry estimates put automated coverage at roughly 30 to 40 percent of WCAG success criteria. axe-core reliably catches missing alt text, insufficient color contrast, missing form labels, invalid ARIA attributes, and duplicate IDs. It cannot judge whether alt text is meaningful, whether a tab order makes logical sense, or whether a screen reader announcement is actually helpful in context.

That gap means manual testing stays mandatory for AA compliance. Keyboard-only navigation through every critical flow matters most. Add at least one pass with a screen reader (VoiceOver, NVDA, or JAWS), plus a review of focus order and visible focus indicators, since those catch issues automation cannot evaluate.

Consider a checkout form that ships with a Playwright axe scan already green. The scan does not fail because every input has a label and contrast passes.

But a QA engineer tabbing through the form finds the focus indicator jumps from the email field straight to the submit button, skipping the promo code field. It was added later with a positive tabindex. Automation reported zero violations; five minutes of keyboard testing found a real blocker for keyboard-only users.

A practical workflow for QA engineers

Treat accessibility scans like any other regression gate rather than a one-off audit.

  1. Add an axe-core scan to component tests so new UI is checked the moment it is built, before it reaches a full page.
  2. Add a page-level scan in your end-to-end suite for every critical user flow: sign up, checkout, settings.
  3. Fail the build only on serious and critical impact violations at first; minor and moderate findings can go to a backlog so the gate doesn't become noise.
  4. Wire the scan into the same pipeline stage as your other test suites, following the same gating pattern described in CI/CD for test suites. Treat a11y failures the same way you treat any other broken build, not as a separate follow-up ticket, so flaky or ignored scans don't quietly stop protecting anything.
  5. Schedule a recurring manual pass, quarterly at minimum, focused on keyboard and screen reader flows that automation cannot verify.

Questions people ask

Is WCAG 2.2 required if we already comply with 2.1?

WCAG 2.2 is additive. Meeting 2.1 AA does not automatically satisfy 2.2's new criteria, so review the nine additions separately, especially focus appearance and dragging alternatives.

Can axe-core replace manual accessibility testing entirely?

No. It catches a meaningful share of structural and markup issues but cannot judge context, meaning, or usability, which is why keyboard and screen reader testing stay part of the process.

Which axe-core wrapper should we start with?

Match your existing stack. Use jest-axe if you already run Jest component tests, cypress-axe for Cypress suites, and @axe-core/playwright for Playwright, since each integrates with the runner you already have.