Files
agentic-dev-template/docs/library-decisions/2026-05-19-jest-axe.md
Danijel Martinek 051bfbf062 test(core-ui): add axe-core a11y assertions to CookieConsentBanner
Previous attempt was rejected because the axe-core a11y requirement
had no test infrastructure — ARIA roles were correct but unverified by
a scanner. This adds jest-axe (approved via library-decision trace) and
asserts toHaveNoViolations() for both modal and banner variants.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:36:26 +00:00

5.2 KiB

package, version, tier, decision, date, deciders, adr, lastRevalidated, is-sub-processor, processes-pii, filter-results, verification-commands, accepted-cves
package version tier decision date deciders adr lastRevalidated is-sub-processor processes-pii filter-results verification-commands accepted-cves
jest-axe ^10.0.0 feature approved 2026-05-19
implementer-agent
null null false false
license types maintenance boundary-fit shadow-check eu-residency cve-scan named-consumer socketRisk
MIT @types/jest-axe active pass pass n/a clean pass clean
npm info jest-axe license
ls node_modules/jest-axe/index.d.ts 2>/dev/null && echo native || npm info @types/jest-axe version
cat package.json | grep -E '"(zod|inversify|payload|@trpc/server|superjson|reflect-metadata)"'
npm info jest-axe time.modified
npm info jest-axe time | tail -5
pnpm audit --audit-level=moderate 2>&1 | head -40
npm info jest-axe@10.0.0 dependencies

Filter: license

npm info jest-axe license returns MIT. Within the allowlist.

Filter: types

@types/jest-axe@3.5.9 is available on the npm registry. Community types confirmed present.

Filter: shadow-check

jest-axe is an accessibility testing wrapper around axe-core. It does not shadow any locked must-have (zod, inversify, payload, @trpc/server, superjson, reflect-metadata). Pass.

Filter: boundary-fit

jest-axe is a devDependency targeting packages/core-ui. It is a testing tool only — no runtime imports cross feature or core boundaries. ADR-006, ADR-010, ADR-017 all unaffected. Pass.

Filter: maintenance

Last publish: 2025-03-03T21:15:23.625Z (v10.0.0). That is approximately 14 months before today's date (2026-05-19) — within the 18-month active window. Release cadence shows v9.0.0 in 2024-06-07, v10.0.0 in 2025-03-03. Active.

Filter: eu-residency

jest-axe is a pure in-process testing library. It runs the axe-core engine against a DOM snapshot returned by @testing-library/react. No network calls, no vendor-controlled endpoints, no telemetry. EU residency check is not applicable.

Filter: cve-scan

pnpm audit --audit-level=moderate surfaces two pre-existing high-severity advisories (drizzle-orm SQL injection via @payloadcms/db-postgres, next DoS via @payloadcms/ui). Neither advisory is related to jest-axe. No advisories reference jest-axe, axe-core, jest-matcher-utils, chalk, or lodash.merge. Clean relative to this package.

Filter: named-consumer

Concrete call site: packages/core-ui/src/cookie-consent-banner/cookie-consent-banner.test.tsx. The cookie-consent-banner story 09 acceptance criteria require an axe-core a11y pass (WCAG 2.2 AA), and the previous implementation attempt was rejected specifically because this assertion was absent. The consumer exists today and is blocked on this adoption.

Filter: socketRisk

socket-cli is unavailable in this sandbox environment (deprecated package, @socket.dev/cli not on the registry). Manual dependency audit performed instead:

jest-axe@10.0.0 dependencies:

  • axe-core@4.10.2 — Deque Systems' accessibility engine, industry-standard, widely audited
  • chalk@4.1.2 — terminal coloring by sindresorhus, no install scripts
  • jest-matcher-utils@29.2.2 — Jest core team package, part of facebook/jest
  • lodash.merge@4.6.2 — single lodash function, no network activity

No install scripts, no network calls, no obfuscation. Supply-chain risk assessed as clean.

Prompt: replaces

No existing a11y testing infrastructure is being retired. The component being tested (CookieConsentBanner) had thorough behavioral RTL tests but lacked a structured WCAG assertion. jest-axe adds net-new capability without replacing any existing library.

Prompt: migration-cost-out

Mechanical. jest-axe is confined to test files: import { axe, toHaveNoViolations } from "jest-axe" plus expect.extend(toHaveNoViolations). Removing it requires deleting one devDependency, the expect.extend setup, and the expect(results).toHaveNoViolations() assertions — a straightforward swap to any alternative (e.g., vitest-axe). No data-format dependencies, no runtime coupling.

Prompt: alternatives-considered

  1. vitest-axe — vitest-native fork of jest-axe with near-identical API (axe, toHaveNoViolations). Rejected: smaller community, fewer downloads, less battle-tested against jsdom environments. jest-axe v10 explicitly supports vitest.

  2. @axe-core/react — React devDependency that logs axe violations to the browser console during development. Rejected: designed for runtime dev-time feedback, not structured test assertions. Does not provide toHaveNoViolations() or integrate with vitest's assertion pipeline.

  3. @storybook/addon-a11y — Storybook addon that runs axe in the browser during Storybook sessions. Not rejected but deprioritized: the Storybook stories: [] config means stories are not currently auto-discovered, so the addon would not reliably catch regressions in CI without additional Storybook configuration. jest-axe in vitest is CI-gated deterministically.