import { defineConfig, devices } from "@playwright/test"; /** * End-to-end customer journeys — real browser, real dev server, real * MySQL. Needs DATABASE_HOST/DATABASE_NAME/DATABASE_USER/DATABASE_PASSWORD * pointed at a throwaway database before running (same "migrate, seed, * test, tear down" pattern as `npm run test:integration` — see * docs/phase-3-summary.md and docs/phase-4-summary.md). `globalSetup` * applies migrations and seed data automatically so a single * `npm run test:e2e` is enough once those are set. */ const PORT = 3100; const baseURL = `http://localhost:${PORT}`; export default defineConfig({ testDir: "./e2e", globalSetup: "./e2e/global-setup.ts", fullyParallel: false, workers: 1, retries: 0, timeout: 45_000, expect: { timeout: 10_000 }, reporter: "list", use: { baseURL, trace: "retain-on-failure", screenshot: "only-on-failure", }, projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }], webServer: { command: `npm run dev -- --port ${PORT}`, url: baseURL, reuseExistingServer: false, timeout: 60_000, env: { ...process.env, // Any fixed value is fine — see src/lib/booking-draft/sign.ts. Only // needs to be consistent for the lifetime of this one server process. AUTH_SECRET: process.env.AUTH_SECRET ?? "playwright-e2e-test-secret-do-not-use-in-production", NEXT_PUBLIC_APP_URL: baseURL, // Unlocks GET /api/test/otp-code so helpers.ts's signIn() can read a // just-sent OTP code the way a human reads their inbox — see that // route's own header. Never set outside this one dev-mode webServer. E2E_TEST_MODE: "true", }, }, });