Vencura
Testing

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

CommandDescription
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:e2e

Defaults: Next NEXT_PUBLIC_APP_URL or http://localhost:3000; API NEXT_PUBLIC_API_URL or http://localhost:3001.

Local Development

  1. Full suite (root): pnpm test:e2e — runs Fastify E2E then Next E2E (both spawn servers, poll, run, cleanup).
  2. Next only: pnpm --filter @repo/web test:e2e:local — builds, spawns Fastify + Next, runs Next E2E, cleanup.
  3. Fastify only: pnpm --filter @repo/api test:e2e:local — spawns API, runs Scalar login E2E, cleanup.
  4. Manual (two terminals): Build with pnpm --filter @repo/web build:e2e, run pnpm --filter @repo/web start:e2e:servers in one terminal and pnpm --filter @repo/web test:e2e in another.
  5. External URLs: Use --app and --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:local and start:ci set ALLOW_TEST=true.
  • Vercel previews: Set ALLOW_TEST=true for the Preview environment in project env vars.

CI

Test workflows run on pull requests (path-filtered):

  • API E2E (api-e2e.yml) — Runs when apps/api or its deps change. Spawns Fastify locally, runs Playwright.
  • Web E2E (web-e2e.yml) — Runs when apps/web or its deps change. Spawns Fastify + Next locally, runs Playwright.
  • Packages (packages-test.yml) — Runs when packages or tools change. 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.yml

An 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:

  1. Protection Bypass for Automation: In each project (Next, Fastify): Settings → Deployment Protection → Protection Bypass for Automation → enable → generate secret.
  2. Use the same bypass secret for both projects.
  3. Add VERCEL_AUTOMATION_BYPASS_SECRET to GitHub secrets.
  4. Playwright adds x-vercel-protection-bypass and x-vercel-set-bypass-cookie headers automatically when the env var is set.
  5. OPTIONS Allowlist (for CORS): In Fastify project, Deployment Protection → OPTIONS Allowlist → add / or /auth so CORS preflight succeeds.

See Vercel Protection Bypass for Automation.

Environment Variables

  • Chat E2E (chat-assistant.spec.ts): Uses Anthropic Sonnet (ANTHROPIC_API_KEY). CI and test:e2e:local force AI_PROVIDER=anthropic. Uses authenticatedPage fixture.
  • E2E CI: Uses local servers only; no Vercel URLs. For manual testing against previews, pass --app/--api URLs.

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_TEST is true in production

Next E2E Specs

SpecCoverage
magic-link-auth.spec.tsMagic link login, invalid/expired token errors, email validation, protected route, JWT session
chat-assistant.spec.tsChat UI with authenticatedPage; Who am I? prompt
security/api-keys.spec.tsAPI keys CRUD: create, revoke, empty state
security/authenticator.spec.tsTOTP setup/unlink via extractSessionToken + test endpoint
security/passkeys.spec.tsPasskeys add/remove with CDP virtual authenticator

Project order

Troubleshooting

  • Port in use: scripts/run-e2e.mjs kills processes on 3000/3001 before E2E. If ports remain in use, run bash scripts/kill-test-servers.sh manually.
  • Tests fail with unreachable URLs: Ensure both servers are running, or pass correct --app / --api URLs.
  • Token extraction fails: Verify ALLOW_TEST=true and email is test@test.ai.
  • Vercel CORS errors: Add / or /auth to OPTIONS Allowlist in Fastify Deployment Protection.
  • Protection bypass not working: Ensure VERCEL_AUTOMATION_BYPASS_SECRET matches the secret in both Vercel projects.

On this page