E2E Testing
Playwright E2E tests for Next.js app and Fastify API (Scalar login).
End-to-end tests run full user flows using Playwright. Two suites: Web E2E (apps/web) tests the web app + auth; Fastify E2E (apps/api) tests Scalar UI login. Both use test@test.ai for magic-link when ALLOW_TEST=true.
Root QA: pnpm qa runs the full pipeline (install → checktypes → lint → build → test) and ends with pnpm test:e2e, which runs Fastify E2E then Next E2E via scripts/run-e2e.mjs (both use test:e2e:local to spawn servers). The E2E script kills any processes on ports 3000 and 3001 before starting (unless SKIP_KILL_PORTS=1).
Commands
| Command | Description |
|---|---|
pnpm test:e2e (root) | Run Fastify API E2E, then Next E2E (spawns local servers) |
pnpm test:e2e (in apps/web) | Run E2E; expects URLs via env or --app/--api params |
pnpm test:e2e:local (in apps/web) | Build (unless SKIP_BUILD=1), spawn Fastify + Next, poll until healthy, run tests, cleanup |
pnpm test:e2e (in apps/api) | Run E2E; expects API URL via env or --api param |
pnpm test:e2e:local (in apps/api) | Spawn API, poll until healthy, run tests, cleanup |
pnpm test:e2e:ui (in apps/web or apps/api) | Run with Playwright UI |
pnpm test:e2e:debug (in apps/web or apps/api) | Run in debug mode |
URL Configuration
test:e2e accepts URL params. Next: --app and --api. Fastify: --api only. Params override environment variables.
# Next (both app and API)
pnpm test:e2e --app=https://my-app.vercel.app --api=https://my-api.vercel.app
pnpm test:e2e -- --app https://localhost:3000 --api https://localhost:3001
# Fastify (API only)
pnpm test:e2e --api=https://my-api.vercel.app
pnpm test:e2e -- --api https://localhost:3001
# Environment (defaults when no params)
PLAYWRIGHT_APP_URL=https://... PLAYWRIGHT_API_URL=https://... pnpm test:e2eDefaults: Next NEXT_PUBLIC_APP_URL or http://localhost:3000; API NEXT_PUBLIC_API_URL or http://localhost:3001.
Local Development
- Full suite (root):
pnpm test:e2e— runs Fastify E2E then Next E2E (both spawn servers, poll, run, cleanup). - Next only:
pnpm --filter @repo/web test:e2e:local— builds, spawns Fastify + Next, runs Next E2E, cleanup. - Fastify only:
pnpm --filter @repo/api test:e2e:local— spawns API, runs Scalar login E2E, cleanup. - Manual (two terminals): Build with
pnpm --filter @repo/web build:e2e, runpnpm --filter @repo/web start:e2e:serversin one terminal andpnpm --filter @repo/web test:e2ein another. - External URLs: Use
--appand--api(Next) or--api(Fastify) to target already-running servers or Vercel previews.
Test Email (test@test.ai)
Magic-link E2E tests use test@test.ai when ALLOW_TEST=true. The token is stored in the database (verification.token_plain) and read from /test/magic-link/last. No fake outbox; works with Vercel serverless (shared DB across instances).
- Local:
test:e2e:localandstart:cisetALLOW_TEST=true. - Vercel previews: Set
ALLOW_TEST=truefor the Preview environment in project env vars.
CI
Test workflows run on pull requests (path-filtered):
- API E2E (
api-e2e.yml) — Runs whenapps/apior its deps change. Spawns Fastify locally, runs Playwright. - Web E2E (
web-e2e.yml) — Runs whenapps/webor its deps change. Spawns Fastify + Next locally, runs Playwright. - Packages (
packages-test.yml) — Runs whenpackagesortoolschange. Unit tests only; excludes app E2E.
Lint and security run on every PR. See GitHub Actions.
Mobile E2E (Maestro)
The Expo app uses Maestro for E2E flows. Flow at apps/mobile/.maestro/flows/home.yml: launch app, assert home screen content.
Run locally (app must be installed on emulator/simulator):
cd apps/mobile && maestro test .maestro/flows/home.ymlAn optional mobile-e2e workflow (EAS Workflows + Maestro) can be added to run in CI; v1 defers this. See Mobile CI/CD.
Vercel Deployment Protection (Manual Testing)
To run E2E manually against Vercel preview deployments with Deployment Protection enabled:
When Deployment Protection is enabled:
- Protection Bypass for Automation: In each project (Next, Fastify): Settings → Deployment Protection → Protection Bypass for Automation → enable → generate secret.
- Use the same bypass secret for both projects.
- Add
VERCEL_AUTOMATION_BYPASS_SECRETto GitHub secrets. - Playwright adds
x-vercel-protection-bypassandx-vercel-set-bypass-cookieheaders automatically when the env var is set. - OPTIONS Allowlist (for CORS): In Fastify project, Deployment Protection → OPTIONS Allowlist → add
/or/authso CORS preflight succeeds.
See Vercel Protection Bypass for Automation.
Environment Variables
- Chat E2E (chat-assistant.spec.ts): Uses Anthropic Sonnet (
ANTHROPIC_API_KEY). CI andtest:e2e:localforceAI_PROVIDER=anthropic. UsesauthenticatedPagefixture. - E2E CI: Uses local servers only; no Vercel URLs. For manual testing against previews, pass
--app/--apiURLs.
ALLOW_TEST
ALLOW_TEST=true enables:
- Fake email for
@test.ai(no Resend) - DB-backed token storage for
/test/magic-link/last - Production guard: server exits if
ALLOW_TESTis true in production
Next E2E Specs
| Spec | Coverage |
|---|---|
magic-link-auth.spec.ts | Magic link login, invalid/expired token errors, email validation, protected route, JWT session |
chat-assistant.spec.ts | Chat UI with authenticatedPage; Who am I? prompt |
security/api-keys.spec.ts | API keys CRUD: create, revoke, empty state |
security/authenticator.spec.ts | TOTP setup/unlink via extractSessionToken + test endpoint |
security/passkeys.spec.ts | Passkeys add/remove with CDP virtual authenticator |
Project order
Troubleshooting
- Port in use:
scripts/run-e2e.mjskills processes on 3000/3001 before E2E. If ports remain in use, runbash scripts/kill-test-servers.shmanually. - Tests fail with unreachable URLs: Ensure both servers are running, or pass correct
--app/--apiURLs. - Token extraction fails: Verify
ALLOW_TEST=trueand email istest@test.ai. - Vercel CORS errors: Add
/or/authto OPTIONS Allowlist in Fastify Deployment Protection. - Protection bypass not working: Ensure
VERCEL_AUTOMATION_BYPASS_SECRETmatches the secret in both Vercel projects.
Related
- Frontend Testing - E2E-only frontend testing strategy
- GitHub Actions - CI workflow
- Vercel Deployment - Preview deployment and env vars