Skip to content

Commit f929584

Browse files
Add Playwright + Lighthouse CI scaffold for the BOxCrete website
Pins down the design and behavioral invariants of the interactive web explorer so we don't regress on them. Two CI workflows run on PRs that touch docs/. Playwright (.github/workflows/e2e.yml) ====================================== Eight specs covering 44 tests (29 active, 15 intentionally skipped): - home-loads: smoke test, no console errors, canvases render - header-layout: theme toggle is rightmost; cite group adjacent (desktop) / hidden (mobile); 5 mobile items evenly spaced; sticky header; no horizontal pan - scatter-toggle: X/Y axis labels cycle on click - mobile-panel-toggle: Composition <-> Performance Tradeoffs tabs swap views and update active state - theme-toggle: data-theme flips, persists across reload - about-modal: opens via link, closes via X / Escape / overlay click - sliders: at least 5 sliders rendered; slider input redraws curve canvas - visual-regression: full-page screenshots (skipped until Linux baselines are committed; see test/e2e/README.md for the docker recipe) Two projects per spec: 'desktop' (1280x800 Chrome) and 'mobile' (Pixel 7 emulation, also Chromium so CI installs only one browser engine). Project-specific tests skip themselves when run under the wrong project. Lighthouse CI (.github/workflows/lighthouse.yml) ================================================ Enforces: - Accessibility >= 0.90 (axe-core color-contrast etc.) - Performance >= 0.85 (warn) - CLS < 0.1 (error) - Resource budgets per type (script <= 300KB, image <= 1.5MB, total <= 3MB) defined in budgets.json - Timing budgets (FCP < 2.5s, LCP < 4s, TTI < 5s) Conventions =========== - Each spec corresponds to a named, plain-English invariant; see test/e2e/README.md for the catalogue. - Tests serve docs/ via http-server on port 4173. - Playwright auto-starts the server on test invocation. - pytest.ini ignores test/e2e/ so Python and TypeScript tests don't collide. - node_modules, playwright-report, test-results, .lighthouseci ignored in .gitignore. package-lock.json IS committed (npm ci needs it). Local usage =========== npm install npx playwright install --with-deps chromium npm run test:e2e # all projects npm run test:e2e:ui # interactive debugger npm run test:e2e:report # show last HTML report Verified locally: 29 passed, 15 skipped, 0 failed.
1 parent 2b9d267 commit f929584

18 files changed

Lines changed: 5287 additions & 1 deletion

.github/workflows/e2e.yml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Playwright end-to-end tests for the BOxCrete website.
2+
# Runs on PRs that touch the website or the test specs themselves.
3+
# See test/e2e/README.md for the catalogue of invariants and how to add new tests.
4+
5+
name: E2E (Playwright)
6+
7+
on:
8+
push:
9+
branches: [main]
10+
paths:
11+
- 'docs/**'
12+
- 'test/e2e/**'
13+
- 'playwright.config.ts'
14+
- 'package.json'
15+
- '.github/workflows/e2e.yml'
16+
pull_request:
17+
branches: [main]
18+
paths:
19+
- 'docs/**'
20+
- 'test/e2e/**'
21+
- 'playwright.config.ts'
22+
- 'package.json'
23+
- '.github/workflows/e2e.yml'
24+
workflow_dispatch:
25+
inputs:
26+
update_snapshots:
27+
description: 'Regenerate visual snapshots and upload as an artifact'
28+
required: false
29+
default: 'false'
30+
31+
# Restrict GITHUB_TOKEN to read-only on repo contents.
32+
permissions:
33+
contents: read
34+
35+
env:
36+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
37+
38+
jobs:
39+
e2e:
40+
runs-on: ubuntu-latest
41+
timeout-minutes: 20
42+
43+
strategy:
44+
fail-fast: false
45+
matrix:
46+
project: [desktop, mobile]
47+
48+
steps:
49+
- uses: actions/checkout@v4
50+
51+
- uses: actions/setup-node@v4
52+
with:
53+
node-version: '20'
54+
cache: 'npm'
55+
56+
- name: Install dependencies
57+
run: npm ci
58+
59+
- name: Cache Playwright browsers
60+
id: pw-cache
61+
uses: actions/cache@v4
62+
with:
63+
path: ~/.cache/ms-playwright
64+
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
65+
66+
- name: Install Playwright browsers
67+
if: steps.pw-cache.outputs.cache-hit != 'true'
68+
run: npx playwright install --with-deps chromium
69+
70+
- name: Install Chromium system deps (cached browsers path)
71+
if: steps.pw-cache.outputs.cache-hit == 'true'
72+
run: npx playwright install-deps chromium
73+
74+
- name: Run Playwright tests
75+
run: npx playwright test --project=${{ matrix.project }}
76+
env:
77+
CI: true
78+
79+
- name: Update snapshots (manual dispatch only)
80+
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.update_snapshots == 'true' }}
81+
run: npx playwright test --project=${{ matrix.project }} --update-snapshots
82+
env:
83+
CI: true
84+
85+
- name: Upload Playwright report on failure
86+
if: failure()
87+
uses: actions/upload-artifact@v4
88+
with:
89+
name: playwright-report-${{ matrix.project }}
90+
path: |
91+
playwright-report/
92+
test-results/
93+
retention-days: 14
94+
95+
- name: Upload regenerated snapshots
96+
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.update_snapshots == 'true' }}
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: snapshots-${{ matrix.project }}
100+
path: test/e2e/**/*-snapshots/**
101+
retention-days: 30

.github/workflows/lighthouse.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Lighthouse CI: enforces performance, accessibility, and resource budgets
2+
# on the BOxCrete website. Runs on PRs that touch the site.
3+
# Configuration: lighthouserc.json + budgets.json.
4+
5+
name: Lighthouse CI
6+
7+
on:
8+
push:
9+
branches: [main]
10+
paths:
11+
- 'docs/**'
12+
- 'lighthouserc.json'
13+
- 'budgets.json'
14+
- '.github/workflows/lighthouse.yml'
15+
pull_request:
16+
branches: [main]
17+
paths:
18+
- 'docs/**'
19+
- 'lighthouserc.json'
20+
- 'budgets.json'
21+
- '.github/workflows/lighthouse.yml'
22+
workflow_dispatch:
23+
24+
permissions:
25+
contents: read
26+
27+
env:
28+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
29+
30+
jobs:
31+
lighthouse:
32+
runs-on: ubuntu-latest
33+
timeout-minutes: 15
34+
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- uses: actions/setup-node@v4
39+
with:
40+
node-version: '20'
41+
cache: 'npm'
42+
43+
- name: Install dependencies
44+
run: npm ci
45+
46+
- name: Run Lighthouse CI
47+
run: npx lhci autorun
48+
env:
49+
# Public uploads to temporary-public-storage are anonymous;
50+
# no token required for our config.
51+
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,11 @@ GWPvsStrength.png
7070

7171
# Planning files
7272
*.plan.md
73+
74+
# E2E / Playwright / Lighthouse CI
75+
node_modules/
76+
playwright-report/
77+
test-results/
78+
.lighthouseci/
79+
blob-report/
80+
playwright/.cache/

budgets.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[
2+
{
3+
"path": "/*",
4+
"resourceSizes": [
5+
{ "resourceType": "document", "budget": 50 },
6+
{ "resourceType": "stylesheet", "budget": 50 },
7+
{ "resourceType": "script", "budget": 300 },
8+
{ "resourceType": "image", "budget": 1500 },
9+
{ "resourceType": "font", "budget": 100 },
10+
{ "resourceType": "third-party", "budget": 200 },
11+
{ "resourceType": "total", "budget": 3000 }
12+
],
13+
"resourceCounts": [
14+
{ "resourceType": "third-party", "budget": 5 },
15+
{ "resourceType": "image", "budget": 10 },
16+
{ "resourceType": "font", "budget": 4 }
17+
],
18+
"timings": [
19+
{ "metric": "first-contentful-paint", "budget": 2500 },
20+
{ "metric": "largest-contentful-paint", "budget": 4000 },
21+
{ "metric": "interactive", "budget": 5000 }
22+
]
23+
}
24+
]

lighthouserc.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"ci": {
3+
"collect": {
4+
"url": ["http://127.0.0.1:4173/"],
5+
"startServerCommand": "npx http-server docs -p 4173 -s -c-1 -a 127.0.0.1",
6+
"startServerReadyPattern": "Available on:",
7+
"numberOfRuns": 3,
8+
"settings": {
9+
"preset": "desktop",
10+
"skipAudits": ["uses-http2", "redirects-http"]
11+
}
12+
},
13+
"assert": {
14+
"preset": "lighthouse:recommended",
15+
"budgetsFile": "./budgets.json",
16+
"assertions": {
17+
"categories:performance": ["warn", { "minScore": 0.85 }],
18+
"categories:accessibility": ["error", { "minScore": 0.9 }],
19+
"categories:best-practices": ["warn", { "minScore": 0.9 }],
20+
"categories:seo": ["warn", { "minScore": 0.9 }],
21+
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
22+
"color-contrast": ["error", { "minScore": 1 }],
23+
"csp-xss": "off",
24+
"is-on-https": "off",
25+
"uses-text-compression": "off",
26+
"valid-source-maps": "off"
27+
}
28+
},
29+
"upload": {
30+
"target": "temporary-public-storage"
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)