SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
3 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
2.8 KB · 47 lines javascript
Raw Blame History
1// Viewport screenshot helper: node apps/web/qa/shot.mjs <path> <name> [--w=1280] [--h=900] [--dark] [--scroll=#id] [--click=selector] [--wait=ms] [--full]2// Writes qa/shots/<name>-<w>.png. Playwright from ~/Desktop/uqo-eval.3import { createRequire } from "node:module";4import { mkdirSync } from "node:fs";5import { dirname, resolve } from "node:path";6import { fileURLToPath } from "node:url";78const require = createRequire("/Users/simon-pierreboucher/Desktop/uqo-eval/package.json");9const { chromium } = require("playwright");10const here = dirname(fileURLToPath(import.meta.url));11const OUT = resolve(here, "shots");12mkdirSync(OUT, { recursive: true });13const BASE = process.env.BASE ?? "http://localhost:8314";1415const [path, name, ...flags] = process.argv.slice(2);16const opt = Object.fromEntries(flags.map((f) => { const m = /^--([^=]+)=?(.*)$/.exec(f); return [m[1], m[2] === "" ? true : m[2]]; }));17const w = Number(opt.w ?? 1280);18const h = Number(opt.h ?? (w < 700 ? 844 : 900));19const mobile = w < 700;20const browser = await chromium.launch();21const ctx = await browser.newContext({ viewport: { width: w, height: h }, deviceScaleFactor: 1, isMobile: mobile, hasTouch: mobile, colorScheme: opt.dark ? "dark" : "light", locale: "en-CA" });22await ctx.addInitScript((theme) => { try { window.localStorage.setItem("theme", theme); } catch {} }, opt.dark ? "dark" : "light");23const page = await ctx.newPage();24const errors = [];25page.on("pageerror", (e) => errors.push(String(e).slice(0, 200)));26page.on("console", (m) => { if (m.type() === "error") errors.push(m.text().slice(0, 200)); });27await page.goto(`${BASE}${path}`, { waitUntil: "load", timeout: 90000 });28await page.waitForLoadState("networkidle", { timeout: 15000 }).catch(() => {});29await page.waitForTimeout(Number(opt.wait ?? 800));30if (opt.scroll) {31  await page.evaluate((sel) => document.querySelector(sel)?.scrollIntoView({ block: "start" }), opt.scroll);32  await page.waitForTimeout(400);33}34if (opt.click) {35  const clicks = String(opt.click).split("||");36  for (const c of clicks) {37    await page.locator(c).first().click({ timeout: 5000 }).catch((e) => errors.push(`click failed ${c}: ${String(e).slice(0, 80)}`));38    await page.waitForTimeout(500);39  }40}41if (opt.key) { await page.keyboard.press(String(opt.key)); await page.waitForTimeout(300); }42const file = resolve(OUT, `${name}-${w}${opt.dark ? "-dark" : ""}.png`);43await page.screenshot({ path: file, fullPage: !!opt.full });44const overflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth ? `${document.documentElement.scrollWidth}>${document.documentElement.clientWidth}` : null);45console.log(file, overflow ? `OVERFLOW ${overflow}` : "no-overflow", errors.length ? `errors: ${errors.join(" | ")}` : "");46await browser.close();47