Skip to content

Commit 86f26f7

Browse files
authored
Merge pull request #1580 from coseeian/a11y-ci-scan
feat: run Playwright accessibility scan on pull requests
2 parents dfd5d4e + c50c582 commit 86f26f7

4 files changed

Lines changed: 71 additions & 18 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ name: Test, typecheck, and lint
33
on:
44
pull_request:
55

6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
8+
cancel-in-progress: true
9+
610
permissions:
711
contents: read
812

@@ -48,6 +52,7 @@ jobs:
4852
run: npm run check
4953
build:
5054
runs-on: ubuntu-latest
55+
timeout-minutes: 30
5156
steps:
5257
- name: Checkout your repository using git
5358
uses: actions/checkout@v6
@@ -62,3 +67,17 @@ jobs:
6267
SKIP_BUILD_COMPRESS: 1
6368
NODE_OPTIONS: "--max_old_space_size=4096"
6469
run: npm run build
70+
- name: Install Playwright browser
71+
run: npx playwright install --with-deps chromium
72+
- name: Run accessibility tests
73+
continue-on-error: true
74+
run: npm run test:a11y
75+
- name: Upload Playwright report
76+
if: ${{ !cancelled() }}
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: playwright-report
80+
path: |
81+
playwright-report/
82+
test-results/
83+
retention-days: 14

‎playwright.config.ts‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@ import { defineConfig, devices } from "@playwright/test";
22

33
const PORT = 4321;
44
const BASE_URL = `http://localhost:${PORT}`;
5+
const isCI = Boolean(process.env.CI);
56

67
export default defineConfig({
78
testDir: "./test/a11y",
89
testMatch: "**/*.spec.ts",
910
outputDir: "./test-results",
1011
fullyParallel: true,
11-
reporter: [
12-
["list"],
13-
['html', { outputFolder: 'playwright-report', open: 'never' }]
14-
],
12+
forbidOnly: isCI,
13+
reporter: isCI
14+
? [
15+
["github"],
16+
["list"],
17+
["html", { outputFolder: "playwright-report", open: "never" }],
18+
]
19+
: [
20+
["list"],
21+
['html', { outputFolder: 'playwright-report', open: 'never' }]
22+
],
1523

1624
use: {
1725
baseURL: BASE_URL,
@@ -34,10 +42,12 @@ export default defineConfig({
3442
],
3543

3644
webServer: {
37-
command: "npm run dev",
45+
// CI serves the dist/ built by an earlier step; see .github/workflows/test.yml.
46+
command: isCI ? "npm run preview" : "npm run dev",
3847
url: BASE_URL,
39-
reuseExistingServer: true,
48+
reuseExistingServer: !isCI,
4049
timeout: 180_000,
50+
stdout: isCI ? "pipe" : "ignore",
4151
env: {
4252
A11Y_TEST: "1",
4353
},

‎test/a11y/homepage.spec.ts‎

Lines changed: 0 additions & 12 deletions
This file was deleted.

‎test/a11y/pages.spec.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import AxeBuilder from "@axe-core/playwright";
2+
import { expect, test } from "@playwright/test";
3+
4+
const pagesToScan = [
5+
{ name: "home", path: "/" },
6+
{ name: "about", path: "/about/" },
7+
{ name: "community", path: "/community/" },
8+
{ name: "contribute", path: "/contribute/" },
9+
{ name: "education resources", path: "/education-resources/" },
10+
{ name: "events", path: "/events/" },
11+
{ name: "libraries", path: "/libraries/" },
12+
{ name: "people", path: "/people/" },
13+
{ name: "sketches", path: "/sketches/" },
14+
{ name: "search", path: "/search/" },
15+
{ name: "tutorials index", path: "/tutorials/" },
16+
{ name: "tutorial", path: "/tutorials/get-started/" },
17+
{ name: "examples index", path: "/examples/" },
18+
{ name: "example", path: "/examples/Shapes-And-Color-Shape-Primitives/" },
19+
{ name: "reference index", path: "/reference/" },
20+
{ name: "reference function", path: "/reference/p5/ellipse/" },
21+
{ name: "reference class method", path: "/reference/p5.Vector/add/" },
22+
{ name: "reference p5.sound", path: "/reference/p5.sound/" },
23+
{ name: "404", path: "/no-such-page/" },
24+
];
25+
26+
test.describe("a11y", () => {
27+
for (const { name, path } of pagesToScan) {
28+
test(`${name} should not have any automatically detectable accessibility issues`, async ({
29+
page,
30+
}) => {
31+
await page.goto(path);
32+
const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
33+
expect(accessibilityScanResults.violations).toEqual([]);
34+
});
35+
}
36+
});

0 commit comments

Comments
 (0)