From e17cc1458ee4b91007c0215afffe3d783f9da2c7 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 3 Sep 2026 13:13:01 +0200 Subject: [PATCH 1/6] Add Accessibility infra setup skill --- README.md | 1 + skills/accessibility-infra-setup/SKILL.md | 173 ++++++++++++++++++ .../assets/accessibility-README.md | 55 ++++++ .../assets/axe-helpers.ts | 60 ++++++ .../assets/example.accessibility.spec.ts | 27 +++ .../assets/playwright.config.ts | 51 ++++++ .../evals/evals.json | 77 ++++++++ .../evals/trigger-eval.json | 50 +++++ 8 files changed, 494 insertions(+) create mode 100644 skills/accessibility-infra-setup/SKILL.md create mode 100644 skills/accessibility-infra-setup/assets/accessibility-README.md create mode 100644 skills/accessibility-infra-setup/assets/axe-helpers.ts create mode 100644 skills/accessibility-infra-setup/assets/example.accessibility.spec.ts create mode 100644 skills/accessibility-infra-setup/assets/playwright.config.ts create mode 100644 skills/accessibility-infra-setup/evals/evals.json create mode 100644 skills/accessibility-infra-setup/evals/trigger-eval.json diff --git a/README.md b/README.md index 3eb84d4..4040f52 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ its purpose, trigger phrases, and full instructions. | Skill | Description | |------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| +| **[accessibility-infra-setup](./skills/accessibility-infra-setup/)** | Set up automated accessibility (a11y) check infrastructure in an existing Angular app with Playwright + axe-core (WCAG 2.2 AA) — detects existing test setup, scaffolds config, a shared axe fixture, one dummy example scan, npm scripts, and docs, then validates the sample passes. | | **[bdd-maintain](./skills/bdd-maintain/)** | REMOVE and DEAD CODE AUDIT modes — delete feature files, step definitions, and PageObjects linked to | **[create-repository](./skills/create-repository/)** | Creates and configures a GitHub repository under AbsaOSS (open source) or absa-group (internal). Runs a short interview, then shows an annotated `gh` command plan and executes it on confirmation — visibility, naming, admins, CODEOWNERS, labels, merge settings, and project links. | | **[data-cy-instrument](./skills/data-cy-instrument/)** | Resolve missing `data-cy` attributes in Angular component templates and sync PageObjects to use `getByTestId()` — run after a crawl when `coverage_gaps` are non-empty. | diff --git a/skills/accessibility-infra-setup/SKILL.md b/skills/accessibility-infra-setup/SKILL.md new file mode 100644 index 0000000..9d75fdb --- /dev/null +++ b/skills/accessibility-infra-setup/SKILL.md @@ -0,0 +1,173 @@ +--- +name: accessibility-infra-setup +description: > + Sets up automated accessibility (a11y) check infrastructure in an existing Angular application + using Playwright + axe-core (@axe-core/playwright), asserting WCAG 2.2 AA compliance. Detects the + existing test setup, installs and wires Playwright with a dedicated `accessibility` project, + scaffolds a shared axe fixture, adds one dummy example scan, wires npm scripts, documents how to + run the checks, and validates that the sample passes. Activates on requests like: "set up + accessibility checks", "add a11y testing infrastructure", "add axe-core to this Angular app", + "set up WCAG testing", "add accessibility scans with Playwright", "bootstrap a11y infra". + Scope is infrastructure only plus ONE dummy example test — authoring real accessibility tests is + a separate concern and out of scope. +license: Apache-2.0 +compatibility: > + Requires an existing Angular application with a runnable dev server (`npm run start` on port 4200) + and Node.js 22+. Installs Playwright browsers, which needs network access on first run. +--- + +# accessibility-infra-setup + +Bootstraps Playwright + axe-core accessibility infrastructure in an existing Angular app. Follows the +[AbsaOSS/cps-shared-ui](https://github.com/AbsaOSS/cps-shared-ui) pattern, generalized for a plain +application (not a component library). + +**Scope:** infrastructure + exactly one dummy example scan. Do **not** author real accessibility +tests here — that is a separate follow-up task. + +## Expected outcome + +After this skill runs, the repository contains: + +``` +playwright/ +├── fixtures/ +│ └── axe-helpers.ts # Shared axe fixture (WCAG 2.2 AA tags) + assertion helpers +└── a11y/ + └── example.accessibility.spec.ts # ONE dummy scan of the "/" route — passes +playwright.config.ts # `accessibility` project (Desktop Chrome, testMatch /accessibility/) +docs/accessibility.md # How to run, where reports land (or playwright/README.md) +``` + +- `package.json` gains `@playwright/test` + `@axe-core/playwright` (devDependencies) and + `test:a11y*` scripts. +- `npm run test:a11y` starts the dev server, runs the dummy scan on Desktop Chrome, and **passes + green**. That green run is the definition of done. + +## Workflow + +Copy this checklist and track progress: + +``` +- [ ] Step 1: Detect existing test infrastructure +- [ ] Step 2: Install dependencies +- [ ] Step 3: Scaffold config + fixture + example spec +- [ ] Step 4: Wire npm scripts +- [ ] Step 5: Validate (run the dummy scan → green) +- [ ] Step 6: Document +``` + +### Step 1 · Detect existing test infrastructure + +Inspect the repo before writing anything — the goal is to **extend, not clobber**. + +1. Read `package.json`: note the dev-server script (usually `start` → `ng serve`, port 4200), the + package manager (from `package-lock.json` / `yarn.lock` / `pnpm-lock.yaml`), and any existing + `@playwright/test`, `@axe-core/playwright`, Cypress, or Karma entries. +2. Check for an existing `playwright.config.*` and for Cypress (`cypress.config.*`, a `cypress/` + folder, or a `cypress` devDependency). + +Pick exactly one path based on what Playwright infra exists — Cypress never changes the decision: + +- **Playwright already configured** (a `playwright.config.*` exists) → **adjust it in place, do not + recreate it.** Merge in an `accessibility` project + `{ name: 'accessibility', testMatch: /accessibility/, use: { ...devices['Desktop Chrome'] } }`, + add `testIgnore: /accessibility/` to existing functional projects, and ensure `webServer` starts + the Angular dev server. Keep the user's existing `testDir` and place a11y specs accordingly. Reuse + any existing axe fixture instead of adding a second one. +- **No Playwright yet** → fresh setup. Copy `assets/playwright.config.ts` to the repo root and + scaffold the full structure in Step 3. + +**Cypress is off-limits either way.** If Cypress is present, treat it as read-only: never edit, +migrate, or delete Cypress config, specs, or dependencies, and never fold a11y scans into Cypress. +The two runners coexist — Playwright owns accessibility, Cypress keeps whatever it already covers. +Cypress existing does **not** make this a "fresh" or "adjust" decision; only the presence/absence of +a `playwright.config.*` does. + +Confirm the dev-server command and port with the user only if they differ from `npm run start` / +`4200`; otherwise proceed. + +### Step 2 · Install dependencies + +Use the repo's package manager. For npm: + +```bash +npm install -D @playwright/test @axe-core/playwright +npx playwright install chromium +``` + +`npx playwright install chromium` downloads the browser and needs network access. If Playwright was +already installed, skip the packages but still ensure the Chromium browser is present. + +### Step 3 · Scaffold config, fixture, and example spec + +Create these files (templates live in this skill's `assets/`): + +1. `playwright.config.ts` (root) — from `assets/playwright.config.ts` (fresh setup only; otherwise + merge as in Step 1). Adjust `baseURL`, `webServer.command`, and port if the app differs. +2. `playwright/fixtures/axe-helpers.ts` — copy verbatim from `assets/axe-helpers.ts`. This is the + single source of the WCAG 2.2 AA tag set; every scan must build from `makeAxeBuilder`. +3. `playwright/a11y/example.accessibility.spec.ts` — from `assets/example.accessibility.spec.ts`. + Verify the import path resolves to the fixture (`../fixtures/axe-helpers`) given where you place + the spec, and point `page.goto('/')` at a route that renders without auth. If the app's landing + route requires login, use a known public route instead and note it. + +The `accessibility` substring in the spec filename is what routes it to the accessibility project — +keep it. + +### Step 4 · Wire npm scripts + +Add to `package.json` `scripts` (do not clobber existing entries): + +```jsonc +"test:a11y": "playwright test --project=accessibility", +"test:a11y:headed": "playwright test --project=accessibility --headed", +"test:a11y:report": "playwright show-report" +``` + +### Step 5 · Validate — run the dummy scan + +Run the feedback loop until green: + +```bash +npm run test:a11y +``` + +1. If it **passes**, the infrastructure is proven. Done. +2. If it **fails on a real WCAG violation** on the chosen route, switch the example to a simpler + public route (the dummy test must pass to prove the plumbing — fixing app violations is out of + scope). Note the finding for the user. +3. If it fails on **setup** (missing browser, wrong port, dev server timeout, import error), fix the + config/paths and re-run. Common causes: dev server not on 4200, `webServer.command` wrong, + Chromium not installed, fixture import path incorrect. + +Do not finish until `npm run test:a11y` exits green. + +### Step 6 · Document + +Add `assets/accessibility-README.md` to the repo as `docs/accessibility.md` (or +`playwright/README.md`). Adjust file paths/scripts to match what you created. Add a short +"Accessibility" note with the run command to the main `README.md` if one exists. + +## Gotchas + +- **Separate project, Chrome only.** axe evaluates rendered DOM/ARIA, not browser rendering quirks — + scan once on Desktop Chrome. Do not fan a11y scans across webkit/firefox. +- **Wait for animations.** Scanning mid-transition produces false-positive color-contrast + violations. `waitForAnimationsToFinish` (in the fixture) prevents this — call it before every scan. +- **Never touch Cypress.** If the repo uses Cypress, leave its config, specs, and dependencies + untouched — add Playwright alongside it rather than migrating or editing anything Cypress owns. +- **Extend, don't recreate Playwright.** When a `playwright.config.*` already exists, merge the + `accessibility` project into it and reuse any existing axe fixture — do not generate a second + config or a duplicate fixture. +- **Filename routing.** A spec only lands in the accessibility project if `accessibility` is in its + filename. This is `testMatch: /accessibility/`, not a folder. +- **git-ignore artifacts.** Ensure `test-results/` and `playwright-report/` are git-ignored. +- **WCAG tag set lives in one place.** Never inline `withTags(...)` in a spec — always go through + `makeAxeBuilder`, so the standard stays consistent as scans are added later. + +## Out of scope + +- Writing real accessibility tests / per-page coverage (separate skill/task). +- Fixing accessibility violations found in the app. +- pa11y-ci, Lighthouse, or CI-pipeline wiring — Playwright + axe-core only, run locally. diff --git a/skills/accessibility-infra-setup/assets/accessibility-README.md b/skills/accessibility-infra-setup/assets/accessibility-README.md new file mode 100644 index 0000000..72025ae --- /dev/null +++ b/skills/accessibility-infra-setup/assets/accessibility-README.md @@ -0,0 +1,55 @@ +# Accessibility Tests + +Automated accessibility checks for this app, powered by +[Playwright](https://playwright.dev/) + [axe-core](https://github.com/dequelabs/axe-core) +(via [`@axe-core/playwright`](https://github.com/dequelabs/axe-core-npm/tree/develop/packages/playwright)). +Scans assert compliance with **WCAG 2.2 AA** (plus axe best-practice rules). + +## Layout + +``` +playwright/ +├── fixtures/ +│ └── axe-helpers.ts # Shared axe fixture (WCAG 2.2 AA tag set) + assertion helpers +└── a11y/ + └── example.accessibility.spec.ts # Dummy example scan of the home route +playwright.config.ts # `accessibility` project routes any *accessibility* spec here +``` + +Any spec file with `accessibility` in its name runs under the dedicated +`accessibility` Playwright project (Desktop Chrome only). + +## Running + +```bash +npm run test:a11y # run all accessibility scans (auto-starts the dev server) +npm run test:a11y:headed # same, with the browser visible +npm run test:a11y:report # open the last HTML report +``` + +Playwright auto-starts `npm run start` (the Angular dev server) and waits for +`http://localhost:4200`. If a dev server is already running locally, it is reused. + +## Reports and artifacts + +- HTML report → `playwright-report/` (open with `npm run test:a11y:report`) +- Full axe results JSON attached to each test → visible in the HTML report +- Screenshots / videos / traces on failure → `test-results/` + +Both directories are git-ignored. + +## Adding a scan + +1. Create a spec whose filename contains `accessibility`, e.g. + `playwright/a11y/checkout.accessibility.spec.ts`. +2. Import the shared fixture: + + ```ts + import { test, expectNoViolations, waitForAnimationsToFinish } from '../fixtures/axe-helpers'; + ``` + +3. Navigate, wait for animations, scan with `makeAxeBuilder()`, assert with + `expectNoViolations`. Use the example spec as a template. + +Writing real accessibility tests is intentionally out of scope of the setup — +this directory only ships the infrastructure and one dummy example. diff --git a/skills/accessibility-infra-setup/assets/axe-helpers.ts b/skills/accessibility-infra-setup/assets/axe-helpers.ts new file mode 100644 index 0000000..cd44229 --- /dev/null +++ b/skills/accessibility-infra-setup/assets/axe-helpers.ts @@ -0,0 +1,60 @@ +import { test as base, expect, type Page } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; + +type Violations = Awaited>['violations']; + +type AxeFixture = { + makeAxeBuilder: () => AxeBuilder; +}; + +/** + * Shared axe-core fixture. Every accessibility scan builds its AxeBuilder from + * here so the WCAG 2.2 AA tag set stays identical across the whole suite. + */ +export const test = base.extend({ + makeAxeBuilder: async ({ page }, use) => { + const makeAxeBuilder = () => + new AxeBuilder({ page }).withTags([ + 'wcag2a', + 'wcag2aa', + 'wcag21a', + 'wcag21aa', + 'wcag22a', + 'wcag22aa', + 'best-practice' + ]); + await use(makeAxeBuilder); + } +}); + +export function formatViolations(violations: Violations): string { + if (violations.length === 0) return ''; + return violations + .map((v) => { + const nodes = v.nodes + .map((n) => ` - ${n.html}\n ${n.failureSummary}`) + .join('\n'); + return `\n[${v.impact}] ${v.id}: ${v.description}\n Help: ${v.helpUrl}\n${nodes}`; + }) + .join('\n'); +} + +export function expectNoViolations(violations: Violations) { + expect(violations, formatViolations(violations)).toHaveLength(0); +} + +/** + * Wait for all animations/transitions to complete before scanning. Without this, + * axe may capture intermediate states (e.g. mid-transition background color) and + * report false-positive color-contrast violations. + */ +export async function waitForAnimationsToFinish(page: Page) { + await page.evaluate(() => + Promise.all( + document + .getAnimations() + .filter((a) => a.effect?.getTiming().iterations !== Infinity) + .map((a) => a.finished.catch(() => {})) + ) + ); +} diff --git a/skills/accessibility-infra-setup/assets/example.accessibility.spec.ts b/skills/accessibility-infra-setup/assets/example.accessibility.spec.ts new file mode 100644 index 0000000..0644569 --- /dev/null +++ b/skills/accessibility-infra-setup/assets/example.accessibility.spec.ts @@ -0,0 +1,27 @@ +import { + test, + expectNoViolations, + waitForAnimationsToFinish +} from '../fixtures/axe-helpers'; + +// Dummy example scan proving the infrastructure works end to end. +// Replace the route and add real scans in dedicated *.accessibility.spec.ts files. +// The "accessibility" in the filename routes this spec to the accessibility project. +test.describe('Accessibility - example scan', () => { + test('home route has no WCAG 2.2 AA violations', async ({ + page, + makeAxeBuilder + }, testInfo) => { + await page.goto('/'); + await waitForAnimationsToFinish(page); + + const results = await makeAxeBuilder().analyze(); + + await testInfo.attach('home-accessibility-scan', { + body: JSON.stringify(results, null, 2), + contentType: 'application/json' + }); + + expectNoViolations(results.violations); + }); +}); diff --git a/skills/accessibility-infra-setup/assets/playwright.config.ts b/skills/accessibility-infra-setup/assets/playwright.config.ts new file mode 100644 index 0000000..c5c672e --- /dev/null +++ b/skills/accessibility-infra-setup/assets/playwright.config.ts @@ -0,0 +1,51 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Playwright configuration with a dedicated `accessibility` project. + * + * Any spec whose filename contains `accessibility` runs axe-core scans on + * Desktop Chrome only — axe evaluates rendered DOM/ARIA state, so cross-browser + * variation adds no value. Functional specs (if any) run under `chromium`. + * + * See https://playwright.dev/docs/test-configuration + */ +export default defineConfig({ + testDir: './playwright', + outputDir: 'test-results', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: [['html'], ['json', { outputFile: 'playwright-report/summary.json' }]], + timeout: 30_000, + expect: { timeout: 5_000 }, + use: { + baseURL: 'http://localhost:4200', + actionTimeout: 5_000, + navigationTimeout: 5_000, + trace: 'on-first-retry', + screenshot: 'only-on-failure', + video: 'retain-on-failure' + }, + projects: [ + { + name: 'chromium', + testIgnore: /accessibility/, + use: { ...devices['Desktop Chrome'] } + }, + { + name: 'accessibility', + testMatch: /accessibility/, + use: { ...devices['Desktop Chrome'] } + } + ], + /* Start the Angular dev server before running tests. */ + webServer: { + command: 'npm run start', + url: 'http://localhost:4200', + /* Reuse a running dev server locally; CI always starts fresh. */ + reuseExistingServer: !process.env.CI, + /* Angular builds can be slow — allow up to 2 minutes. */ + timeout: 120_000 + } +}); diff --git a/skills/accessibility-infra-setup/evals/evals.json b/skills/accessibility-infra-setup/evals/evals.json new file mode 100644 index 0000000..55df615 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/evals.json @@ -0,0 +1,77 @@ +{ + "skill_name": "accessibility-infra-setup", + "evals": [ + { + "id": "happy-path-fresh-angular-app", + "category": "happy-path", + "prompt": "Set up accessibility check infrastructure in this Angular app.", + "expected_output": "Skill detects there is no existing Playwright setup, installs @playwright/test and @axe-core/playwright, scaffolds playwright.config.ts with a dedicated accessibility project, a shared axe-helpers fixture using the WCAG 2.2 AA tag set, one dummy example.accessibility.spec.ts scanning '/', adds test:a11y npm scripts, runs the dummy scan to green, and documents how to run it.", + "files": [], + "expectations": [ + "Detects existing test infrastructure before writing files (reads package.json)", + "Installs @playwright/test and @axe-core/playwright as devDependencies", + "Installs the Chromium browser via playwright install", + "Creates playwright.config.ts with an 'accessibility' project using testMatch /accessibility/ on Desktop Chrome", + "Creates a shared axe fixture (axe-helpers) whose makeAxeBuilder uses wcag2a/wcag2aa/wcag21a/wcag21aa/wcag22a/wcag22aa/best-practice tags", + "Creates exactly one dummy accessibility spec (filename contains 'accessibility')", + "Adds test:a11y npm scripts to package.json without clobbering existing scripts", + "Runs npm run test:a11y and confirms it passes green", + "Adds documentation describing how to run the checks and where reports are generated", + "Does NOT author real per-page accessibility tests beyond the single dummy example" + ] + }, + { + "id": "happy-path-existing-playwright", + "category": "happy-path", + "prompt": "We already use Playwright for e2e. Add axe-core accessibility scanning on top.", + "expected_output": "Skill detects the existing playwright.config, does NOT overwrite it, merges in an accessibility project and adds testIgnore /accessibility/ to functional projects, adds the axe fixture and one dummy scan, and validates.", + "files": [], + "expectations": [ + "Detects the existing playwright.config and does not overwrite it", + "Merges an accessibility project (testMatch /accessibility/, Desktop Chrome) into the existing config", + "Adds testIgnore /accessibility/ to existing functional projects so a11y scans run once", + "Installs @axe-core/playwright but does not reinstall Playwright if already present", + "Creates the shared axe fixture and one dummy accessibility spec", + "Validates the dummy scan passes" + ] + }, + { + "id": "regression-cypress-untouched", + "category": "regression", + "prompt": "We use Cypress for e2e. Set up accessibility checks for this Angular app.", + "expected_output": "Skill introduces Playwright + axe-core accessibility infrastructure alongside Cypress and leaves all Cypress config, specs, and dependencies completely untouched.", + "files": [], + "expectations": [ + "Detects Cypress and does NOT edit, migrate, or delete any Cypress config, specs, or dependencies", + "Does NOT fold accessibility scans into Cypress", + "Sets up a fresh Playwright config (no existing playwright.config present) with the accessibility project", + "Cypress and Playwright coexist after the change" + ] + }, + { + "id": "regression-infra-only-scope", + "category": "regression", + "prompt": "Set up accessibility infrastructure and write full a11y coverage for every page.", + "expected_output": "Skill sets up the infrastructure plus exactly one dummy example scan, and explicitly declines to author per-page coverage, noting that is a separate follow-up task.", + "files": [], + "expectations": [ + "Only one dummy example accessibility spec is created", + "Skill explicitly states per-page/real accessibility test authoring is out of scope", + "Infrastructure (config, fixture, scripts, docs) is still fully set up", + "Skill does not attempt to fix accessibility violations in application code" + ] + }, + { + "id": "regression-do-not-clobber", + "category": "regression", + "prompt": "Add accessibility checks. Our package.json already has a bunch of test scripts and a playwright config.", + "expected_output": "Skill preserves existing scripts and config, merging additively rather than overwriting.", + "files": [], + "expectations": [ + "Existing npm scripts are preserved (additive edit only)", + "Existing playwright.config is merged, not replaced", + "New test:a11y scripts are added alongside existing ones" + ] + } + ] +} diff --git a/skills/accessibility-infra-setup/evals/trigger-eval.json b/skills/accessibility-infra-setup/evals/trigger-eval.json new file mode 100644 index 0000000..690dae2 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/trigger-eval.json @@ -0,0 +1,50 @@ +[ + { + "query": "Set up accessibility check infrastructure in this Angular app.", + "should_trigger": true + }, + { + "query": "Add a11y testing infrastructure with Playwright and axe-core.", + "should_trigger": true + }, + { + "query": "I want to add WCAG 2.2 AA accessibility scans to our frontend.", + "should_trigger": true + }, + { + "query": "Bootstrap axe-core accessibility testing for this Angular application.", + "should_trigger": true + }, + { + "query": "We already use Playwright — add accessibility scanning on top.", + "should_trigger": true + }, + { + "query": "Set up automated accessibility checks and a sample test.", + "should_trigger": true + }, + { + "query": "Add an accessibility infrastructure setup so we can catch WCAG issues.", + "should_trigger": true + }, + { + "query": "Write a full accessibility test for the checkout page.", + "should_trigger": false + }, + { + "query": "Fix the color contrast violation on the login button.", + "should_trigger": false + }, + { + "query": "Add unit tests for the discount service.", + "should_trigger": false + }, + { + "query": "Set up a CI pipeline for our Angular app.", + "should_trigger": false + }, + { + "query": "Migrate our Cypress e2e tests to Playwright.", + "should_trigger": false + } +] From 36751f9fa0d7207fcce8541cff44ee609b8cb763 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 3 Sep 2026 13:58:46 +0200 Subject: [PATCH 2/6] Adjust docs --- skills/accessibility-infra-setup/SKILL.md | 9 +++++---- .../assets/accessibility-README.md | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/skills/accessibility-infra-setup/SKILL.md b/skills/accessibility-infra-setup/SKILL.md index 9d75fdb..a6c35da 100644 --- a/skills/accessibility-infra-setup/SKILL.md +++ b/skills/accessibility-infra-setup/SKILL.md @@ -2,8 +2,8 @@ name: accessibility-infra-setup description: > Sets up automated accessibility (a11y) check infrastructure in an existing Angular application - using Playwright + axe-core (@axe-core/playwright), asserting WCAG 2.2 AA compliance. Detects the - existing test setup, installs and wires Playwright with a dedicated `accessibility` project, + using Playwright + axe-core (@axe-core/playwright) to catch automatically detectable WCAG 2.2 AA violations. + Detects the existing test setup, installs and wires Playwright with a dedicated `accessibility` project, scaffolds a shared axe fixture, adds one dummy example scan, wires npm scripts, documents how to run the checks, and validates that the sample passes. Activates on requests like: "set up accessibility checks", "add a11y testing infrastructure", "add axe-core to this Angular app", @@ -96,8 +96,9 @@ npm install -D @playwright/test @axe-core/playwright npx playwright install chromium ``` -`npx playwright install chromium` downloads the browser and needs network access. If Playwright was -already installed, skip the packages but still ensure the Chromium browser is present. + `npx playwright install chromium` downloads the browser and needs network access. If Playwright is + already installed, install `@axe-core/playwright` when it is missing, skip reinstalling + `@playwright/test`, and still ensure the Chromium browser is present. ### Step 3 · Scaffold config, fixture, and example spec diff --git a/skills/accessibility-infra-setup/assets/accessibility-README.md b/skills/accessibility-infra-setup/assets/accessibility-README.md index 72025ae..4b49e7a 100644 --- a/skills/accessibility-infra-setup/assets/accessibility-README.md +++ b/skills/accessibility-infra-setup/assets/accessibility-README.md @@ -3,7 +3,7 @@ Automated accessibility checks for this app, powered by [Playwright](https://playwright.dev/) + [axe-core](https://github.com/dequelabs/axe-core) (via [`@axe-core/playwright`](https://github.com/dequelabs/axe-core-npm/tree/develop/packages/playwright)). -Scans assert compliance with **WCAG 2.2 AA** (plus axe best-practice rules). +Scans assert compliance with **WCAG 2.2 AA** (plus axe best-practice rules); manual testing is still required for full compliance. ## Layout From 9bab397c9fde89356c18ee21a5d0784cb90ad254 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 3 Sep 2026 15:46:59 +0200 Subject: [PATCH 3/6] Add eval fixtures --- .../evals/evals.json | 33 ++++++++++++---- .../files/cypress-angular/cypress.config.ts | 8 ++++ .../cypress-angular/cypress/e2e/home.cy.ts | 6 +++ .../evals/files/cypress-angular/package.json | 29 ++++++++++++++ .../existing-playwright/e2e/example.spec.ts | 6 +++ .../files/existing-playwright/package.json | 29 ++++++++++++++ .../existing-playwright/playwright.config.ts | 22 +++++++++++ .../package.json | 33 ++++++++++++++++ .../playwright.config.ts | 26 +++++++++++++ .../evals/files/fresh-angular/angular.json | 30 +++++++++++++++ .../files/fresh-angular/package-lock.json | 18 +++++++++ .../evals/files/fresh-angular/package.json | 38 +++++++++++++++++++ .../fresh-angular/src/app/app.component.ts | 10 +++++ .../evals/files/fresh-angular/src/index.html | 12 ++++++ 14 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 skills/accessibility-infra-setup/evals/files/cypress-angular/cypress.config.ts create mode 100644 skills/accessibility-infra-setup/evals/files/cypress-angular/cypress/e2e/home.cy.ts create mode 100644 skills/accessibility-infra-setup/evals/files/cypress-angular/package.json create mode 100644 skills/accessibility-infra-setup/evals/files/existing-playwright/e2e/example.spec.ts create mode 100644 skills/accessibility-infra-setup/evals/files/existing-playwright/package.json create mode 100644 skills/accessibility-infra-setup/evals/files/existing-playwright/playwright.config.ts create mode 100644 skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json create mode 100644 skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/playwright.config.ts create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/package-lock.json create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/package.json create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/src/index.html diff --git a/skills/accessibility-infra-setup/evals/evals.json b/skills/accessibility-infra-setup/evals/evals.json index 55df615..fdfbe2a 100644 --- a/skills/accessibility-infra-setup/evals/evals.json +++ b/skills/accessibility-infra-setup/evals/evals.json @@ -4,9 +4,15 @@ { "id": "happy-path-fresh-angular-app", "category": "happy-path", - "prompt": "Set up accessibility check infrastructure in this Angular app.", + "prompt": "Set up accessibility check infrastructure in this Angular app. The project is in evals/files/fresh-angular.", "expected_output": "Skill detects there is no existing Playwright setup, installs @playwright/test and @axe-core/playwright, scaffolds playwright.config.ts with a dedicated accessibility project, a shared axe-helpers fixture using the WCAG 2.2 AA tag set, one dummy example.accessibility.spec.ts scanning '/', adds test:a11y npm scripts, runs the dummy scan to green, and documents how to run it.", - "files": [], + "files": [ + "evals/files/fresh-angular/package.json", + "evals/files/fresh-angular/angular.json", + "evals/files/fresh-angular/package-lock.json", + "evals/files/fresh-angular/src/index.html", + "evals/files/fresh-angular/src/app/app.component.ts" + ], "expectations": [ "Detects existing test infrastructure before writing files (reads package.json)", "Installs @playwright/test and @axe-core/playwright as devDependencies", @@ -23,9 +29,13 @@ { "id": "happy-path-existing-playwright", "category": "happy-path", - "prompt": "We already use Playwright for e2e. Add axe-core accessibility scanning on top.", + "prompt": "We already use Playwright for e2e. Add axe-core accessibility scanning on top. The project is in evals/files/existing-playwright.", "expected_output": "Skill detects the existing playwright.config, does NOT overwrite it, merges in an accessibility project and adds testIgnore /accessibility/ to functional projects, adds the axe fixture and one dummy scan, and validates.", - "files": [], + "files": [ + "evals/files/existing-playwright/package.json", + "evals/files/existing-playwright/playwright.config.ts", + "evals/files/existing-playwright/e2e/example.spec.ts" + ], "expectations": [ "Detects the existing playwright.config and does not overwrite it", "Merges an accessibility project (testMatch /accessibility/, Desktop Chrome) into the existing config", @@ -38,9 +48,13 @@ { "id": "regression-cypress-untouched", "category": "regression", - "prompt": "We use Cypress for e2e. Set up accessibility checks for this Angular app.", + "prompt": "We use Cypress for e2e. Set up accessibility checks for this Angular app. The project is in evals/files/cypress-angular.", "expected_output": "Skill introduces Playwright + axe-core accessibility infrastructure alongside Cypress and leaves all Cypress config, specs, and dependencies completely untouched.", - "files": [], + "files": [ + "evals/files/cypress-angular/package.json", + "evals/files/cypress-angular/cypress.config.ts", + "evals/files/cypress-angular/cypress/e2e/home.cy.ts" + ], "expectations": [ "Detects Cypress and does NOT edit, migrate, or delete any Cypress config, specs, or dependencies", "Does NOT fold accessibility scans into Cypress", @@ -64,9 +78,12 @@ { "id": "regression-do-not-clobber", "category": "regression", - "prompt": "Add accessibility checks. Our package.json already has a bunch of test scripts and a playwright config.", + "prompt": "Add accessibility checks. Our package.json already has a bunch of test scripts and a playwright config. The project is in evals/files/existing-scripts-and-playwright.", "expected_output": "Skill preserves existing scripts and config, merging additively rather than overwriting.", - "files": [], + "files": [ + "evals/files/existing-scripts-and-playwright/package.json", + "evals/files/existing-scripts-and-playwright/playwright.config.ts" + ], "expectations": [ "Existing npm scripts are preserved (additive edit only)", "Existing playwright.config is merged, not replaced", diff --git a/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress.config.ts b/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress.config.ts new file mode 100644 index 0000000..6aab236 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'cypress'; + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:4200', + specPattern: 'cypress/e2e/**/*.cy.ts', + }, +}); diff --git a/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress/e2e/home.cy.ts b/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress/e2e/home.cy.ts new file mode 100644 index 0000000..c6df447 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/cypress-angular/cypress/e2e/home.cy.ts @@ -0,0 +1,6 @@ +describe('home page', () => { + it('shows the expected heading', () => { + cy.visit('/'); + cy.get('h1').should('be.visible'); + }); +}); diff --git a/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json b/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json new file mode 100644 index 0000000..5c95c9c --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json @@ -0,0 +1,29 @@ +{ + "name": "sample-angular-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "cypress:open": "cypress open", + "e2e": "cypress run" + }, + "private": true, + "dependencies": { + "@angular/common": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/router": "^22.0.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^22.0.0", + "@angular/cli": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "cypress": "^13.14.0", + "typescript": "~5.9.2" + } +} diff --git a/skills/accessibility-infra-setup/evals/files/existing-playwright/e2e/example.spec.ts b/skills/accessibility-infra-setup/evals/files/existing-playwright/e2e/example.spec.ts new file mode 100644 index 0000000..672c915 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/existing-playwright/e2e/example.spec.ts @@ -0,0 +1,6 @@ +import { test, expect } from '@playwright/test'; + +test('home page has expected heading', async ({ page }) => { + await page.goto('/'); + await expect(page.getByRole('heading', { level: 1 })).toBeVisible(); +}); diff --git a/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json b/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json new file mode 100644 index 0000000..d7ce11f --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json @@ -0,0 +1,29 @@ +{ + "name": "sample-angular-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "e2e": "playwright test" + }, + "private": true, + "dependencies": { + "@angular/common": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/router": "^22.0.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^22.0.0", + "@angular/cli": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "@playwright/test": "^1.47.0", + "@types/node": "^22.10.0", + "typescript": "~5.9.2" + } +} diff --git a/skills/accessibility-infra-setup/evals/files/existing-playwright/playwright.config.ts b/skills/accessibility-infra-setup/evals/files/existing-playwright/playwright.config.ts new file mode 100644 index 0000000..272a7dd --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/existing-playwright/playwright.config.ts @@ -0,0 +1,22 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + reporter: 'html', + use: { + baseURL: 'http://localhost:4200', + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: { + command: 'npm run start', + url: 'http://localhost:4200', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json new file mode 100644 index 0000000..02fb558 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json @@ -0,0 +1,33 @@ +{ + "name": "sample-angular-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "test:unit": "ng test --watch=false", + "test:ci": "ng test --watch=false --browsers=ChromeHeadless", + "e2e": "playwright test", + "e2e:headed": "playwright test --headed", + "lint": "ng lint" + }, + "private": true, + "dependencies": { + "@angular/common": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/router": "^22.0.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^22.0.0", + "@angular/cli": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "@playwright/test": "^1.47.0", + "@types/node": "^22.10.0", + "typescript": "~5.5.2" + } +} diff --git a/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/playwright.config.ts b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/playwright.config.ts new file mode 100644 index 0000000..bc1881a --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/playwright.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + reporter: 'html', + use: { + baseURL: 'http://localhost:4200', + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + ], + webServer: { + command: 'npm run start', + url: 'http://localhost:4200', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json new file mode 100644 index 0000000..81f0dc2 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json @@ -0,0 +1,30 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "sample-angular-app": { + "projectType": "application", + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/sample-angular-app", + "index": "src/index.html", + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json" + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "port": 4200 + } + } + } + } + } +} diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/package-lock.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/package-lock.json new file mode 100644 index 0000000..d2e48fd --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/package-lock.json @@ -0,0 +1,18 @@ +{ + "name": "sample-angular-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sample-angular-app", + "version": "0.0.0", + "dependencies": { + "@angular/core": "^22.0.0" + }, + "devDependencies": { + "@angular/cli": "^22.0.0" + } + } + } +} diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json new file mode 100644 index 0000000..74dc77c --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json @@ -0,0 +1,38 @@ +{ + "name": "sample-angular-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^22.0.0", + "@angular/common": "^22.0.0", + "@angular/compiler": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/forms": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/platform-browser-dynamic": "^22.0.0", + "@angular/router": "^22.0.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^22.0.0", + "@angular/cli": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.4.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.9.2" + } +} diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts new file mode 100644 index 0000000..a4b425d --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + standalone: true, + template: `

Welcome to the sample Angular app

`, +}) +export class AppComponent { + title = 'sample-angular-app'; +} diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/src/index.html b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/index.html new file mode 100644 index 0000000..084ae92 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/index.html @@ -0,0 +1,12 @@ + + + + + Sample Angular App + + + + + + + From 9f8f28b7b8d90f9babbeb6988741d8fd06e4cacc Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 3 Sep 2026 15:55:36 +0200 Subject: [PATCH 4/6] Update ts --- .../evals/files/cypress-angular/package.json | 2 +- .../evals/files/existing-playwright/package.json | 2 +- .../evals/files/existing-scripts-and-playwright/package.json | 2 +- .../evals/files/fresh-angular/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json b/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json index 5c95c9c..85191e4 100644 --- a/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json +++ b/skills/accessibility-infra-setup/evals/files/cypress-angular/package.json @@ -24,6 +24,6 @@ "@angular/cli": "^22.0.0", "@angular/compiler-cli": "^22.0.0", "cypress": "^13.14.0", - "typescript": "~5.9.2" + "typescript": "~6.0.0" } } diff --git a/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json b/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json index d7ce11f..5505ca0 100644 --- a/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json +++ b/skills/accessibility-infra-setup/evals/files/existing-playwright/package.json @@ -24,6 +24,6 @@ "@angular/compiler-cli": "^22.0.0", "@playwright/test": "^1.47.0", "@types/node": "^22.10.0", - "typescript": "~5.9.2" + "typescript": "~6.0.0" } } diff --git a/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json index 02fb558..c50c3a1 100644 --- a/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json +++ b/skills/accessibility-infra-setup/evals/files/existing-scripts-and-playwright/package.json @@ -28,6 +28,6 @@ "@angular/compiler-cli": "^22.0.0", "@playwright/test": "^1.47.0", "@types/node": "^22.10.0", - "typescript": "~5.5.2" + "typescript": "~6.0.0" } } diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json index 74dc77c..73d7a26 100644 --- a/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/package.json @@ -33,6 +33,6 @@ "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", - "typescript": "~5.9.2" + "typescript": "~6.0.0" } } From 33cbf1778df3dc8e8963419ffec1bfc9de4cc2ab Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Thu, 3 Sep 2026 16:29:36 +0200 Subject: [PATCH 5/6] Add missing pieces for angular app --- .../evals/evals.json | 2 ++ .../evals/files/fresh-angular/angular.json | 17 ++++++++++++----- .../fresh-angular/src/app/app.component.ts | 7 ++++++- .../evals/files/fresh-angular/src/main.ts | 4 ++++ .../evals/files/fresh-angular/tsconfig.json | 19 +++++++++++++++++++ 5 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/src/main.ts create mode 100644 skills/accessibility-infra-setup/evals/files/fresh-angular/tsconfig.json diff --git a/skills/accessibility-infra-setup/evals/evals.json b/skills/accessibility-infra-setup/evals/evals.json index fdfbe2a..d1dcd52 100644 --- a/skills/accessibility-infra-setup/evals/evals.json +++ b/skills/accessibility-infra-setup/evals/evals.json @@ -10,7 +10,9 @@ "evals/files/fresh-angular/package.json", "evals/files/fresh-angular/angular.json", "evals/files/fresh-angular/package-lock.json", + "evals/files/fresh-angular/tsconfig.json", "evals/files/fresh-angular/src/index.html", + "evals/files/fresh-angular/src/main.ts", "evals/files/fresh-angular/src/app/app.component.ts" ], "expectations": [ diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json index 81f0dc2..0c2913b 100644 --- a/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/angular.json @@ -15,14 +15,21 @@ "outputPath": "dist/sample-angular-app", "index": "src/index.html", "browser": "src/main.ts", - "tsConfig": "tsconfig.app.json" - } + "tsConfig": "tsconfig.json" + }, + "configurations": { + "production": { "optimization": true, "outputHashing": "all" }, + "development": { "optimization": false, "sourceMap": true } + }, + "defaultConfiguration": "development" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "port": 4200 - } + "configurations": { + "production": { "buildTarget": "sample-angular-app:build:production" }, + "development": { "buildTarget": "sample-angular-app:build:development" } + }, + "defaultConfiguration": "development" } } } diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts index a4b425d..1564d33 100644 --- a/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/app/app.component.ts @@ -3,7 +3,12 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-root', standalone: true, - template: `

Welcome to the sample Angular app

`, + template: ` +
+

Welcome to the sample Angular app

+

Accessibility infrastructure smoke test.

+
+ `, }) export class AppComponent { title = 'sample-angular-app'; diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/src/main.ts b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/main.ts new file mode 100644 index 0000000..31c5da4 --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/src/main.ts @@ -0,0 +1,4 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent).catch((err) => console.error(err)); diff --git a/skills/accessibility-infra-setup/evals/files/fresh-angular/tsconfig.json b/skills/accessibility-infra-setup/evals/files/fresh-angular/tsconfig.json new file mode 100644 index 0000000..a83858a --- /dev/null +++ b/skills/accessibility-infra-setup/evals/files/fresh-angular/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "moduleResolution": "bundler", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022" + }, + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts"] +} From 6a963104ea8a42850acd40c82ef3a36984c48598 Mon Sep 17 00:00:00 2001 From: Lukas Matta Date: Fri, 4 Sep 2026 13:22:10 +0200 Subject: [PATCH 6/6] Add docs --- docs/README.md | 1 + docs/guides/accessibility-infra-setup.md | 88 ++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 docs/guides/accessibility-infra-setup.md diff --git a/docs/README.md b/docs/README.md index 366284b..d0aff01 100644 --- a/docs/README.md +++ b/docs/README.md @@ -72,6 +72,7 @@ Task-specific guidance for using individual skills. Start by picking your use ca | Guide | Description | |---|---| +| [Accessibility Infra Setup](./guides/accessibility-infra-setup.md) | Bootstrap Playwright + axe-core a11y infrastructure in an Angular app (WCAG 2.2 AA) — config, shared fixture, one example scan, npm scripts, docs | | [TDD Workflow](./guides/tdd-workflow.md) | Test-driven development with: specification, confirmation gates, and vertical-sliced implementation | | [Unit Test Standards](./guides/test-unit-standards.md) | Reference for unit test standards across isolation, scope, naming, assertions, coverage, fixtures | | [Unit Test Writer](./guides/test-unit-write.md) | Generate complete unit tests from scratch following language-specific standards | diff --git a/docs/guides/accessibility-infra-setup.md b/docs/guides/accessibility-infra-setup.md new file mode 100644 index 0000000..e298ce8 --- /dev/null +++ b/docs/guides/accessibility-infra-setup.md @@ -0,0 +1,88 @@ +# Accessibility Infra Setup Skill + +The `accessibility-infra-setup` skill bootstraps automated accessibility (a11y) check infrastructure in an existing Angular application using [Playwright](https://playwright.dev/) + [axe-core](https://github.com/dequelabs/axe-core) (`@axe-core/playwright`). It scaffolds the plumbing to catch automatically detectable **WCAG 2.2 AA** violations and proves it works with one passing example scan. + +It activates when you ask to set up accessibility checks, add a11y testing infrastructure, or wire axe-core into an Angular app. + +--- + +## What it does + +The skill extends your existing test setup rather than replacing it, then validates the result end to end: + +| Step | Action | +|------|--------| +| Detect | Inspects `package.json`, the dev-server script, package manager, and any existing Playwright / Cypress setup | +| Install | Adds `@playwright/test` + `@axe-core/playwright` and installs the Chromium browser | +| Scaffold | Creates `playwright.config.ts`, a shared axe fixture, and one dummy example scan | +| Wire scripts | Adds `test:a11y*` npm scripts to `package.json` | +| Validate | Runs the dummy scan until it passes green — the definition of done | +| Document | Adds `docs/accessibility.md` (or `playwright/README.md`) with how to run and where reports land | + +**Scope:** infrastructure plus exactly **one** dummy example scan. Authoring real accessibility tests, fixing violations, and CI wiring are all out of scope. + +--- + +## Expected outcome + +After the skill runs, the repository contains: + +``` +playwright/ +├── fixtures/ +│ └── axe-helpers.ts # Shared axe fixture (WCAG 2.2 AA tags) + assertion helpers +└── a11y/ + └── example.accessibility.spec.ts # ONE dummy scan of the "/" route — passes +playwright.config.ts # `accessibility` project (Desktop Chrome, testMatch /accessibility/) +docs/accessibility.md # How to run, where reports land +``` + +Running `npm run test:a11y` starts the dev server, runs the dummy scan on Desktop Chrome, and passes green. + +--- + +## How to trigger it + +Ask naturally — the skill fires on intent, not exact wording: + +``` +set up accessibility checks +add a11y testing infrastructure +add axe-core to this Angular app +set up WCAG testing +add accessibility scans with Playwright +bootstrap a11y infra +``` + +--- + +## Requirements + +- An existing Angular application with a runnable dev server (`npm run start` on port 4200) +- Node.js 22+ +- Network access on first run (Playwright downloads the Chromium browser) + +--- + +## Coexistence rules + +- **Never touches Cypress.** If the repo uses Cypress, its config, specs, and dependencies are left untouched — Playwright is added alongside it. +- **Extends, doesn't recreate Playwright.** When a `playwright.config.*` already exists, the skill merges an `accessibility` project into it and reuses any existing axe fixture instead of adding a duplicate. + +--- + +## Installation + +The skill is installed along with the rest of the toolkit: + +```bash +npx skills add https://github.com/AbsaOSS/agentic-toolkit -g +``` + +To install only this skill: + +```bash +npx skills add https://github.com/AbsaOSS/agentic-toolkit -g --skill accessibility-infra-setup +``` + +See [Getting Started](../getting-started.md) for the full install guide.