Automated accessibility testing usually means one thing: point a scanner at the page, let it check the initial HTML against a set of WCAG rules, and turn green. Missing alt text, an unlabeled input, low-contrast text at load. Caught. Done.
Then a user opens the menu, submits the empty form, expands the accordion, and lands in a state your scanner never saw. The newly revealed panel steals focus and never gives it back. The modal traps a keyboard user with no way out. None of that exists in the first render, so none of it was tested.
That is the gap this post is about. Accessibility is not a property of a page, it is a property of every state a page can reach, and most of those states only exist after someone interacts. The fix is to run your accessibility checks in a real browser, after the interaction, with two complementary tools: axe-core for WCAG rule checks, and keyboard navigation tests for focus order. This walks through both.
The gap: accessibility tests that run in jsdom
The default setup runs your tests in jsdom. Render a component with Testing Library, run axe-core over it with jest-axe or vitest-axe, assert no violations. It is fast, and it is fine for catching the obvious stuff: a button with no accessible name, an input with no label, a misused ARIA attribute.






