Skip to content

test(web): fail on axe violations in ui fragments - #332

Open
anabelle wants to merge 1 commit into
theam:mainfrom
anabelle:test/web-a11y-guard
Open

anabelle wants to merge 1 commit into
theam:mainfrom
anabelle:test/web-a11y-guard

Conversation

@anabelle

@anabelle anabelle commented Sep 7, 2026

Copy link
Copy Markdown

Refs #331. First slice of the accessibility guard proposed there.

What changes

Adds apps/web/test/a11y.test.tsx: a fragment-scoped axe-core guard in the default web test suite. Component trees are server-rendered with renderToString into a jsdom fragment and run through axe. No browser, network, or credentials, so it fits the deterministic default suite. docs/testing.md documents the tier and its boundary: color contrast, focus order, page-level landmarks, and keyboard flows stay with the manual browser pass.

First coverage: @facility/ui primitives (Button, ButtonLink, PillTag, Callout, Terminal, Metric, Field with all three controls, LegendChip, StatusDot, Eyebrow, NumeralAnchor, Divider), CiStatusLink, and the Markdown evidence renderer.

Two dev-only dependencies are added to apps/web: axe-core and jsdom. They resolve through the lockfile supply-chain policy without exceptions.

The guard caught something on its first run

Callout hardcodes an <h3> (packages/ui/src/primitives.tsx:134). Under a page <h1> with no <h2> in between, heading order skips a level and axe fails. The test fixture documents the constraint by including the <h2>. Whether Callout should accept a configurable level is left to the issue.

Verification

  • pnpm --filter @facility/web test — 6 files, 36 tests passed (4 new)
  • pnpm --filter @facility/web typecheck — clean
  • pnpm exec biome check apps/web/test/a11y.test.tsx apps/web/package.json docs/testing.md — clean after auto-fix of import order
  • pnpm --filter @facility/web build — clean
  • node guards/run.mjs — 2 guards ran, 0 failed
  • pnpm install — lockfile passes supply-chain policies

Not run: full pnpm verify (needs local PostgreSQL via Docker; this change touches no API, database, or workspace boundary) and the manual browser pass (no runtime behavior changed).

Effects

  • No user-visible behavior change; no persistence, migration, or compatibility effect.
  • No security or money surface touched. The new dependencies are dev-only and confined to apps/web tests.
  • Release classification: test: — no release on its own.

Add a fragment-scoped accessibility guard to the web app test suite:
server-rendered component trees run through axe-core in jsdom with no
browser, network, or credentials. First coverage: the @facility/ui
primitives, labeled form controls, CI status text, and markdown
evidence. The guard found one latent issue on first run: Callout
hardcodes an h3, so it skips heading order under an h1 without an h2.
The fixture documents that constraint; making the level configurable
stays with the issue.

Refs theam#331
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant