spb/satelliteindex
Public
TypeScript 66.5%
Python 30.9%
JavaScript 1.4%
CSS 0.7%
1/**2 * Production QA sweep: every key route at 390 and 1440 px — HTTP status, console errors, horizontal overflow, screenshot.3 * Run: node qa/screens.mjs [BASE_URL] (default http://localhost:8321)4 */5import { chromium } from '/Users/simon-pierreboucher/Desktop/uqo-eval/node_modules/playwright/index.mjs';6import { mkdirSync } from 'node:fs';78const BASE = process.argv[2] ?? 'http://localhost:8321';9const OUT = new URL('./screens/sweep/', import.meta.url).pathname;10mkdirSync(OUT, { recursive: true });1112const PAGES = ['/', '/explore', '/search?q=starlink', '/satellites', '/satellites?constellation=starlink&status=ACTIVE', '/satellite/iss-zarya-25544',13 '/satellite/sputnik-1-2', '/constellations', '/constellation/starlink', '/operators', '/operator/spacex', '/countries', '/country/canada',14 '/launches', '/launch/1998-067', '/launch-sites', '/debris', '/reentries', '/events', '/stats', '/rankings?metric=operators', '/sources',15 '/methodology', '/status', '/developers', '/about', '/privacy', '/terms', '/admin', '/does-not-exist'];16const WIDTHS = [390, 1440];17const browser = await chromium.launch();18let failures = 0;19for (const width of WIDTHS) {20 const mobile = width < 768;21 const ctx = await browser.newContext({ viewport: { width, height: mobile ? 844 : 900 }, deviceScaleFactor: 1, isMobile: mobile, hasTouch: mobile });22 const page = await ctx.newPage();23 for (const path of PAGES) {24 const errors = [];25 const onErr = (e) => errors.push(String(e));26 const onCon = (m) => { if (m.type() === 'error') errors.push(m.text()); };27 page.on('pageerror', onErr);28 page.on('console', onCon);29 const t0 = Date.now();30 const res = await page.goto(BASE + path, { waitUntil: 'networkidle', timeout: 60000 }).catch((e) => ({ status: () => `ERR ${e.message.slice(0, 40)}` }));31 await page.waitForTimeout(800);32 const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth).catch(() => -1);33 const expected = path === '/does-not-exist' ? 404 : path === '/admin' ? [200, 307] : 200;34 const status = res.status();35 const okStatus = Array.isArray(expected) ? expected.includes(status) : status === expected;36 const filtered = errors.filter((e) => !/WebGL|webgl|THREE\.WebGLRenderer|favicon/.test(e));37 const ok = okStatus && overflow <= 0 && filtered.length === 0;38 if (!ok) failures++;39 console.log(`${ok ? 'OK ' : 'FAIL'} ${width} ${status} ${String(Date.now() - t0).padStart(5)}ms overflow=${overflow} errors=${filtered.length} ${path}${filtered.length ? ' :: ' + filtered[0].slice(0, 120) : ''}`);40 await page.screenshot({ path: `${OUT}${width}-${path.replace(/[^a-z0-9]+/gi, '_').replace(/^_|_$/g, '') || 'home'}.png`, fullPage: false }).catch(() => undefined);41 page.off('pageerror', onErr);42 page.off('console', onCon);43 }44 await ctx.close();45}46await browser.close();47console.log(failures ? `\n${failures} failure(s)` : '\nall pages OK');48process.exit(failures ? 1 : 0);49