import { expect, type Page } from "@playwright/test"; /** Dev-system credentials — these exist in the planarchy.dev seed data */ export const DEV_USERS = { admin: { email: "admin@planarchy.dev", password: "admin123" }, manager: { email: "manager@planarchy.dev", password: "manager123" }, viewer: { email: "viewer@planarchy.dev", password: "viewer123" }, } as const; export async function signIn(page: Page, email: string, password: string) { await page.goto("/auth/signin"); await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', password); await page.click('button[type="submit"]'); await expect(page).toHaveURL(/\/(dashboard|resources)/, { timeout: 15000 }); } export async function signOut(page: Page) { // next-auth/react signOut() POSTs to /auth/signout with a CSRF token. // There is no GET-accessible signout page in this app (/auth/signout returns 404). // Replicate what the client-side signOut() function does: // 1. Fetch the CSRF token from /auth/csrf // 2. POST to /auth/signout with that token // 3. Follow the redirect to /auth/signin await page.goto("/dashboard"); // land on any authenticated page for cookie context await page.evaluate(async () => { const csrfRes = await fetch("/api/auth/csrf"); const { csrfToken } = await csrfRes.json() as { csrfToken: string }; await fetch("/api/auth/signout", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ csrfToken, callbackUrl: "/auth/signin", json: "true" }), redirect: "follow", }); }); // After the POST clears the session cookie, navigating to a protected route // should redirect to sign-in. await page.goto("/dashboard"); await page.waitForURL(/\/auth\/signin/, { timeout: 10000 }); } /** * Intercept all tRPC batch responses and assert none return HTTP 401. * Returns a list of intercepted tRPC paths that were called. */ export async function assertNoTrpc401s(page: Page, action: () => Promise) { const failures: string[] = []; page.on("response", (response) => { if (response.url().includes("/api/trpc/") && response.status() === 401) { const url = new URL(response.url()); failures.push(url.pathname + url.search.slice(0, 80)); } }); await action(); if (failures.length > 0) { throw new Error( `tRPC 401 responses detected (session registry / auth broken):\n${failures.join("\n")}`, ); } }