A deliberately testable, full-stack web application where Test Automation Engineers practice Playwright against a realistic target β from your first getByRole to WebSocket frames, storageState sessions, page.clock time travel and Page Object architecture.
Every challenge page states the task, lists the Playwright concepts it teaches, gives progressive hints, and links to a runnable reference test in examples/. The reference suite runs against the app on every change β that is what keeps every challenge provably solvable.
- 46 challenges across 5 tracks β basic, intermediate, advanced, expert and real-world β mapped explicitly to the official Playwright feature surface (locators, auto-wait,
page.route,storageState,page.clock, tracing, sharding,addLocatorHandler, HARβ¦). - A real backend (Fastify): practice
request-fixture API testing, JWT auth with MFA, uploads/downloads, WebSockets and SSE β not just UI clicks. - Chaos Mode: a global toggle that injects latency and DOM re-mounts so you learn to write tests that survive real-world flakiness.
- Progress tracking in localStorage β which is itself a storage-assertion challenge.
- Dogfooded: ~120 reference tests run in CI across Chromium, Firefox and WebKit.
npm install # installs workspaces (apps/web, apps/api) + tooling
npx playwright install # downloads the three browser engines
npm run dev # starts web (5173) + api (3001) togetherOpen http://localhost:5173 and pick a challenge. To write your own tests against it:
npm init playwright@latest # in a separate folder (or reuse this repo's config)
# set baseURL to http://localhost:5173 and start solvingOr run the shipped reference suite (it boots both servers itself):
npm run test:examples # Chromium
npm run test:examples:all # Chromium + Firefox + WebKitββ apps/
β ββ web/ # Vite + React + TS β the practice target SPA
β β ββ src/challenges/ # one folder per challenge (component + metadata)
β ββ api/ # Fastify practice API (auth, CRUD, WS, SSE, uploads)
ββ examples/ # reference Playwright suites, one file per challenge
β ββ basic/ intermediate/ advanced/ shop/
β ββ utils.ts # loginViaApi, seedSession, reset helpers
ββ docs/ # challenge catalog + API reference
ββ playwright.config.ts # 3 browser projects, webServer auto-start
ββ .github/workflows/ci.yml # sharded CI with trace artifacts
| # | Challenge | Concepts |
|---|---|---|
| 1 | Locator Gym | role / label / placeholder / text / testid / CSS / XPath locators, strict mode |
| 2 | Actions Playground | click, dblclick, right-click, hover, press, check, selectOption, focus/blur |
| 3 | Form Validation | fill, disabled/enabled assertions, inline error messages |
| 4 | Assertions Zoo | toHaveText/Value/Count/Attribute/Class/URL/Title, visibility |
| 5 | Navigation Wizard | client-side routes, waitForURL, goBack, redirects |
| 6 | First E2E Test | the login β dashboard β logout skeleton |
Waits & auto-waiting Β· Dynamic content (infinite scroll, polling) Β· Dropdowns & typeahead Β· Data tables (sort/filter/paginate) Β· iFrames Β· Windows & popups Β· Dialogs Β· Drag & drop (incl. canvas) Β· Files (upload/download) Β· Network inspection (page.route, waitForResponse) Β· Toasts Β· Clipboard & selection.
Auth & sessions (JWT + MFA + storageState) Β· API testing (request fixture, full error matrix) Β· Mocking & HAR Β· WebSockets & SSE Β· Shadow DOM Β· Visual testing (masking, baselines) Β· Clock & timers (page.clock) Β· Storage & cookies Β· Emulation (geolocation, devices, locale, timezone) Β· A11y & aria snapshots Β· Flakiness clinic Β· Parallelism & sharding Β· Debugging & tracing Β· Capstone: POM & custom fixtures (a complete e-commerce shop).
Setup project & storageState (the canonical auth architecture, wired into this repo's config) Β· HAR record & replay Β· Overlay clinic (page.addLocatorHandler) Β· Console & page-error monitoring (auto fixture policy) Β· test.step, attachments & programmatic tracing Β· Network surgery (route.fetch patching, { times }, route.fallback) Β· Worker-scoped fixtures & parallel-safe data.
Analytics & tracking verification (network spies + exposeBinding) Β· Multi-user contexts (two browser identities talking live) Β· Keyboard navigation & focus (skip links, roving tabs, modal traps) Β· Custom matchers & soft assertions (expect.extend) Β· Performance smoke testing (budgets, resource entries, page.metrics()) Β· Kata: fix this bad test (a deliberately awful suite to refactor) Β· Config layering & environments (feature-flag matrices, annotations, layered configs β see playwright.smoke.config.ts).
See docs/challenge-catalog.md for the full table with links, docs/api-reference.md for endpoint details, and docs/architecture.md for Mermaid diagrams of the system.
Real HTTP, same-origin with the SPA (the Vite dev server proxies /api, /auth, /ws, /sse):
POST /auth/loginβ JWT. Demo users:standard@demo.io/secret123,admin@demo.io/admin123GET|POST|PUT|DELETE /api/articlesβ CRUD with 400/401/404/409 pathsPOST /api/orders,GET /api/productsβ the shop capstoneGET /api/slow?ms=,/api/flaky,/api/limitedβ timing, retry and 429 practicePOST /api/upload,GET /api/files/:name/downloadβ multipart + downloadsWS /ws/chat,GET /sse/tickerβ realtimePOST /api/resetβ restore seed data for per-test isolation
Full reference: docs/api-reference.md or the in-app /api-docs page.
- Run the app, open a challenge, read only the task.
- Write a test for it in your own suite.
- Stuck? Reveal hints one at a time.
- Done? Compare with the reference test in
examples/β and try to make yours cleaner.
Turn on Chaos Mode (header toggle) to replay any challenge under injected latency and re-mounts.
| Command | What it does |
|---|---|
npm run dev |
web + api together |
npm run dev:web / dev:api |
just one of them |
npm run build |
production build of the SPA |
npm run typecheck |
TS check of the web app |
npm run test:examples |
reference suite, Chromium |
npm run test:examples:all |
reference suite, all three engines |
npm run report |
browse the latest HTML report at localhost:9323 |
Every run produces a report.
- Local: each test run writes an interactive HTML report to
playwright-report/(it auto-opens in your browser only when something fails). View the latest one any time withnpm run report. - CI: each of the 3 shards emits a blob report; a
reportjob merges them into a single HTML report, uploaded as theplaywright-reportartifact on every run (even red ones) β download it from the run's Artifacts section and open withnpx playwright show-report <unzipped-folder>. The run page also shows a results table (passed/failed/flaky/skipped + duration) in the job summary, and failures get inline PR annotations plus trace/video artifacts for debugging. - Failure traces and videos are always retained for 7 days; the merged report for 14.
Every run β local and CI β can be recorded into an append-only history store, with a dashboard for trend analysis.
flowchart LR
T["playwright test"] -->|"json report<br/>(local: auto, CI: merge-reports)"| C["collect.mjs<br/>run record"]
C --> H["history.jsonl<br/>(local dir / test-history branch)"]
H --> D["π dashboard<br/>localhost:4310"]
B["test-history branch"] -.->|"history:sync"| H
- Every local run automatically writes
test-history/last-run.json. Add it to the history withnpm run history:record(or the dashboard button) β so throwaway debug runs don't pollute trends. - Every CI run is recorded automatically: the
reportjob appends the run record to thetest-historybranch (dedup by run id, so re-runs don't duplicate). npm run dashboardstarts the analysis dashboard at http://localhost:4310 β pass-rate and duration trends, per-run outcomes, flakiest and slowest test rankings, and recent runs with links to the CI run.Sync from CI(ornpm run history:sync) merges the branch history into your local store.
Records are compact JSONL (totals + per-test rows), so the store is diff-friendly and scales to thousands of runs.
Broken challenge? Missing concept? PRs welcome β see CONTRIBUTING.md for the setup guide and the one hard rule: every challenge ships with a green reference test.
MIT β use it, fork it, teach with it.