import { execSync } from "node:child_process"; import fs from "node:fs"; import type { Page } from "@playwright/test"; export const DB = process.env.E2E_DATABASE_URL ?? "postgres://localhost:5432/polyllm"; export const DEV_LOG = process.env.E2E_DEV_LOG ?? "/tmp/polyllm-dev.log"; export function sql(q: string): string { return execSync(`psql "${DB}" -Atc ${JSON.stringify(q)}`, { encoding: "utf8" }).trim(); } /** Finds the latest verification / reset URL for an email in the dev log (EMAIL_DRY_RUN_PRINT=1). */ export function lastLinkFromLog(pattern: RegExp): string | null { const log = fs.readFileSync(DEV_LOG, "utf8"); const matches = [...log.matchAll(pattern)]; return matches.length ? matches[matches.length - 1][0] : null; } export function readEnv(name: string): string | undefined { if (process.env[name]) return process.env[name]; const env = fs.existsSync(".env") ? fs.readFileSync(".env", "utf8") : ""; const m = env.match(new RegExp(`^${name}=(.*)$`, "m")); return m ? m[1].replace(/^"|"$/g, "") : undefined; } export const TEST_EMAIL = process.env.E2E_EMAIL ?? `e2e+${Date.now()}@polyllm.test`; export const TEST_PASSWORD = "Str0ng-Passw0rd-e2e!"; export async function login(page: Page, email: string, password: string) { await page.goto("/login"); await page.getByLabel(/email/i).fill(email); await page.getByLabel(/^password$/i).fill(password); await page.getByRole("button", { name: /sign in/i }).click(); await page.waitForURL(/\/app/); } export async function noConsoleErrors(page: Page) { const errors: string[] = []; page.on("console", (msg) => { if (msg.type() === "error" && !/favicon|hydration|Download the React DevTools/i.test(msg.text())) errors.push(msg.text()); }); page.on("pageerror", (e) => errors.push(e.message)); return errors; } const STATE_FILE = "qa/.e2e-session.json"; /** Persist the signed-in cookies so later tests don't hit the sign-in rate limit (8/min). */ export async function saveSession(page: Page) { fs.mkdirSync("qa", { recursive: true }); await page.context().storageState({ path: STATE_FILE }); } export async function restoreSession(page: Page) { const state = JSON.parse(fs.readFileSync(STATE_FILE, "utf8")) as { cookies: Parameters[0] extends never ? never : import("@playwright/test").Cookie[] }; await page.context().addCookies(state.cookies); }