Tags: web-dev ux concept

Accessibility Testing

Date: 2026-08-17


Automated checks catch roughly a third of accessibility issues — the mechanical third. The remaining share needs a keyboard, a screen reader and judgement, and a clean automated scan is routinely mistaken for conformance.


Accessibility testing verifies that people using assistive technology, keyboards, magnification or alternative input can complete tasks.

What automation catches

RELIABLY DETECTED
  missing alt attributes
  insufficient colour contrast
    — Colour Contrast
  form inputs without labels
    — Accessible Forms
  invalid or conflicting ARIA
  missing document language
  duplicate ids
  empty buttons and links

See: Colour Contrast · Accessible Forms

These are mechanical and worth automating, because they’re common, cheap to check, and there’s no reason to ship one.

What automation cannot catch

IS THE ALT TEXT MEANINGFUL?
  alt="image1.jpg" passes

IS THE FOCUS ORDER LOGICAL?
  every element focusable, in a
  nonsensical sequence, passes

DOES THE PAGE MAKE SENSE READ ALOUD?

IS THE ERROR MESSAGE HELPFUL?

CAN THE TASK ACTUALLY BE COMPLETED?

IS THE HEADING STRUCTURE MEANINGFUL?
  h1 → h4 → h2 is flagged; h1 → h2
  with wrong content isn't

[CHECK: current published figures for the proportion of issues automated tooling detects before citing a specific number — the commonly-quoted figures come from particular studies and vary.]

The criteria requiring judgement are the ones that block people, which is why a clean scan is a starting point rather than a result — WCAG.

The layers

1  LINT AS YOU WRITE
     eslint-plugin-jsx-a11y
     ← cheapest, earliest — Linting

2  UNIT / COMPONENT
     axe assertions in component tests

3  E2E PAGE SCANS
     axe against real rendered pages
     — End-to-End Testing

4  KEYBOARD WALKTHROUGH
     manual, 15 minutes, highest yield
     — Keyboard Navigation

5  SCREEN READER WALKTHROUGH
     manual — Screen Readers

6  TESTING WITH DISABLED USERS
     the only test that tells you
     whether it works

See: Linting · End-to-End Testing · Keyboard Navigation · Screen Readers

Layer 4 finds more real problems per minute than 1–3 combined, and needs no tooling — unplug the mouse and try to buy something.

Automating it in tests

import { axe } from 'vitest-axe'
 
test('checkout form has no axe violations', async () => {
  const { container } = render(<CheckoutForm />)
  expect(await axe(container)).toHaveNoViolations()
})

Component-level scanning is better than page-level — failures localise, and it runs on every change rather than on every deploy.

Query by role in ordinary tests too, which makes every functional test a partial accessibility test at no extra cost:

screen.getByRole('button', { name: 'Add to basket' })

If that query fails, the control isn’t reachable by assistive technology — the test catches it without anyone writing an accessibility test — Integration Testing.

The manual checklist

Fifteen minutes, per significant change:

□  Tab through — everything reachable?
□  Focus visible at every step?
       — Focus Management
□  Escape closes what it should?
□  Any keyboard traps?
□  Complete a purchase, keyboard only
□  Zoom to 400% — does it reflow?
□  prefers-reduced-motion on
       — Reduced Motion
□  Screen reader through one journey
□  Greyscale screenshot — anything
   ambiguous?

See: Focus Management · Reduced Motion

“Complete a purchase, keyboard only” is the acceptance test. Everything above it is diagnosis.

Third-party components

The most-missed risk, and it’s yours regardless of who wrote it:

cookie banners
chat widgets
payment iframes
review plugins

A cookie banner trapping focus blocks your entire site for keyboard users before they see anything — and “it’s the vendor’s code” is not a defence to a customer who can’t buy, or to a regulator — Accessibility Law in the UK, Third-Party Scripts.

Test them. They’re rarely covered because they’re not in the codebase.

Where it belongs in the pipeline

BLOCKING          lint rules, component
                  axe assertions
                  → fast, deterministic

REPORTING         full-page scans
                  → a trend, with a ratchet

MANUAL, PER       keyboard walkthrough on
RELEASE           changed journeys

PERIODIC          full audit, ideally
                  external

Ratchet the page-level scans rather than blocking on the existing backlog — fail on new violations, fix the rest opportunistically. Blocking on a full fix means it never starts — Static Analysis.