Automated Axe Testing Limits
What axe-core catches reliably, the large WCAG surface it cannot, and how to combine automation with manual keyboard and SR testing.
- accessibility
- automated-axe
axe-core (and wrappers like jest-axe, Storybook a11y, Lighthouse) automates checks for a subset of accessibility issues. Deque estimates automation covers only part of WCAG criteria — often cited around 30–50% depending on methodology. Treat green axe as necessary, not sufficient.
What automation catches well
- Missing form labels
- Invalid ARIA attributes / roles
- Empty buttons / links
- Duplicate ids
- Some contrast issues (computed styles)
- Document language missing
- Certain landmark / structure issues
const results = await axe(container);
expect(results.violations).toHaveLength(0);
What it misses (high impact)
| Miss | Why |
|---|---|
| Focus order / traps | Needs interaction |
| Meaningful alt text quality | “dog.jpg” passes if alt exists |
| Keyboard operability of custom widgets | Behavior |
| Screen reader verbosity / context | Human judgment |
| Color alone for meaning in charts | Partial |
| Logical heading misuse that still “has h2s” | Semantics quality |
| Timing, motion, cognitive load | Human |
A perfect score on a mouse-only modal is possible if markup is clean but JS never traps focus.
False confidence patterns
- Running axe only on the empty shell route.
- Disabling rules that fire often instead of fixing.
- Ignoring “needs review” incomplete results.
- No manual pass on primary flows.
Complete strategy
CI: jsx-a11y + axe on components/routes
+ keyboard smoke checklist on PRs for new widgets
+ SR spot checks on release for critical journeys
+ occasional expert audit
See accessibility testing in CI, screen reader testing basics.
Configuring axe wisely
await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.disableRules(['color-contrast']) // only with alternate contrast process
.analyze();
Prefer fixing over disabling. If disable, document the compensating control.
Footguns
- Celebrating Lighthouse 100 a11y while checkout is unusable by keyboard.
- Snapshotting violations without owning tickets.
- Running different rule sets locally vs CI.
Interview out-loud answer
“Axe catches many markup issues in CI, maybe a third to half of WCAG depending on what you count. It doesn’t prove keyboard or screen reader UX. I automate axe, then manually test focus and SR on critical flows.”
Incomplete results
Axe marks some checks incomplete when color contrast can’t be determined (background images, transparency). Don’t treat “0 violations” with many incompletes as a clean bill of health — open the report and sample incompletes manually.
Extra practice
Write a minimal demo in a scratch file or the playground: one happy path, one failure path, and one boundary input. If you cannot exhibit a bug that the pattern prevents, you do not own the concept yet — re-read the primary docs linked below and tighten the example until the failure is obvious.
Notes from real codebases
Teams that succeed here keep the rules mechanical: lint where possible, CI for the rest, and a short human checklist for what automation cannot see. Document exceptions with an owner name and a removal date so “temporary” escapes do not become permanent architecture.
Related on this site
- Accessibility testing in CI
- Keyboard accessibility checklist
- Screen reader testing basics
- WCAG principles POUR
- Color contrast requirements
Further reading
Related guides
- Accessible Combobox PatternBuild or evaluate comboboxes with APG keyboard behavior, aria-expanded/activedescendant, and filterable listbox pairing.
- Accessible Forms ErrorsLabel inputs, associate errors with fields, announce failures, and avoid placeholder-only forms that break accessibility.
- Accessible Menus PatternAPG menu and menubar keyboard model — arrow navigation, escape to close, aria-expanded, and when a disclosure is enough.
- Accessible Modals PatternsModal dialogs that work: focus trap, Escape, return focus, aria-modal, and why native dialog or APG patterns beat div soup.
- Accessible Names ComputationHow browsers compute accessible names from content, labels, aria-label, and labelledby — and how that powers Testing Library queries.