Files
crewli/apps/app/playwright.config.ts
bert.hausmans 2dfb1e8bae test(e2e): real-backend 409 conflict contract test (TEST-CONTRACT-001)
B4 of TEST-INFRA-001 (RFC-WS-FRONTEND-PRIMEVUE Amendment A-1).

- Add api/database/seeders/E2EBaselineSeeder.php — deterministic seed
  for Playwright e2e: e2e@test.local user (org_admin) on a fresh org +
  event + stage + StageDay + artist + engagement + performance
  (version=0). Writes seeded IDs to api/storage/app/e2e-fixtures.json
  so the Playwright fixture can construct API URLs without API
  discovery calls.
- Add apps/app/tests/playwright-e2e/global-setup.ts — runs
  `php artisan migrate:fresh --force --seed` against crewli_test (the
  existing PHPUnit MySQL test DB) before the test suite starts.
  Uses --env=testing to satisfy the dangerous-bash hook's migrate:fresh
  guard.
- Add apps/app/tests/playwright-e2e/utils/fixtures.ts — typed reader
  for e2e-fixtures.json. Cached after first read.
- Add apps/app/tests/playwright-e2e/utils/auth.ts — login helper that
  POSTs /api/v1/auth/login and returns user/org IDs. Uses Bearer-via-
  cookie flow (per api/.../SetAuthCookie.php), not stateful Sanctum.
- Add apps/app/tests/playwright-e2e/timetable/409-conflict.spec.ts —
  the contract test: first move with version=0 returns 200, second
  move with same stale version returns 409 with shape
  `errors.conflict: 'version_mismatch'`. Catches the schema-drift
  bug class that timetable-stabilization B5 surfaced.
- Update apps/app/playwright.config.ts — wire globalSetup, webServer
  for `php artisan serve --port=8001`, baseURL `http://localhost:8001`
  (NOT 127.0.0.1 — auth cookie's domain=localhost requires hostname
  match).
- Update .gitignore — runtime e2e-fixtures.json never committed.

DoD-19 met locally: `pnpm test:e2e` passes against a real Laravel
test server. CI integration deferred to TEST-INFRA-002 (per A-1
amendment).

Constraint: e2e tests share the crewli_test DB with PHPUnit. Running
both concurrently would collide. Documented in ARCH-TESTING.md (B5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:24:33 +02:00

70 lines
2.4 KiB
TypeScript

import { defineConfig, devices } from '@playwright/test'
// E2E config — drives a real Laravel test server. Used by `pnpm test:e2e`.
// Component tests live in playwright-ct.config.ts (different runner).
//
// Architecture (B4 / TEST-CONTRACT-001):
// - globalSetup runs `php artisan migrate:fresh --force --seed` against
// crewli_test (the existing PHPUnit MySQL test DB) using the
// E2EBaselineSeeder. Writes seeded IDs to api/storage/app/e2e-fixtures.json.
// - webServer auto-starts `php artisan serve --port=8001` against the
// same DB so the test can hit a live HTTP endpoint.
// - Tests use page.context().request to call /api/v1/* with cookie auth
// established via /api/v1/auth/login (Bearer-via-cookie, not stateful
// Sanctum SPA flow — see api/.../SetAuthCookie.php).
//
// SCOPE: contract tests only (request shape verification). UI-driven e2e
// tests would additionally need the Vite dev server (port 5174). Add that
// to webServer when first UI-driven e2e test lands.
//
// CI integration: deferred to TEST-INFRA-002. This config currently
// targets local-machine execution.
const E2E_API_PORT = Number(process.env.E2E_API_PORT ?? 8001)
// Use `localhost` (not 127.0.0.1) so the auth cookie set with
// `domain=localhost` (per api/.env's SESSION_DOMAIN) is matched on
// subsequent requests. Playwright's APIRequestContext respects
// cookie scope strictly.
const E2E_API_URL = `http://localhost:${E2E_API_PORT}`
export default defineConfig({
testDir: './tests/playwright-e2e',
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: 0,
workers: 1,
reporter: process.env.CI ? 'github' : 'list',
globalSetup: './tests/playwright-e2e/global-setup.ts',
use: {
baseURL: E2E_API_URL,
trace: 'off',
video: 'off',
screenshot: 'off',
viewport: { width: 1440, height: 900 },
extraHTTPHeaders: {
Accept: 'application/json',
},
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
// Auto-start the Laravel test server. globalSetup runs first
// (migrate:fresh + seed), then this command spawns artisan serve
// against the now-seeded crewli_test DB.
webServer: {
command: 'cd ../../api && DB_DATABASE=crewli_test php artisan --env=testing serve --port=8001',
url: `${E2E_API_URL}/up`,
reuseExistingServer: !process.env.CI,
timeout: 60_000,
stdout: 'ignore',
stderr: 'pipe',
},
})