SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
2.9 KB · 46 lines javascript
Raw Blame History
1/**2 * QA sweep: key routes at 390 and 1440 px, dark and light — HTTP status, console errors, horizontal overflow, screenshot.3 * Run: node qa/screens.mjs [BASE_URL]   (default http://localhost:8390)4 * Playwright is resolved from the uqo-eval project on this machine (see import below); adjust if needed.5 */6import { chromium } from "/Users/simon-pierreboucher/Desktop/uqo-eval/node_modules/playwright/index.mjs";7import { mkdirSync } from "node:fs";89const BASE = process.argv[2] ?? "http://localhost:8390";10const OUT = new URL("./screens/", import.meta.url).pathname;11mkdirSync(OUT, { recursive: true });1213const PAGES = ["/", "/live", "/markets", "/crypto", "/stocks", "/indices", "/forex", "/rates", "/commodities", "/instruments/crypto_btc_usd", "/instruments/AAPL", "/instruments/US10Y", "/exchanges", "/exchanges/xnas", "/countries", "/countries/CA", "/events", "/halts", "/filings", "/sources", "/coverage", "/coverage?tier=A", "/connectors", "/data-health", "/search?q=bitcoin", "/compare?ids=crypto_btc_usd,crypto_eth_usd", "/status", "/methodology", "/developers", "/licensing", "/admin", "/does-not-exist"];14const WIDTHS = [390, 1440];15const THEMES = ["dark", "light"];1617const browser = await chromium.launch();18let failures = 0;19for (const theme of THEMES) {20  for (const width of WIDTHS) {21    const ctx = await browser.newContext({ viewport: { width, height: width < 600 ? 844 : 900 }, deviceScaleFactor: 1 });22    await ctx.addInitScript((t) => localStorage.setItem("ma-theme", t), theme);23    for (const path of PAGES) {24      const page = await ctx.newPage();25      const errors = [];26      page.on("console", (m) => m.type() === "error" && errors.push(m.text()));27      page.on("pageerror", (e) => errors.push(`pageerror: ${e.message}`));28      const res = await page.goto(BASE + path, { waitUntil: "networkidle", timeout: 60_000 }).catch((e) => ({ status: () => `ERR ${e.message}` }));29      await page.waitForTimeout(1200);30      const overflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth + 1);31      const status = res.status();32      const expected = path === "/does-not-exist" ? 404 : 200;33      const errs = errors.filter((e) => !/favicon|404 \(Not Found\)|hydrat/i.test(e) || /Hydration failed|did not match/.test(e));34      const ok = status === expected && !overflow && errs.length === 0;35      if (!ok) failures++;36      console.log(`${ok ? "OK  " : "FAIL"} ${theme.padEnd(5)} ${String(width).padEnd(4)} ${String(status).padEnd(4)} ${overflow ? "OVERFLOW " : ""}${path}${errs.length ? `\n      ${errs.slice(0, 3).join("\n      ")}` : ""}`);37      await page.screenshot({ path: `${OUT}${theme}-${width}-${path.replace(/[^a-z0-9]+/gi, "_").replace(/^_|_$/g, "") || "home"}.png`, fullPage: width >= 600 });38      await page.close();39    }40    await ctx.close();41  }42}43await browser.close();44console.log(failures ? `\n${failures} failing checks` : "\nall checks passed");45process.exit(failures ? 1 : 0);46