import { chromium, request } from '@playwright/test'; import { promises as fs } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const API_BASE = process.env.E2E_API_BASE ?? 'http://127.0.0.1:18080'; const DASHBOARD_PORT = Number(process.env.PICLOUD_DASHBOARD_PORT ?? 5173); const DASHBOARD_ORIGIN = process.env.E2E_DASHBOARD_ORIGIN ?? `http://localhost:${DASHBOARD_PORT}`; const ADMIN_USERNAME = process.env.E2E_ADMIN_USERNAME ?? 'admin'; const ADMIN_PASSWORD = process.env.E2E_ADMIN_PASSWORD ?? 'admin'; const AUTH_DIR = path.join(__dirname, '.auth'); const ADMIN_STATE_PATH = path.join(AUTH_DIR, 'admin.json'); export default async function globalSetup(): Promise { await assertBackendUp(); await fs.mkdir(AUTH_DIR, { recursive: true }); const token = await loginAsAdmin(); await persistAdminStorageState(token); } async function assertBackendUp(): Promise { const probe = await request.newContext(); try { const res = await probe.get(`${API_BASE}/healthz`, { timeout: 5_000 }); if (!res.ok()) { throw new Error( `backend /healthz returned ${res.status()} — is \`cargo run -p picloud\` listening on ${API_BASE}?` ); } } catch (err) { throw new Error( `Could not reach backend at ${API_BASE}/healthz. ` + `Bring it up before running E2E tests:\n\n` + ` docker compose up -d postgres\n` + ` PICLOUD_BIND=127.0.0.1:18080 \\\n` + ` PICLOUD_ADMIN_USERNAME=${ADMIN_USERNAME} \\\n` + ` PICLOUD_ADMIN_PASSWORD=${ADMIN_PASSWORD} \\\n` + ` DATABASE_URL=postgres://picloud:picloud@127.0.0.1:15432/picloud \\\n` + ` cargo run -p picloud\n\n` + `Underlying error: ${(err as Error).message}` ); } finally { await probe.dispose(); } } async function loginAsAdmin(): Promise { const ctx = await request.newContext(); try { const res = await ctx.post(`${API_BASE}/api/v1/admin/auth/login`, { data: { username: ADMIN_USERNAME, password: ADMIN_PASSWORD }, headers: { 'content-type': 'application/json' } }); if (!res.ok()) { const body = await res.text(); throw new Error( `Admin login failed (${res.status()}): ${body}. ` + `Verify PICLOUD_ADMIN_USERNAME / PICLOUD_ADMIN_PASSWORD match the seeded bootstrap admin.` ); } const payload = (await res.json()) as { token?: string }; if (!payload.token) { throw new Error('Admin login response missing token field'); } return payload.token; } finally { await ctx.dispose(); } } // The dashboard reads its session from localStorage under the key // `picloud.admin.token` (see src/lib/auth.ts). We can't write to // localStorage without a browser context, so launch a throwaway one, // seed the value, then save storageState for every test to reuse. async function persistAdminStorageState(token: string): Promise { const browser = await chromium.launch(); try { const context = await browser.newContext(); const page = await context.newPage(); await page.goto(`${DASHBOARD_ORIGIN}/admin/login`); await page.evaluate( ([key, value]) => { localStorage.setItem(key, value); }, ['picloud.admin.token', token] ); await context.storageState({ path: ADMIN_STATE_PATH }); } finally { await browser.close(); } }