TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import { execSync } from "node:child_process";2import fs from "node:fs";3import type { Page } from "@playwright/test";45export const DB = process.env.E2E_DATABASE_URL ?? "postgres://localhost:5432/polyllm";6export const DEV_LOG = process.env.E2E_DEV_LOG ?? "/tmp/polyllm-dev.log";78export function sql(q: string): string {9 return execSync(`psql "${DB}" -Atc ${JSON.stringify(q)}`, { encoding: "utf8" }).trim();10}1112/** Finds the latest verification / reset URL for an email in the dev log (EMAIL_DRY_RUN_PRINT=1). */13export function lastLinkFromLog(pattern: RegExp): string | null {14 const log = fs.readFileSync(DEV_LOG, "utf8");15 const matches = [...log.matchAll(pattern)];16 return matches.length ? matches[matches.length - 1][0] : null;17}1819export function readEnv(name: string): string | undefined {20 if (process.env[name]) return process.env[name];21 const env = fs.existsSync(".env") ? fs.readFileSync(".env", "utf8") : "";22 const m = env.match(new RegExp(`^${name}=(.*)$`, "m"));23 return m ? m[1].replace(/^"|"$/g, "") : undefined;24}2526export const TEST_EMAIL = process.env.E2E_EMAIL ?? `e2e+${Date.now()}@polyllm.test`;27export const TEST_PASSWORD = "Str0ng-Passw0rd-e2e!";2829export async function login(page: Page, email: string, password: string) {30 await page.goto("/login");31 await page.getByLabel(/email/i).fill(email);32 await page.getByLabel(/^password$/i).fill(password);33 await page.getByRole("button", { name: /sign in/i }).click();34 await page.waitForURL(/\/app/);35}3637export async function noConsoleErrors(page: Page) {38 const errors: string[] = [];39 page.on("console", (msg) => {40 if (msg.type() === "error" && !/favicon|hydration|Download the React DevTools/i.test(msg.text())) errors.push(msg.text());41 });42 page.on("pageerror", (e) => errors.push(e.message));43 return errors;44}4546const STATE_FILE = "qa/.e2e-session.json";47/** Persist the signed-in cookies so later tests don't hit the sign-in rate limit (8/min). */48export async function saveSession(page: Page) {49 fs.mkdirSync("qa", { recursive: true });50 await page.context().storageState({ path: STATE_FILE });51}52export async function restoreSession(page: Page) {53 const state = JSON.parse(fs.readFileSync(STATE_FILE, "utf8")) as { cookies: Parameters<Page["context"]>[0] extends never ? never : import("@playwright/test").Cookie[] };54 await page.context().addCookies(state.cookies);55}56