Adds tests/e2e/24-axe-wcag.spec.ts — a Playwright spec running @axe-core/playwright (already in deps) against home, login, register, dashboard, discover, and search. The test fails on any "serious" or "critical" axe violation at WCAG 2.1 AA conformance level ; "moderate" and "minor" violations are logged for backlog visibility but don't gate the build. What this catches that 11-accessibility-ethics.spec.ts (heuristic checks) misses : - Color-contrast violations across the entire DOM - ARIA role / state mismatches - Form fields without programmatic labels - Focus-trap errors in modals - Heading-order regressions Wiring : - New @a11y test tag + npm script "e2e:a11y" - .github/workflows/e2e.yml runs e2e:a11y after e2e:critical on every PR + push (~30s overhead). - Toast portals excluded ([data-sonner-toaster], .toast-container) to avoid false positives on transient color-contrast. - Failure prints rule ids + impact + node count so the cause is visible in the CI log without artifact retrieval. Lighthouse/LHCI was previously removed (security audit A06) — axe-core is the modern recommended replacement and is what the WCAG 2.1 AA conformance ask actually needs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.3 KiB
E2E CI — runbook
v1.0.8 Batch C — Playwright E2E suite running on Forgejo Actions. Workflow:
.github/workflows/e2e.yml. Tests:tests/e2e/*.spec.ts. Skipped tests inventory:tests/e2e/SKIPPED_TESTS.md.
Triggers
| Trigger | Scope | Target time | Why |
|---|---|---|---|
PR opened / synced (against main) |
@critical only |
~5–7 min | Fast feedback loop, blocks merge if red |
Push to main |
Full suite | ~25 min | Catches regressions that slipped past @critical |
| Nightly cron (03:00 UTC) | Full suite | ~25 min | Catches infra drift independent of merges |
workflow_dispatch |
Full suite | manual | Re-run after a flaky failure or on a feature branch |
@critical is a Playwright --grep tag — see npm run e2e:critical.
How a CI run works
actions/checkout+setup-node@20+setup-go@1.25.npm cifrom repo root.- Adds
127.0.0.1 veza.frto/etc/hostsso the browsers can hit the dev domain. - Generates dev JWT keys + SSL cert via the existing scripts.
- Brings up
postgres / redis / rabbitmqviadocker compose. - Runs Go migrations.
go run ./cmd/tools/seed --ci— the lean seed: 5 test accounts- 10 tracks + 3 playlists, no chat/live/marketplace/analytics. ~5s.
- Builds + starts the backend on
localhost:18080, asserts/api/v1/health. playwright install --with-deps chromium.- Runs
npm run e2e:critical(PR) ornpm run e2e(push/cron).CI=trueis exported globally soplaywright.config.ts:141,155spawns its own Vite + backend instance instead of trying to reuse. - On failure: uploads the Playwright HTML report and
backend.logas artifacts, retained 7 days.
Required secrets (Forgejo)
The workflow falls back to dev defaults so it can still run on a fresh repo without secrets configured, but production-style runs should set these in Forgejo Actions secrets:
| Secret | Default fallback | Purpose |
|---|---|---|
E2E_DB_PASSWORD |
devpassword |
Postgres password (must match docker-compose.yml) |
E2E_JWT_SECRET |
ci-dev-jwt-secret-32-chars-min-padding!! |
HS256 signing key (32+ chars) |
E2E_RABBITMQ_URL |
amqp://guest:guest@localhost:5672/ |
RabbitMQ AMQP URL |
Without these, the workflow still passes for everything that doesn't exercise WebSocket / RabbitMQ paths under load.
Reproducing a CI failure locally
Mirrors the workflow exactly:
# From repo root
make infra-up-dev # postgres + redis + rabbitmq
cd veza-backend-api
go run cmd/migrate_tool/main.go
go run ./cmd/tools/seed --ci # 5 test accounts only
go build -o veza-api ./cmd/api/main.go
APP_ENV=test ./veza-api &
# In another shell
cd apps/web && npm run dev -- --host 127.0.0.1 --port 5174 &
# Run the same tests CI ran
cd /path/to/repo
CI=true npm run e2e:critical # PR scope
# or
CI=true npm run e2e # full suite
If the failure only reproduces under CI=true, suspect
reuseExistingServer — set CI= (empty) to flip back to local mode
and bisect.
Debugging a red run
- Open the run in Forgejo Actions UI.
- Find the failing job's "Run E2E" step. Each test failure shows the selector / assertion / screenshot inline.
- Scroll to the artifact section: download
playwright-report-<run-id>-<attempt>(the HTML report — opens in any browser, shows trace viewer + video for retry-on-fail) andbackend-log-<run-id>-<attempt>(full backend stdout + stderr). - If the failure looks env-related (404 on a known route, 500
without a clear cause), check
backend-logfor panics or migration errors before assuming a test bug. - Cross-check
tests/e2e/SKIPPED_TESTS.md— if the test is already listed as flaky, the right fix may be.skip()until the underlying app bug is tracked.
Adding a new E2E test
- Drop a
*.spec.tsfile undertests/e2e/. - Tag it with
@criticalif it must run on every PR (be conservative — every@criticaltest extends the PR feedback loop). - Use the auth fixture from
tests/e2e/fixtures/auth.fixture.ts(listenerPage/creatorPage/adminPage/moderatorPage) instead of writing UI login flows. - If the test needs DB state outside the
--ciseed (rare), seed it from inside the test viapage.request.post(...)rather than extending the seed tool — keeps the seed lean. - Run locally with
CI=true npm run e2e:critical -- --grep "your test"before pushing.
Scaling considerations
- Forgejo runner pool is shared across CI workflows — keep PR runs under 10 min so we don't hold a runner during peak hours.
docker compose up -d postgres redis rabbitmqreuses the dev compose file; if that file changes, the workflow inherits the change automatically.- The full suite is gated to push/cron/dispatch precisely because we don't want to pay 25 min on every PR push.
Accessibility (@a11y axe-core WCAG 2.1 AA scan)
v1.0.10 ops item 12 — tests/e2e/24-axe-wcag.spec.ts runs
@axe-core/playwright against home, login, register, dashboard,
discover, and search. The test fails on any serious or
critical axe violation at WCAG 2.1 AA level ; moderate /
minor violations are logged but don't gate.
- Trigger : every PR + push (alongside
@critical). Adds ~30s. - Local run :
npm run e2e:a11y. - Reports : violation summary printed to stdout in the CI log ; the full Playwright HTML report is uploaded as an artifact on failure (see "Upload Playwright report" step).
- Exclusions :
[data-sonner-toaster]+.toast-container(toast portal nodes occasionally flagged for transient color contrast). - Adding a new route : append to the
targetsarray in24-axe-wcag.spec.ts. If it's auth-only, setrequiresAuth: true. - Fixing a violation : the test output prints rule id + impact + count of nodes. Cross-reference with https://dequeuniversity.com/rules/axe/4.10/ for the remediation guide.
Related
tests/e2e/playwright.config.ts— base config,reuseExistingServer: !process.env.CI(committed in v1.0.8 C3, commit46d21c5c).veza-backend-api/cmd/tools/seed/config.go—CIConfig()and the--ciflag (committed in v1.0.8 C4, commitcee850a5).tests/e2e/SKIPPED_TESTS.md— known flakes + tickets to resolve.docs/audit-2026-04/v107-plan.md— historical context for E2E coverage gaps that landed in v1.0.7.