// Visual smoke test: load the extension, create a branching history, open the // viewer, and screenshot each mode. Outputs PNGs to /tmp/hg-shots. // // node scripts/viewer-shot.mjs (run after `npm run build`) import { chromium } from "playwright"; import { mkdtempSync, mkdirSync } from "node:fs"; import { tmpdir } from "node:os"; import { fileURLToPath } from "node:url"; import { dirname, resolve } from "node:path"; const DIST = resolve(dirname(fileURLToPath(import.meta.url)), "../dist"); const OUT = "/tmp/hg-shots"; mkdirSync(OUT, { recursive: true }); const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); const context = await chromium.launchPersistentContext(mkdtempSync(resolve(tmpdir(), "hg-")), { headless: false, args: [`--disable-extensions-except=${DIST}`, `--load-extension=${DIST}`], viewport: { width: 1100, height: 800 }, colorScheme: "dark", // preview the theme the user actually sees }); try { let [sw] = context.serviceWorkers(); if (!sw) sw = await context.waitForEvent("serviceworker", { timeout: 10_000 }); const extId = new URL(sw.url()).host; const page = await context.newPage(); await page.goto("https://developer.chrome.com/", { waitUntil: "load" }); await sleep(1200); // Collect two distinct in-page doc links to fork between. const hrefs = await page.evaluate(() => { const set = new Set(); for (const a of document.querySelectorAll('a[href*="/docs/"]')) { try { set.add(new URL(a.href).pathname); } catch {} if (set.size >= 2) break; } return [...set]; }); // Branch A: click first link, then go back. await page.evaluate((p) => document.querySelector(`a[href*="${p}"]`)?.click(), hrefs[0]); await page.waitForLoadState("load"); await sleep(1000); await page.goBack(); await page.waitForLoadState("load"); await sleep(800); // Branch B: click the second link from the same root → root is now a fork. await page.evaluate((p) => document.querySelector(`a[href*="${p}"]`)?.click(), hrefs[1]); await page.waitForLoadState("load"); await sleep(1200); const viewer = await context.newPage(); await viewer.goto(`chrome-extension://${extId}/viewer.html`, { waitUntil: "load" }); await viewer.waitForSelector(".graph, .empty", { timeout: 5000 }); await sleep(600); await viewer.screenshot({ path: `${OUT}/1-graph.png` }); // Switch to Tree, then List. await viewer.getByRole("tab", { name: "Tree" }).click(); await sleep(400); await viewer.screenshot({ path: `${OUT}/2-tree.png` }); await viewer.getByRole("tab", { name: "List" }).click(); await sleep(400); await viewer.screenshot({ path: `${OUT}/3-list.png` }); // Back to graph, collapse the first fork station we find. await viewer.getByRole("tab", { name: "Git graph" }).click(); await sleep(400); const fork = viewer.locator(".station--fork").first(); if (await fork.count()) { await fork.click(); await sleep(400); await viewer.screenshot({ path: `${OUT}/4-collapsed.png` }); } console.log(`extension id: ${extId}`); console.log(`forked between: ${hrefs.join(" , ")}`); console.log(`screenshots in ${OUT}`); } finally { await context.close(); }