Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
7bd623e
feat(atomic-a11y): scaffold new package for accessibility tooling
y-lakhdar Feb 13, 2026
2cf42d6
feat(atomic-a11y): add shared types, guards, constants and WCAG data …
y-lakhdar Feb 16, 2026
af3262b
feat(atomic-a11y): add vitest a11y reporter and merge-shards
y-lakhdar Feb 16, 2026
94a34f0
feat(atomic-a11y): add OpenACR converter modules
y-lakhdar Feb 16, 2026
74af535
Merge branch 'main' into feat/a11y-package-scaffold
y-lakhdar Feb 16, 2026
efa402b
Merge branch 'feat/a11y-package-scaffold' into feat/a11y-shared-found…
y-lakhdar Feb 16, 2026
e05f330
Merge branch 'feat/a11y-shared-foundation' into feat/a11y-reporter
y-lakhdar Feb 16, 2026
8e7bbed
Merge branch 'feat/a11y-reporter' into feat/a11y-openacr
y-lakhdar Feb 16, 2026
f95508f
docs(atomic-a11y): add PR dependency graph for the a11y PR chain
y-lakhdar Feb 16, 2026
b5dc51a
Merge branch 'feat/a11y-package-scaffold' into feat/a11y-shared-found…
y-lakhdar Feb 16, 2026
461ce15
Merge branch 'feat/a11y-shared-foundation' into feat/a11y-reporter
y-lakhdar Feb 16, 2026
eea174c
Merge branch 'feat/a11y-reporter' into feat/a11y-openacr
y-lakhdar Feb 16, 2026
471838d
update axe-core dep
y-lakhdar Feb 16, 2026
b97a25b
clean deps
y-lakhdar Feb 16, 2026
7f6c675
clean deps
y-lakhdar Feb 16, 2026
f6fd40c
Merge branch 'feat/a11y-package-scaffold' into feat/a11y-shared-found…
y-lakhdar Feb 16, 2026
87801d2
remove hand-written rules
y-lakhdar Feb 16, 2026
0b3caf0
Merge branch 'feat/a11y-shared-foundation' into feat/a11y-reporter
y-lakhdar Feb 16, 2026
1aedae1
refactor(atomic-a11y): adapt reporter to use derived WCAG data
y-lakhdar Feb 16, 2026
f7b57ef
Merge branch 'feat/a11y-reporter' into feat/a11y-openacr
y-lakhdar Feb 16, 2026
b4afa13
refactor(atomic-a11y): defer unused exports to downstream PRs
y-lakhdar Feb 16, 2026
0042dd9
Merge branch 'feat/a11y-shared-foundation' into feat/a11y-reporter
y-lakhdar Feb 16, 2026
16d6250
fix(atomic-a11y): restore wasExecutedDirectly in reporter branch
y-lakhdar Feb 16, 2026
4aee3cd
Merge branch 'feat/a11y-reporter' into feat/a11y-openacr
y-lakhdar Feb 16, 2026
e0527c0
add agent
y-lakhdar Feb 16, 2026
3d90b19
clean PR
y-lakhdar Feb 16, 2026
a6a88bb
lock
y-lakhdar Feb 16, 2026
bee703d
add script to generate rules
y-lakhdar Feb 16, 2026
585cc7d
hook script to build
y-lakhdar Feb 16, 2026
5ffceab
reduce pr scope
y-lakhdar Feb 16, 2026
f25233d
Apply suggestion from @y-lakhdar
y-lakhdar Feb 16, 2026
7f145a8
feat(atomic-a11y): add axe-core to WCAG criteria bridge
y-lakhdar Feb 16, 2026
6354e0e
feat(atomic-a11y): add reporter utility functions
y-lakhdar Feb 16, 2026
dcba2f0
feat(atomic-a11y): add VitestA11yReporter and shard merger
y-lakhdar Feb 16, 2026
fcf5b83
test(atomic-a11y): add tests for reporter and merge-shards
y-lakhdar Feb 16, 2026
e60d0b4
feat(atomic): wire VitestA11yReporter into storybook test config
y-lakhdar Feb 16, 2026
d2744d1
knip and dep cleaning
y-lakhdar Feb 16, 2026
a1d62f2
fix reporter
y-lakhdar Feb 16, 2026
862c439
refactor(atomic-a11y): extract shared sort comparator and unify summa…
y-lakhdar Feb 16, 2026
23112a0
refactor(atomic-a11y): fix import paths to use shared modules directly
y-lakhdar Feb 16, 2026
840e926
refactor(atomic-a11y): split reporter-utils into focused modules
y-lakhdar Feb 17, 2026
0ce8238
refactor(atomic-a11y): replace TestUtils with direct function exports
y-lakhdar Feb 17, 2026
7039603
remove sisyphus
y-lakhdar Feb 17, 2026
4e8111a
refactor(atomic-a11y): extract merge-shards to separate PR
y-lakhdar Feb 17, 2026
9626d40
feat(atomic-a11y): add merge-shards for parallel a11y report aggregation
y-lakhdar Feb 17, 2026
61496ce
feat(atomic-a11y): export merge-shards API and add CLI script
y-lakhdar Feb 17, 2026
086864e
lock
y-lakhdar Feb 17, 2026
0abcf4c
lock
y-lakhdar Feb 17, 2026
6ec3281
add builder
y-lakhdar Feb 17, 2026
dd2dd0c
refactor(atomic-a11y): improve reporter robustness and JSDoc
y-lakhdar Feb 17, 2026
56ae711
remove test
y-lakhdar Feb 17, 2026
463405a
update agent.md files
y-lakhdar Feb 17, 2026
6f08cb4
Delete packages/atomic-a11y/PR-DEPENDENCY-GRAPH.md
y-lakhdar Feb 17, 2026
314dcf7
lock and knip
y-lakhdar Feb 17, 2026
b33828f
Merge branch 'feat/a11y-package-scaffold' into feat/a11y-shared-found…
y-lakhdar Feb 17, 2026
7299b3c
lock
y-lakhdar Feb 17, 2026
39a678c
remove error parsing and knip
y-lakhdar Feb 17, 2026
594b23c
merge
y-lakhdar Feb 17, 2026
8cd45b3
add back axe-core
y-lakhdar Feb 17, 2026
e5c1445
Merge branch 'feat/a11y-reporter' into feat/a11y-merge-shards
y-lakhdar Feb 18, 2026
2f17078
remove tsx dep
y-lakhdar Feb 18, 2026
6c4c49f
fix merge
y-lakhdar Feb 20, 2026
0450337
clean
y-lakhdar Feb 20, 2026
bb8b9fd
merge
y-lakhdar Feb 20, 2026
4a87d4f
merge
y-lakhdar Feb 20, 2026
698a34c
refactor
y-lakhdar Feb 24, 2026
bf73e99
knip
y-lakhdar Feb 24, 2026
ca5de58
merge
y-lakhdar Feb 24, 2026
3e48554
Add generated files
developer-experience-bot[bot] Feb 24, 2026
9a05a2c
simplify
y-lakhdar Feb 24, 2026
dd726e3
Merge branch 'feat/a11y-merge-shards' into feat/a11y-openacr
y-lakhdar Feb 24, 2026
bc507ee
apply corrections
y-lakhdar Feb 24, 2026
182b421
merge
y-lakhdar Feb 24, 2026
232d7c8
Add generated files
developer-experience-bot[bot] Feb 24, 2026
dd5493c
Add generated files
developer-experience-bot[bot] Feb 24, 2026
5014c96
docs(atomic-a11y): add JSDoc to exported functions and manual audit g…
y-lakhdar Feb 24, 2026
322e8a6
chore(atomic-a11y): extract openacr tests to dedicated PR
y-lakhdar Feb 24, 2026
9d72599
udpate guide
y-lakhdar Feb 24, 2026
ab20258
knip
y-lakhdar Feb 24, 2026
8547fa6
add readme
y-lakhdar Feb 24, 2026
9e1eb96
knip
y-lakhdar Feb 24, 2026
804674f
match openacr schema
y-lakhdar Feb 24, 2026
8ac2a1b
simplify types
y-lakhdar Feb 24, 2026
6b3e2d5
simplify
y-lakhdar Feb 26, 2026
d26e8a3
exclude example audit file
y-lakhdar Feb 26, 2026
ed2cebe
apply corrections
y-lakhdar Feb 26, 2026
7760e8d
Merge branch 'feat/a11y-merge-shards' into feat/a11y-openacr
y-lakhdar Feb 26, 2026
bbe73d4
add interactive tests to reporter
y-lakhdar Mar 25, 2026
f058663
setup storybook with interactive test foundation
y-lakhdar Mar 25, 2026
670ca42
add missing index file
y-lakhdar Mar 25, 2026
a1fa5f5
fix: update a11y interactive test helpers to match actual Atomic impl…
y-lakhdar Mar 26, 2026
97f3d67
feat(a11y): capture interactive test pass/fail status in reporter pip…
y-lakhdar Mar 26, 2026
3c996cc
clean storybook a11y utils
y-lakhdar Mar 26, 2026
1f2003e
Refactor listbox accessibility tests
y-lakhdar Mar 30, 2026
af007e8
Export InteractiveA11yOptions type from listbox.js
y-lakhdar Mar 30, 2026
12887e8
Merge branch 'feat/a11y-interactive' into feat/a11y-merge-shards
y-lakhdar Mar 30, 2026
b7d4772
Merge branch 'feat/a11y-merge-shards' into feat/a11y-openacr
y-lakhdar Mar 30, 2026
0e8ff0b
merge interactive tests
y-lakhdar Mar 30, 2026
b672834
Merge branch 'feat/a11y-merge-shards' into feat/a11y-openacr
y-lakhdar Mar 30, 2026
790aed8
merge interactive tests
y-lakhdar Mar 30, 2026
61404a6
Update json-to-openacr.ts
y-lakhdar Mar 30, 2026
c8d5964
small fix
y-lakhdar Mar 30, 2026
c78af92
Merge branch 'feat/a11y-openacr' of github.com:coveo/ui-kit into feat…
y-lakhdar Mar 30, 2026
691a8a3
revert old change
y-lakhdar Mar 30, 2026
0387978
Apply suggestions from code review
y-lakhdar Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"Numberof",
"nusse",
"omnibox",
"openacr",
"ondeselect",
"onhighlightchange",
"onsuggestionselected",
Expand Down Expand Up @@ -309,6 +310,7 @@
"Unsubscribers",
"uparrow",
"upvoted",
"VPAT",
"visi",
"visio",
"Vite",
Expand Down
104 changes: 104 additions & 0 deletions packages/atomic-a11y/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# @coveo/atomic-a11y

**Generated:** 2026-02-17
**Commit:** 56ae711d8
**Branch:** feat/a11y-reporter

## OVERVIEW

Accessibility auditing and reporting package for Coveo Atomic components. Captures axe-core results from Storybook/Vitest tests, maps them to WCAG 2.2 AA criteria, and emits structured JSON reports.

## STRUCTURE

```
atomic-a11y/
├── src/
│ ├── data/ # WCAG criteria definitions + axe-to-WCAG mappings
│ ├── reporter/ # Vitest reporter (main business logic) → see src/reporter/AGENTS.md
│ ├── shared/ # Types, constants, guards, sorting utilities
│ ├── __tests__/ # Empty — tests removed during refactoring
│ └── index.ts # Public API surface
├── scripts/ # WCAG criteria code generator (fetches W3C JSON)
├── reports/ # Generated a11y report artifacts (JSON)
├── turbo.json # Turbo task config (build outputs only)
└── package.json # Private package, ESM ("type": "module")
```

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Understand the public API | `src/index.ts` | All exported symbols |
| Modify report structure | `src/shared/types.ts` | `A11yReport`, `A11yComponentReport`, `A11yCriterionReport`, `A11ySummary` |
| Change how axe results become WCAG criteria | `src/reporter/axe-integration.ts`, `src/data/axe-rule-mappings.ts` | Tag parsing + prebuilt map |
| Change how the final JSON is assembled | `src/reporter/report-builder.ts` | `buildA11yReport()` — transforms accumulators into `A11yReport` |
| Adjust report output paths/defaults | `src/shared/constants.ts` | `DEFAULT_A11Y_REPORT_OUTPUT_DIR`, `DEFAULT_WCAG_22_AA_CRITERIA_COUNT` (55) |
| Update WCAG criteria data | Run `pnpm generate:wcag` | Auto-generates `src/data/wcag-criteria.ts` from W3C JSON |
| Change component/category extraction | `src/reporter/storybook-extraction.ts` | Regex-based path parsing |
| Read package metadata (versions) | `src/reporter/reporter-utils.ts` | `readPackageMetadata()` reads `package.json` for axe-core/storybook versions |

## CODE MAP

| Symbol | Type | Location | Role |
|--------|------|----------|------|
| `VitestA11yReporter` | class | `src/reporter/vitest-a11y-reporter.ts` | Core: implements Vitest `Reporter`, accumulates results, writes JSON |
| `buildA11yReport` | function | `src/reporter/report-builder.ts` | Transforms `Map<string, ComponentAccumulator>` → `A11yReport` |
| `A11yReport` | interface | `src/shared/types.ts` | Root report shape: `{report, components, criteria, summary}` |
| `A11yComponentReport` | interface | `src/shared/types.ts` | Per-component automated results |
| `A11yCriterionReport` | interface | `src/shared/types.ts` | Per-WCAG-criterion coverage/conformance |
| `A11ySummary` | interface | `src/shared/types.ts` | Rollup metrics: counts, coverage percentages |
| `ComponentAccumulator` | interface | `src/reporter/reporter-utils.ts` | Mutable per-component state with `Set<string>` for deduplication |
| `wcagCriteriaDefinitions` | const | `src/data/wcag-criteria.ts` | Auto-generated WCAG 2.2 A+AA criteria (DO NOT EDIT) |
| `getCriterionMetadata` | function | `src/data/criterion-metadata.ts` | Lookup criterion name/level/version by ID |
| `buildAxeRuleCriteriaMap` | function | `src/data/axe-rule-mappings.ts` | Builds `Map<ruleId, criteriaIds[]>` from axe-core rules |
| `isA11yReport` / `isRecord` | function | `src/shared/guards.ts` | Runtime type guards |
| `compareByNumericId` / `compareByName` | function | `src/shared/sorting.ts` | Locale-aware sorting for criteria IDs and component names |

## CONVENTIONS

- **ESM only**: `"type": "module"` — all imports use `.js` extensions even for `.ts` source files
- **No path aliases**: Uses relative imports (no `@/` configured in tsconfig)
- **Strict TypeScript**: `strict: true`, target ES2022, `moduleResolution: NodeNext`
- **`catalog:` versions**: `typescript` and `vitest` use pnpm catalog references (workspace-level pinning)
- **Private package**: Not published (`"private": true`), consumed internally within the monorepo
- **Build = codegen + tsc**: `pnpm build` runs `generate:wcag` first, then `tsc`
- **Reporter never throws**: All Vitest hooks use `try/catch` with `this.warn()` to avoid breaking test runs

## ANTI-PATTERNS (THIS PROJECT)

- **DO NOT** manually edit `src/data/wcag-criteria.ts` — it is auto-generated; run `pnpm generate:wcag` instead
- **DO NOT** throw from reporter lifecycle hooks — use `this.warn()` instead
- Conformance values on criteria are always `'notEvaluated'` in automated reports — manual audit sets final conformance
- Stencil components are tracked but `stencilExcluded: true` in summary — Lit is the target framework

## DATA FLOW

```
Storybook Test Run
→ Vitest calls onTestCaseResult() per test case
→ Filter: only project.name.startsWith('storybook')
→ Extract: axe results from meta.reports (populated by @storybook/addon-a11y)
→ Map: axe rules → WCAG criteria via tag parsing (wcagXYZ → X.Y.Z)
→ Accumulate: per-component violations/passes/incomplete/inapplicable + criteria coverage
→ onTestRunEnd(): buildA11yReport() → components[] + criteria[] + summary → write JSON
→ Output: a11y-report.json (+ shard variant if --shard CLI flag)
```

## COMMANDS

```bash
pnpm build # Generate WCAG data + compile TypeScript
pnpm test # Run vitest (unit + integration) — currently no test files
pnpm generate:wcag # Re-fetch WCAG criteria from W3C and regenerate src/data/wcag-criteria.ts
```

## NOTES

- **No tests currently**: `src/__tests__/` is empty — test file was removed during refactoring
- **Shard support**: Only via `--shard=N/M` CLI flag (env var support was removed); writes both `a11y-report.json` and `a11y-report.shard-N.json`
- **Component detection**: Relies on `atomic-*` naming convention in module paths and story IDs; non-atomic components silently skipped
- **Category detection**: Extracted from path segments (`commerce/`, `search/`, `insight/`, `ipx/`, `common/`, `recommendations/`) or story ID prefixes
- **Framework detection**: `.new.stories.tsx` = Lit, `.stories.tsx` = Stencil
- **PR chain**: This package is being built incrementally — see `PR-DEPENDENCY-GRAPH.md` for merge order
- **Report consumers**: Downstream PRs (#7124-#7126) add OpenACR generation, CLI scripts, and wiring into `packages/atomic`
- **Report builder throws**: Unlike the reporter class, `buildA11yReport()` throws if `axe-core` or `storybook` versions are missing from package metadata
71 changes: 71 additions & 0 deletions packages/atomic-a11y/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# @coveo/atomic-a11y

Accessibility auditing and reporting for Coveo Atomic components. Captures axe-core results from Storybook/Vitest tests, maps them to WCAG 2.2 AA criteria, and produces structured reports in JSON and [OpenACR](https://github.com/GSA/openacr) YAML (VPAT 2.5).

> This is a **private** internal package — not published to npm.

## Pipeline

```
Storybook tests (axe-core)
→ VitestA11yReporter → a11y-report.json (per shard)
→ mergeA11yShardReports() → a11y-report.json (merged)
→ transformJsonToOpenAcr() → openacr.yaml → VPAT markdown
```

## Usage

```ts
// vitest.config.ts — capture axe results during Storybook tests
import { VitestA11yReporter } from '@coveo/atomic-a11y';

export default defineConfig({
test: {
reporters: [new VitestA11yReporter({ outputDir: 'reports' })],
},
});
```

```ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? We have pnpm a11y:merge-shards and pnpm a11y:vpat

If we don't then we could just remove mergeA11yShardReports and transformJsonToOpenAcr from index.ts.

// After test run — merge shards (if using --shard)
import { mergeA11yShardReports } from '@coveo/atomic-a11y';

await mergeA11yShardReports({ inputDir: 'reports' });
```

```ts
// Generate OpenACR YAML for VPAT
import { transformJsonToOpenAcr } from '@coveo/atomic-a11y';

await transformJsonToOpenAcr({
inputFile: 'reports/a11y-report.json',
outputFile: 'reports/openacr.yaml',
});
```

## Scripts

```bash
pnpm build # Generate WCAG data + compile TypeScript
pnpm test # Run unit tests
pnpm a11y:merge-shards # Merge shard reports from parallel CI runs
pnpm a11y:vpat # Generate OpenACR YAML + VPAT markdown
```

## Manual audits

Automated testing covers ~30-40% of WCAG criteria. The rest requires human review. QA creates JSON baseline files that feed into the OpenACR pipeline alongside automated results.

**→ [Manual Audit Guide](docs/manual-audit-guide.md)**

## Structure

```
src/
├── data/ WCAG criteria definitions (auto-generated)
├── reporter/ Vitest reporter + shard merging
├── openacr/ JSON → OpenACR YAML converter
├── shared/ Types, constants, guards, sorting
├── __tests__/ Unit tests
└── index.ts Public API
```
9 changes: 9 additions & 0 deletions packages/atomic-a11y/a11y/a11y-overrides.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
Comment thread
y-lakhdar marked this conversation as resolved.
"overrides": [
{
"criterion": "1.4.2",
"conformance": "not-applicable",
"reason": "Atomic components do not produce audio output."
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file as is doesn't seem super useful 😅

Should we fill it with sample data? Or just remove it? Or is it just there so that the reports folder is kept? If so we can just add a .gitkeep file instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. this is something i forgot to fill. even tho it is explained in the readme. I will update the file and commit it. good catch

Loading
Loading