Files
punimtag/e2e
ilia ccb961d87a test: playkit v0.3.1 network monitors, authed filters, admin-frontend Vitest
Bump @levkin/playkit to v0.3.1 (network interception helpers) and land the
work it unblocked: startNetworkErrorMonitor on gallery/search/upload/manage-
users, Favorites + People filter UI e2e (storageState), and a fix for the
lingering `res.data: unknown` / Mailpit-vs-Mailtrap type errors in the mail
and catalog specs. Also adds Vitest coverage + a CI job for admin-frontend,
which had no test infra before this.
2026-07-14 22:01:27 -04:00
..

PunimTag e2e (Playwright + @levkin/playkit)

Smoke tests against the public DEV URL so we catch LAN-redirect bugs (e.g. NEXTAUTH_URL=http://10.0.10.121:3001 → Kolby #57).

Quick start

cd e2e
cp .env.example .env   # edit credentials
npm ci
npx playwright install chromium
npm test

Private Gitea installs need auth once: set a local git insteadOf with a token before npm ci, then unset it. CI does this in .gitea/workflows/ci.yml. Never commit lockfile URLs that embed tokens.

Environment

Variable Required Purpose
PLAYKIT_BASE_URL yes (default in env-defaults.json) Public viewer host
PLAYKIT_API_BASE_URL no LAN API (see env-defaults.json)
E2E_ADMIN_EMAIL for auth specs Prefer e2e@levkine.canot admin@admin.com
E2E_ADMIN_PASSWORD for auth specs Dedicated e2e password (Vaultwarden / Infisical)
E2E_API_USERNAME / E2E_API_PASSWORD optional FastAPI bearer login, admin role (separate DB from NextAuth; mirrors e2e@levkine.ca)
E2E_API_VIEWER_USERNAME / E2E_API_VIEWER_PASSWORD optional FastAPI bearer login, viewer role — role-permission gate specs only
E2E_VIEWER_EMAIL / E2E_VIEWER_PASSWORD optional NextAuth auth-DB viewer, hasWriteAccess=false (third, independent store) — viewer.write-gates.spec.ts only
PLAYKIT_MAIL_PROVIDER for mail specs mailpit (homelab)
MAILPIT_BASE_URL for mail specs http://10.0.10.45:8025
MAILPIT_USER / MAILPIT_PASSWORD for mail specs Mailpit basic auth

Secrets: Infisical LevkinOpsdev/playkit/punimtag + Gitea Actions. See ansible docs/hardening/SECRETS.md.

Playkit pin: @levkin/playkit@v0.3.1 (git tag). Zod schema option, storageState helpers, playkitFailureArtifacts, Mailpit, and network interception (interceptNetworkCall, startNetworkErrorMonitor — see playkit docs/NETWORK.md) are all in this pin — see network-errors.spec.ts for the silent-4xx/5xx monitors on gallery/search/upload/manage-users. Timing → Pushgateway is supported by the kit but not enabled in this CI job yet.

What we assert

  1. Login page loads on the public hostname
  2. Sign-out stays on that hostname (never 10.x)
  3. FastAPI /health{ "status": "ok" }
  4. Forgot-password / reset-password email in Mailpit; links use public host
  5. Register → unverified block → verify email via Mailpit → login
  6. Idle logout (?e2e_idle_ms=) stays on public host
  7. Upload: submit a tiny fixture via #file-upload (uses storageState)
  8. Manage Users open/close then sign-out (Kolby #57 overlay path)
  9. API /api/v1/auth/me and /api/v1/photos return 401 without token
  10. API catalog: people/tags lists, login 422/401, users/roles 401, missing photo 404|401
  11. Viewer /api/auth/session returns email when storageState is loaded
  12. FastAPI role-permission write gates: viewer 403 vs admin 200 on users, role-permissions, bulk-delete
  13. Public gallery search (/api/search): tag filter, person filter, and combined-filter narrowing return correct subsets; UI tag-filter interaction updates URL + result count
  14. Logged-in-only filters: Favorites checkbox toggles favoritesOnly URL param; People filter UI selection updates URL + result count (uses storageState)
  15. Silent-failure network monitor (startNetworkErrorMonitor): gallery home, search+filter, upload, and Manage Users overlay all stay free of background 4xx/5xx while the UI loads/interacts
  16. interceptNetworkCall spies on the real upload POST (status + { message, photos } shape) and the filtered /api/search?tags= GET (status + Zod-validated shape) instead of brittle waitForResponse/text scraping
  17. Zod-validated API responses: FastAPI login TokenResponse + /auth/me UserResponse (api.fastapi-login.spec.ts), gallery search SearchResponse (gallery.search-filters.spec.ts)
  18. NextAuth (browser-session) write gates: viewer (hasWriteAccess=false) gets 403, admin gets past the gate, on POST /api/faces/{id}/identify (viewer.write-gates.spec.ts) — distinct from the FastAPI role-permission gates in #12
  19. PROD smoke (prod.smoke.spec.ts, opt-in via PROD_BASE_URL): /api/health + login page load on the public PROD host — dormant until the PROD LXC exists (see ROADMAP)
  20. Manage Users real CRUD + causal cross-session effect (admin.manage-users-actions.spec.ts): admin creates/edits/deletes a user through the actual panel (not just open/close), and deactivating a user via the UI immediately revokes that user's already open NextAuth session (jwt callback re-checks isActive, Kolby #57 fix) — every run creates a disposable e2e-manage-test-* account and deletes it in a finally, never touching the shared punimtagdev/MirrorMatch DB's real accounts

See repo root ROADMAP.md for gaps and next steps.

Defaults for base URLs live in env-defaults.json (imported by env-defaults.ts, fixtures.ts, playwright.config.ts, and the Gitea e2e job).