// Viewport screenshot helper: node apps/web/qa/shot.mjs [--w=1280] [--h=900] [--dark] [--scroll=#id] [--click=selector] [--wait=ms] [--full] // Writes qa/shots/-.png. Playwright from ~/Desktop/uqo-eval. import { createRequire } from "node:module"; import { mkdirSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const require = createRequire("/Users/simon-pierreboucher/Desktop/uqo-eval/package.json"); const { chromium } = require("playwright"); const here = dirname(fileURLToPath(import.meta.url)); const OUT = resolve(here, "shots"); mkdirSync(OUT, { recursive: true }); const BASE = process.env.BASE ?? "http://localhost:8314"; const [path, name, ...flags] = process.argv.slice(2); const opt = Object.fromEntries(flags.map((f) => { const m = /^--([^=]+)=?(.*)$/.exec(f); return [m[1], m[2] === "" ? true : m[2]]; })); const w = Number(opt.w ?? 1280); const h = Number(opt.h ?? (w < 700 ? 844 : 900)); const mobile = w < 700; const browser = await chromium.launch(); const ctx = await browser.newContext({ viewport: { width: w, height: h }, deviceScaleFactor: 1, isMobile: mobile, hasTouch: mobile, colorScheme: opt.dark ? "dark" : "light", locale: "en-CA" }); await ctx.addInitScript((theme) => { try { window.localStorage.setItem("theme", theme); } catch {} }, opt.dark ? "dark" : "light"); const page = await ctx.newPage(); const errors = []; page.on("pageerror", (e) => errors.push(String(e).slice(0, 200))); page.on("console", (m) => { if (m.type() === "error") errors.push(m.text().slice(0, 200)); }); await page.goto(`${BASE}${path}`, { waitUntil: "load", timeout: 90000 }); await page.waitForLoadState("networkidle", { timeout: 15000 }).catch(() => {}); await page.waitForTimeout(Number(opt.wait ?? 800)); if (opt.scroll) { await page.evaluate((sel) => document.querySelector(sel)?.scrollIntoView({ block: "start" }), opt.scroll); await page.waitForTimeout(400); } if (opt.click) { const clicks = String(opt.click).split("||"); for (const c of clicks) { await page.locator(c).first().click({ timeout: 5000 }).catch((e) => errors.push(`click failed ${c}: ${String(e).slice(0, 80)}`)); await page.waitForTimeout(500); } } if (opt.key) { await page.keyboard.press(String(opt.key)); await page.waitForTimeout(300); } const file = resolve(OUT, `${name}-${w}${opt.dark ? "-dark" : ""}.png`); await page.screenshot({ path: file, fullPage: !!opt.full }); const overflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth ? `${document.documentElement.scrollWidth}>${document.documentElement.clientWidth}` : null); console.log(file, overflow ? `OVERFLOW ${overflow}` : "no-overflow", errors.length ? `errors: ${errors.join(" | ")}` : ""); await browser.close();