// Screenshots of the shell chrome preview harness (`/?shell`, see src/shell/preview/shellHarness.tsx) // against a running `vite dev`. Usage: node scripts/shell-shots.mjs [baseUrl] [outDir] import { chromium } from 'playwright'; import { mkdirSync } from 'node:fs'; import { join } from 'node:path'; const base = process.argv[2] ?? 'http://127.0.0.1:1420'; const out = process.argv[3] ?? join(import.meta.dirname, '..', '..', '..', 'verification', 'shell-polish'); mkdirSync(out, { recursive: true }); const WIDE = { width: 1600, height: 900 }; const NARROW = { width: 860, height: 640 }; const shots = [ ['wide-tabs', WIDE, 'tabs=7&loading'], ['narrow-tabs', NARROW, 'tabs=7&loading'], ['wide-many-tabs', WIDE, 'tabs=24&pinned=3'], ['narrow-many-tabs', NARROW, 'tabs=24&pinned=3'], ['wide-split', WIDE, 'tabs=5&split'], ['wide-update-chip', WIDE, 'tabs=4&update=ready'], ['wide-newtab', WIDE, 'tabs=4&open=newtab'], ['narrow-newtab', NARROW, 'tabs=4&open=newtab'], ['wide-empty', WIDE, 'open=empty'], ['wide-palette', WIDE, 'tabs=5&open=palette'], ['wide-palette-query', WIDE, 'tabs=5&open=palette&q=from:'], ['narrow-palette', NARROW, 'tabs=5&open=palette'], ['wide-accounts', WIDE, 'tabs=5&profiles=4&open=accounts'], ['narrow-accounts', NARROW, 'tabs=5&profiles=4&open=accounts'], ['wide-context-menu', WIDE, 'tabs=6&open=menu'], ['wide-drafts', WIDE, 'tabs=4&open=drafts'], ['wide-media', WIDE, 'tabs=4&open=media'], ['wide-single-account', WIDE, 'tabs=5&profiles=1'], ['narrow-overflow-list', NARROW, 'tabs=24&pinned=3', async page => { await page.click('.dv-tabs-overflow-dropdown-default'); }], ['wide-hover-states', WIDE, 'tabs=7', async page => { await page.hover('.dv-tab:nth-child(4)'); }], ['wide-address-edit', WIDE, 'tabs=4', async page => { await page.click('.dv-active-group .bt-omni-fill'); await page.keyboard.press('Control+A'); await page.keyboard.type('from:tauriapps since'); }], ]; const only = process.env.ONLY?.split(','); const browser = await chromium.launch(); const errors = []; for (const [name, viewport, query, act] of shots) { if (only && !only.includes(name)) continue; const page = await browser.newPage({ viewport, deviceScaleFactor: 1, reducedMotion: 'reduce' }); page.on('pageerror', error => errors.push(`${name}: ${error.message}`)); page.on('console', message => { if (message.type() === 'error') errors.push(`${name}: ${message.text()}`); }); await page.goto(`${base}/?shell&${query}`); await page.waitForSelector('.bt-titlebar'); await page.waitForTimeout(900); if (act) { await act(page); await page.waitForTimeout(300); } await page.screenshot({ path: join(out, `${name}.png`) }); await page.close(); } await browser.close(); console.log(errors.length ? errors.join('\n') : 'no page errors');