- Move emojis after headline text (CONTRIBUTING.md, actions/, design/, tools/, tests/) - Replace em dashes with colons, semicolons, or complete sentences throughout - Add missing emojis to all headlines in exceptions.md, principles.md, services.md, shell.md, setup.md, pull-request.md, commit.md, act.md, docker.md, pr/README.md - Update H1 titles to reflect renamed directories (actions/, design/) - Fix broken relative links in workflow.md after directory moves - Fix full-path link texts in services.md (style.css.md, javascript.js.md) - Fix broken principles.md link to lint.md after testing/ → actions/testing/ move Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.9 KiB
Playwright Tests 🎭
This page is the SPOT for Playwright end-to-end test requirements, runner integration, and file contracts.
For implementation guidance when writing or updating role-local files, see
Agent playwright.spec.js and
Agent playwright.env.j2.
Framework 🧰
- Playwright runs inside Docker via the shared
test-e2e-playwrightrole. - There is no standalone
maketarget for Playwright. Tests run as part of local deploy flows (e.g.FULL_CYCLE=true APPS=web-app-matomo make deploy-fresh-purged-apps).
When to Write ✍️
- You MUST provide Playwright tests for every
web-*role. - You MUST update the Playwright suite when you add or change role-local
javascript.jsorstyle.css.
Role-Local Files 📁
Every Playwright-enabled role MUST provide exactly these two files:
| File | Purpose |
|---|---|
files/playwright.spec.js |
Test scenarios executed by the Playwright runner |
templates/playwright.env.j2 |
Rendered .env passed to the Playwright container |
package.json and playwright.config.js MUST remain centralized in roles/test-e2e-playwright/files/.
You MUST NOT duplicate or override them per role.
Runner 🚀
The test-e2e-playwright role discovers Playwright-enabled roles through the presence of
templates/playwright.env.j2. For each discovered role it:
- stages the test project
- renders
.envfromplaywright.env.j2 - copies
files/playwright.spec.jsinto the project astests/playwright.spec.js - injects the shared
package.jsonandplaywright.config.js - waits until the app is reachable
- runs Playwright in Docker
File Requirements 📄
See the dedicated SPOT pages for authoring rules:
playwright.spec.js: scenario design, selector strategy, and live reviewplaywright.env.j2: rendered test input surface, variable naming, and entry-point selection
Recording Tests 🎬
Playwright Codegen (built-in) 🔧
Playwright ships a built-in code recorder:
npx playwright codegen https://<app-url>
This opens the Playwright Inspector alongside a browser. Every interaction is recorded and emitted as a runnable spec. Use the output as a starting draft and clean it up according to the authoring rules in playwright.spec.js.
playwright-recorder (Docker-based) 🐳
For infrastructure-heavy setups where Playwright should not live in the main repository, use playwright-recorder. It wraps Playwright codegen in Docker with X11/XWayland forwarding and an ephemeral workspace so no state leaks between recordings.
Requirements: Docker, X11 or XWayland, xhost
# Install
make install
# Record a flow starting at a specific URL
make codegen
# or directly:
./scripts/codegen.sh https://<app-url>/login
# Replay a recorded spec headlessly
make replay
# or directly:
./scripts/replay.sh recordings/login.spec.ts
Generated files are persisted in the local workspace (git-ignored). Copy the relevant parts into files/playwright.spec.js and adapt them.
Development Procedure 📋
- Analyze the deployed application in a running local stack.
- Build hypotheses about the expected user flows before writing tests.
- Optionally record a draft with Playwright codegen or
playwright-recorder. - Write or update
files/playwright.spec.jsandtemplates/playwright.env.j2. - Run the relevant deploy flow (e.g.
FULL_CYCLE=true APPS=<role> make deploy-fresh-purged-apps). - Run
make trust-caand open the app in your browser to confirm the flow manually. - Inspect the browser console for errors when the flow depends on injected JavaScript.
- Verify the suite finishes in a logged-out state.