Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 24 additions & 5 deletions docs/accessibility/audit-baseline-2026-02-25.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ Scope: Frontend E2E flows and shared UI components

## Baseline Summary

- Total Cypress E2E specs: `41`
- Specs currently invoking `checkA11y` (actively executing): `34`
- Specs with commented-out `checkA11y` hooks (not included above): `3`
- Global axe suppression currently present: `link-name` (planned follow-up to remove in `frontend/cypress/support/e2e.js`)
- Baseline measured: `2026-02-25`
- Status reviewed: `2026-03-11`
- Total Cypress E2E specs: `42`
- Specs currently invoking `checkA11y` (actively executing): `38`
- Specs currently not invoking `checkA11y`: `4`
- Global axe suppression currently present: none
- Critical regression spec gap closed on `2026-03-11`: `frontend/cypress/e2e/notificationCenter.cy.js` now calls `injectAxe/checkA11y`
- Scoped `link-name` allowlist entries removed on `2026-03-11` for the current critical regression set

## Phase 1 Target Flows

Expand Down Expand Up @@ -37,9 +41,24 @@ Each finding must be tracked with:

| finding_id | route/component | axe_rule | impact | wcag_criterion | repro_steps | proposed_fix | status |
| --- | --- | --- | --- | --- | --- | --- | --- |
| A11Y-BASELINE-0001 | Global Cypress axe config | `link-name` | moderate | 2.4.4 | Run E2E a11y checks with default global config | Remove global disable and fix icon-only links with accessible names | existing |
| A11Y-BASELINE-0001 | Global Cypress axe config | `link-name` | moderate | 2.4.4 | Run E2E a11y checks with default global config | Remove global disable and fix icon-only links with accessible names | fixed |
| A11Y-BASELINE-0002 | `createAgreementWithValidations` review flow | `landmark-one-main` | moderate | 1.3.1 | Open review page and run a11y check | Remove duplicate `main` landmark in legacy layout | accepted exception |
| A11Y-BASELINE-0003 | `createAgreementWithValidations` review flow | `region` | minor | 1.3.1 | Open review page and run a11y check | Ensure all content is inside landmark regions | accepted exception |
| A11Y-BASELINE-0004 | `notificationCenter.cy.js` critical regression flow | process gap | moderate | N/A | Review CI regression spec list and compare with spec-level axe invocation | Add active `cy.injectAxe()` and `cy.checkA11y()` to the notification center spec so gate coverage matches intent | fixed |
| A11Y-BASELINE-0005 | Shared header/profile and agreement navigation links | `link-name` | moderate | 2.4.4 | Run critical list/detail/create Cypress specs without `link-name` allowlist entries | Add fallback accessible names to shared profile and agreement detail links | fixed |
| A11Y-BASELINE-0006 | Agreement detail and review route loading states | `landmark-one-main`, `page-has-heading-one`, `region` | moderate | 1.3.1 | Navigate into agreement detail or review routes and run axe during loading transitions | Keep loading states inside `App` so landmarks and headings remain present throughout route transitions | fixed |
| A11Y-BASELINE-0007 | Decorative portfolio and budget line SVG icons | `svg-img-alt` | minor | 1.1.1 | Run `portfolioDetail` and `budgetLineItemsList` specs without svg allowlist entries | Mark decorative chart/action SVGs `aria-hidden` or otherwise remove them from the accessibility tree | fixed |

## Wave 3 Notes

- Wave 3 is remediation-first: remove broad suppressions, close gaps between gated specs and actual axe execution, and shrink the temporary allowlist.
- Developer progress tracker: `docs/developers/frontend/accessibility/issue-5149-wave-3.md`
- Completed in current slice:
- active axe execution added to `frontend/cypress/e2e/notificationCenter.cy.js`
- non-gated global `link-name` suppression removed from `frontend/cypress/support/e2e.js`
- all scoped `link-name` allowlist entries removed after targeted component fixes and Cypress validation
- structural allowlist entries removed for `agreementDetails`, `budgetLineItemsList`, and review/upload-related route transitions
- svg allowlist entries removed for `portfolioDetail` and `budgetLineItemsList`

## Regression Gate Onboarding

Expand Down
33 changes: 26 additions & 7 deletions docs/accessibility/github-issue-accessibility-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,41 @@

## Tasks

- [ ] Produce and maintain normalized findings register in `docs/accessibility/audit-baseline-2026-02-25.md`.
- [ ] Re-enable disabled/commented Cypress `injectAxe/checkA11y` hooks for identified specs.
- [ ] Remove global `link-name` suppression and migrate to temporary scoped allowlist entries with expiry.
- [ ] Add CI regression gate for critical specs with `A11Y_REGRESSION_GATE=true`.
- [ ] Add suppression hygiene validation (`owner`, `expires`, `rationale`) for any `enabled: false` usage.
- [x] Produce and maintain normalized findings register in `docs/accessibility/audit-baseline-2026-02-25.md`.
- [x] Re-enable disabled/commented Cypress `injectAxe/checkA11y` hooks for identified specs.
- [x] Remove global `link-name` suppression and migrate fully to temporary scoped allowlist entries with expiry.
- [x] Add CI regression gate for critical specs with `A11Y_REGRESSION_GATE=true`.
- [x] Add suppression hygiene validation (`owner`, `expires`, `rationale`) for any `enabled: false` usage.
- [ ] Open child remediation issues for all non-blocking findings by severity batch (A/B/C).

## Definition Of Done

- [ ] Audit report committed with finding IDs, severity, WCAG mapping, affected routes/components.
- [ ] Disabled a11y checks re-enabled (or time-boxed exception with owner/date and rationale).
- [ ] CI regression gate active for selected critical flows.
- [x] Disabled a11y checks re-enabled (or time-boxed exception with owner/date and rationale).
- [x] CI regression gate active for selected critical flows.
- [ ] Child remediation issues created for all non-blocking findings.

## Additional Context

- Standard target: WCAG 2.1 AA
- Phase 1 scope: Frontend E2E + shared UI components
- Baseline reference: `docs/accessibility/audit-baseline-2026-02-25.md`

## Wave 3 Direction

Wave 3 is focused on remediation-first follow-through for the infrastructure already added in earlier work.

Priority order:

1. Turn on active axe execution for any critical spec listed in the regression gate that still is not calling `injectAxe/checkA11y`.
2. Remove the remaining non-gated global `link-name` suppression in `frontend/cypress/support/e2e.js`.
3. Burn down scoped allowlist entries by fixing source components and updating the findings register.
4. Keep developer-facing progress notes current in `docs/developers/frontend/accessibility/issue-5149-wave-3.md`.

Progress update:

- `notificationCenter.cy.js` now actively executes axe checks.
- Global `link-name` suppression has been removed.
- Scoped `link-name` allowlist entries have been burned down to zero for the current critical regression spec set.
- Scoped structural allowlist entries for agreement-detail/review route transitions have been burned down to zero for the current targeted regression set.
- Scoped `svg-img-alt` allowlist entries have been burned down to zero for the remaining tracked specs.
122 changes: 122 additions & 0 deletions docs/developers/frontend/accessibility/issue-5149-wave-3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# [A11y][Wave 3] Issue 5149 remediation tracker

## Objective
Use Wave 3 to convert the existing accessibility baseline and regression-gate scaffolding into real debt reduction for issue `#5149`.

## Updated Wave 3 Goals
- [x] Enable active `injectAxe/checkA11y` coverage for every currently gated critical spec.
- [x] Remove the remaining non-gated global `link-name` suppression from `frontend/cypress/support/e2e.js`.
- [x] Reduce scoped allowlist entries by fixing underlying UI issues in critical flows.
- [x] Keep `docs/accessibility/audit-baseline-2026-02-25.md` in sync with current findings and status.
- [ ] Track follow-up remediation issues for any non-blocking findings that remain deferred.

## Current Status Snapshot
- Branch: `OPS-5149/a11y-wave-three`
- Issue: `#5149`
- Working mode: remediation-first
- Existing regression gate: active in `.github/workflows/ci.yml`
- Existing allowlist validation: active in `frontend/cypress/support/a11yAllowlist.js`
- Remaining broad suppression: none

## Wave 3 Workstreams

### 1. Critical spec parity
- [x] `frontend/cypress/e2e/notificationCenter.cy.js` should actively run `cy.injectAxe()` and `cy.checkA11y()`.
- [x] Confirm every spec named in the CI regression gate is actually executing accessibility checks.

### 2. Suppression removal
- [x] Remove the fallback global `link-name` disable in `frontend/cypress/support/e2e.js`.
- [x] Keep only scoped, expiring exceptions in `frontend/cypress/support/a11yAllowlist.js` when justified.

### 3. Allowlist burn-down
- [x] `link-name` findings across agreement, portfolio, budget line, upload, and notification flows
- [x] `svg-img-alt` findings in data visualization and icon-driven components
- [x] `landmark-one-main`, `page-has-heading-one`, and `region` findings in review and upload flows

## Current Allowlist Inventory

| Rule | Entries | Notes |
| --- | --- | --- |
| `link-name` | 0 | Removed on `2026-03-11`; targeted specs now pass without allowlist coverage |
| `svg-img-alt` | 0 | Removed on `2026-03-11`; decorative chart and action icons now hide from assistive tech |
| `landmark-one-main` | 0 | Removed on `2026-03-11` after preserving layout landmarks during route loading |
| `page-has-heading-one` | 0 | Removed on `2026-03-11` after preserving page headings during route loading |
| `region` | 0 | Removed on `2026-03-11` after preserving landmark-wrapped loading states |

## Priority Files
- `frontend/cypress/support/e2e.js`
- `frontend/cypress/support/a11yAllowlist.js`
- `frontend/cypress/e2e/notificationCenter.cy.js`
- `frontend/src/components/UI/NotificationCenter/NotificationCenter.jsx`
- `frontend/src/pages/agreements/review/ReviewAgreement.jsx`
- `frontend/src/components/Agreements/Documents/UploadDocument.jsx`
- `docs/accessibility/audit-baseline-2026-02-25.md`

## Progress Log

### 2026-03-11
- Established Wave 3 as a remediation-first phase rather than more test-surface expansion.
- Identified that regression-gate plumbing and suppression metadata validation are already in place.
- Identified remaining major gaps:
- `frontend/cypress/e2e/notificationCenter.cy.js` is not yet executing axe checks.
- `frontend/cypress/support/e2e.js` still applies a non-gated global `link-name` suppression.
- Baseline summary numbers in `docs/accessibility/audit-baseline-2026-02-25.md` need refreshing.
- Implemented first Wave 3 remediation slice:
- added active `cy.injectAxe()` and `cy.checkA11y()` coverage to `frontend/cypress/e2e/notificationCenter.cy.js`
- replaced clickable notification SVGs with accessible buttons in `frontend/src/components/UI/NotificationCenter/NotificationCenter.jsx`
- removed the fallback global `link-name` suppression from `frontend/cypress/support/e2e.js`
- Validation:
- `bun run a11y:validate-suppressions` passes
- `npx cypress run --config-file ./cypress.config.js --headless --spec "cypress/e2e/notificationCenter.cy.js,cypress/e2e/agreementList.cy.js,cypress/e2e/uploadDocument.cy.js"` passes
- no flaky retries detected in the targeted run
- Completed `link-name` burn-down for currently tracked critical specs:
- added fallback accessible names to the shared user-profile link in `frontend/src/components/UI/Header/User.jsx`
- added explicit accessible names to agreement links in `frontend/src/components/BudgetLineItems/AllBudgetLinesTable/AllBLIRow.jsx`
- added explicit accessible names to agreement links in `frontend/src/components/CANs/CANBudgetLineTable/CANBudgetLineTableRow.jsx`
- removed all remaining `link-name` allowlist entries from `frontend/cypress/support/a11yAllowlist.js`
- Expanded validation:
- `npx cypress run --config-file ./cypress.config.js --headless --spec "cypress/e2e/agreementList.cy.js,cypress/e2e/agreementsPagination.cy.js,cypress/e2e/agreementDetails.cy.js,cypress/e2e/portfolioList.cy.js,cypress/e2e/portfolioDetail.cy.js,cypress/e2e/budgetLineItemsList.cy.js,cypress/e2e/createAgreement.cy.js,cypress/e2e/createAgreementWithValidations.cy.js,cypress/e2e/uploadDocument.cy.js,cypress/e2e/notificationCenter.cy.js"` passes
- no `link-name` failures remain in the targeted regression set
- Completed structural burn-down for the routed agreement/review flows:
- preserved `App` layout landmarks and page headings during agreement detail loading in `frontend/src/pages/agreements/details/Agreement.jsx`
- preserved `App` layout landmarks during review-page loading in `frontend/src/pages/agreements/review/ReviewAgreement.jsx`
- removed the nested page-level `<main>` from `frontend/src/components/Agreements/Documents/UploadDocument.jsx`
- removed the remaining `landmark-one-main`, `page-has-heading-one`, and `region` allowlist entries from `frontend/cypress/support/a11yAllowlist.js`
- Structural validation:
- `npx cypress run --config-file ./cypress.config.js --headless --spec "cypress/e2e/agreementDetails.cy.js,cypress/e2e/budgetLineItemsList.cy.js,cypress/e2e/createAgreementWithValidations.cy.js,cypress/e2e/uploadDocument.cy.js"` passes
- no structural allowlist-backed failures remain in that targeted regression set
- Completed `svg-img-alt` burn-down for the remaining tracked specs:
- hid decorative portfolio legend and CAN funding icons from assistive tech in `frontend/src/components/Portfolios/PortfolioSummaryCards/PortfolioLegend.jsx` and `frontend/src/components/Portfolios/PortfolioFundingByCAN/PortfolioFundingByCAN.jsx`
- hid decorative external-link icon in `frontend/src/components/Portfolios/PortfolioHero/HeroDescription.jsx`
- hid decorative budget line summary and change-action icons in `frontend/src/components/BudgetLineItems/BLIStatusSummaryCard/BLIStatusSummaryCard.jsx` and `frontend/src/components/BudgetLineItems/ChangeIcons/ChangeIcons.jsx`
- removed the final `svg-img-alt` allowlist entries from `frontend/cypress/support/a11yAllowlist.js`
- SVG validation:
- `npx cypress run --config-file ./cypress.config.js --headless --spec "cypress/e2e/portfolioDetail.cy.js,cypress/e2e/budgetLineItemsList.cy.js"` passes
- no `svg-img-alt` failures remain in the targeted regression set

## Validation Checklist
- [x] `bun run a11y:validate-suppressions`
- [x] Relevant Cypress regression specs pass locally
- [x] Findings register updated for each removed or narrowed exception
- [ ] Child follow-up issues linked for deferred findings

## Parent Issue Update Draft
Use this comment on the parent issue when Wave 3 changes start landing:

```md
Wave 3 update (`#5149`):

- Shifted this phase to remediation-first work on top of the existing a11y regression gate.
- Added developer tracker: `docs/developers/frontend/accessibility/issue-5149-wave-3.md`
- Current focus:
- enable active axe execution for all gated critical specs
- remove the remaining global `link-name` suppression
- burn down scoped allowlist entries by rule and route

Next implementation targets:
- `frontend/cypress/e2e/notificationCenter.cy.js`
- `frontend/cypress/support/e2e.js`
- `frontend/src/components/UI/NotificationCenter/NotificationCenter.jsx`
- `frontend/src/pages/agreements/review/ReviewAgreement.jsx`
- `frontend/src/components/Agreements/Documents/UploadDocument.jsx`
```
7 changes: 6 additions & 1 deletion frontend/cypress/e2e/notificationCenter.cy.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
/// <reference types="cypress" />
import { testLogin } from "./utils";
import { terminalLog, testLogin } from "./utils";

beforeEach(() => {
testLogin("system-owner");
cy.visit("/");
});

afterEach(() => {
cy.injectAxe();
cy.checkA11y(null, null, terminalLog);
});

it("Notification Center appears when you click the bell icon and has 1 item in list", () => {
cy.get("#notification-center-bell use").should(($iconUse) => {
const href = $iconUse.attr("href") || $iconUse.attr("xlink:href");
Expand Down
Loading
Loading