e2e
Use when adding or fixing browser-level tests for kasane, when a change touches routing, deep links, the Netlify SPA fallback or MangaDex proxy, or when asked to verify a user journey end to end rathe
SKILL.md.claude/skills/e2e/SKILL.md
GitHubEnd-to-End Tests
Playwright drives the real dist/ export, not a dev server, so the suite covers the bundle that actually ships including the SPA fallback and the MangaDex proxy shape.
Run it
bun run e2e:install # once: downloads chromium
bun run build:web # required — the suite serves dist/
bun run e2e
bun run e2e -- --headed --project=chromium # watch it
e2e/serve.ts serves dist/ on port 4173 and reproduces the two netlify.toml behaviours the app depends on: fallback to index.html for any unmatched path, and /_mdx/* proxied to api.mangadex.org. Playwright starts it via webServer and reuses a running one locally.
A stale dist/ silently tests old code. Rebuild before trusting a pass.
Writing a test
Target visible copy the app owns. React Native Web renders deeply nested unlabelled divs whose structure changes whenever a StyleSheet does, so CSS selectors and nth indexes rot immediately.
| Prefer | Avoid |
|---|---|
getByPlaceholder(/search/i) |
locator("input").nth(2) |
getByText(/quick lookup/i) |
locator("div > div > span") |
getByRole("button", { name: "Sign in" }) |
locator(".css-1a2b3c") |
Once the accessibility skill has annotated a surface, switch its tests to getByRole with the accessible name. That makes the e2e suite double as an a11y regression check: a lost accessibilityLabel fails a test.
Pick a stable, fully mapped catalog entry for detail-route tests (/series/5114, Fullmetal Alchemist: Brotherhood). Do not assert on remote AniList or MangaDex copy: titles, descriptions, and cover URLs change upstream and would make the suite flaky.
What belongs here
| Layer | Test it with |
|---|---|
| Pure mapping maths, merge logic | Jest, via domain-tests |
| A screen renders and responds | Playwright |
| Deep link and SPA fallback | Playwright, asserting res.status() |
| Auth and progress sync round-trip | Playwright, against a throwaway account |
Do not re-test range arithmetic through the browser. Assert that Quick Lookup produces an answer; assert which answer in a Jest test.
Wiring into CI
system-check deliberately does not run e2e: it is the pre-commit and pre-push hook, and a chromium download plus a web build per commit is too slow. Add e2e as a separate CI job after the build step in .github/workflows/ci.yml, reusing the dist/ the build job already produced.
Common mistakes
| Mistake | Consequence |
|---|---|
Running bun run e2e without rebuilding |
Tests pass against the previous bundle. |
| Asserting on AniList titles or descriptions | Upstream edits break the suite for reasons unrelated to the app. |
Using waitForTimeout |
Flaky. Use expect(...).toBeVisible(), which retries. |
Adding e2e to system-check |
Every commit pays a full web build. Keep it a separate CI job. |
| Testing arithmetic through the UI | Slow and imprecise. That is what domain-tests is for. |