feat/accessibility-audit
Accessibility is a first-class requirement. Every PR that touches UI must pass the checks below before merge.
The accessibility CI job runs @axe-core/playwright against the quote, policy, claims, and vote routes. No critical violations are permitted. The job uploads a Playwright report as an artifact on failure.
Run locally:
cd frontend
npm install
npm run build
npx playwright test tests/accessibility.spec.ts- Install the axe DevTools browser extension.
- Open each targeted route:
/quote,/policy,/claims,/claims/<id>. - Run the full-page scan. Resolve any critical or serious violations before opening a PR.
Verify these flows using only the keyboard (no mouse):
| Flow | Steps |
|---|---|
| Get a quote | Tab through all form fields → submit → confirm quote preview updates |
| Purchase policy | Complete all 4 wizard steps using Tab / Shift+Tab / Enter / Space |
| File a claim | Complete all 4 wizard steps; confirm focus moves to new step heading on advance |
| Cast a vote | Tab to Approve / Reject buttons → Enter to open confirm modal → Tab within modal → confirm or cancel |
| Connect wallet | Tab to "Connect Wallet" button → Enter → confirm status announced |
Focus must always be visible. After a modal opens, focus must move inside it. After a modal closes, focus must return to the trigger.
Test at minimum one major flow per release with a screen reader:
- macOS / iOS: VoiceOver (
Cmd+F5to toggle) - Windows: NVDA (free) or Narrator
- Android: TalkBack
Checklist:
- Transaction status updates are announced (aria-live regions on wizard and policy pages)
- Step changes in wizards are announced (focus moves to hidden
<h2>with step name) - Quote preview updates are announced on the quote page
- Vote tally countdown is announced via
aria-live="polite" - Modal title is read when dialog opens
- Icon-only buttons have accessible names (aria-label or sr-only text)
- Claim status badges convey outcome via text/shape, not color alone
Verify that setting prefers-reduced-motion: reduce (OS accessibility setting or DevTools emulation) stops all non-essential animations. Loading spinners should become static; slide/fade transitions should be instant.
Each page must have exactly one <h1>. Use the browser Accessibility Tree panel (DevTools → Accessibility) or the HeadingsMap extension to verify a logical heading order with no skipped levels.
Every page must have at minimum: <main>, <nav> (if navigation present), and <footer> (if present). Verify with the Accessibility Tree or axe.
All text must meet WCAG AA contrast ratios (4.5:1 normal text, 3:1 large text). Use the axe scan or the browser color-contrast checker. Claim outcomes (Approved / Rejected / Pending) must not rely on color alone — shape indicators and text labels are required.
When adding new interactive components:
- Icon-only controls must have
aria-labelor a visually hidden label. - Async state changes (transactions, loading) must update an
aria-liveregion. - Multi-step wizards must move focus to a step heading on step change.
- Modals must trap focus and return it to the trigger on close (Radix Dialog handles this automatically).
- Animations must respect
prefers-reduced-motionvia the global CSS rule inglobals.css.
The API E2E suite spins up real Postgres and Redis containers via Testcontainers. You need:
- Docker Desktop (or any Docker-compatible daemon) running locally.
- Node 20+.
No .env file is needed — the global setup injects all ephemeral credentials at runtime.
cd backend
npm ci
npx prisma generate
npm run test:e2eThe first run pulls postgres:16-alpine and redis:7-alpine (~100 MB total). Subsequent runs use the local Docker cache and start in seconds.
Tip: If a test hangs, check that Docker is running:
docker info.
The file backend/src/soroban/golden-vectors.json records the exact ScVal
type and argument order for every critical contract invocation. CI fails if
the builders produce output that no longer matches these vectors.
Refresh the vectors whenever you change:
- Any function signature in
contracts/niffyinsure/src/lib.rs - Argument builders in
backend/src/soroban/soroban.client.tsorbackend/src/tx/tx.service.ts - Enum variants in
contracts/niffyinsure/src/types.rs
cd backend
npm run refresh-vectorsReview the diff carefully:
git diff backend/src/soroban/golden-vectors.json- If the contract ABI changed (argument order, types, new/removed args), bump
_meta.contractSemverin the JSON to match the new contract semver tag. - If only the builder logic changed without an ABI change, leave
contractSemveras-is and explain in the PR description.
Commit the updated file and open a PR. A second engineer must review and approve any vector changes before merge.
Before tagging a release:
- Run
npm run refresh-vectorsand confirm the diff is empty (or intentional). - Confirm
_meta.contractSemvermatches the contract'sCargo.tomlversion. - Update
contracts/deployment-registry.jsonwith the new wasm hash.
- Never commit real private keys (Stellar secret keys start with
S). - Use only placeholder G-addresses and C-addresses in vector
inputs. - The CI job checks for secret-key patterns and will fail if any are found. main