import { chromium, type FullConfig } from "@playwright/test"; import { PrismaClient } from "@prisma/client"; import * as fs from "node:fs"; import * as path from "node:path"; import { seedUi } from "../apps/edr-passenger-api/test/fixtures/seed-ui"; import { seedPassengerSession } from "../apps/edr-passenger-api/test/fixtures/seed-passenger-session"; /** * Playwright global-setup for the UI E2E suite. * 1. Seeds the 5544 test DB with the bookable trip + payment methods + promos (seed-ui.ts). * 2. Mints a passenger IAM session + token → passenger.json storageState (localStorage). * 3. Logs in as the seeded backoffice admin via the REAL /login UI → staff.json storageState. * * Assumes the stack is already running (api :4000, portal :5174, backoffice :5184). */ const STORAGE_DIR = path.join(__dirname, "fixtures", "storage"); const API = process.env.API_URL ?? "http://localhost:4000"; const PORTAL = process.env.PORTAL_URL ?? "http://localhost:5174"; const BACKOFFICE = process.env.BACKOFFICE_URL ?? "http://localhost:5184"; const DB_URL = process.env.DATABASE_URL ?? "postgresql://edr:edr_secret@localhost:5544/edr_database?schema=passenger"; const STAFF = { email: "passenger.admin@edr.local", password: process.env.DEFAULT_PASSWORD ?? "Test@1234" }; export default async function globalSetup(_config: FullConfig) { fs.mkdirSync(STORAGE_DIR, { recursive: true }); process.env.DATABASE_URL = DB_URL; const prisma = new PrismaClient(); try { console.log("[global-setup] seeding test DB…"); await seedUi(prisma); console.log("[global-setup] minting passenger session…"); const { token } = await seedPassengerSession(prisma); const profileRes = await fetch(`${API}/auth/profile`, { headers: { Authorization: `Bearer ${token}` }, }); if (!profileRes.ok) throw new Error(`/auth/profile failed: HTTP ${profileRes.status}`); const profile = (await profileRes.json())?.data ?? {}; const passengerState = { cookies: [], origins: [ { origin: PORTAL, localStorage: [ { name: "auth_token", value: token }, { name: "auth_user", value: JSON.stringify(profile) }, ], }, ], }; fs.writeFileSync(path.join(STORAGE_DIR, "passenger.json"), JSON.stringify(passengerState)); console.log("[global-setup] passenger.json written"); } finally { await prisma.$disconnect(); } console.log("[global-setup] minting staff storageState via real login…"); const browser = await chromium.launch(); const ctx = await browser.newContext(); const page = await ctx.newPage(); await page.goto(`${BACKOFFICE}/login`, { waitUntil: "domcontentloaded" }); await page.locator('input[type="email"]').fill(STAFF.email); await page.locator('input[type="password"]').fill(STAFF.password); await Promise.all([ page.waitForURL((url) => !url.pathname.startsWith("/login"), { timeout: 30_000 }), page.locator('button[type="submit"]').click(), ]); await ctx.storageState({ path: path.join(STORAGE_DIR, "staff.json") }); console.log("[global-setup] staff.json written"); await browser.close(); }