1/**
2 * Browser smoke test: serve the built app, load the demo data, run a
3 * short benchmark, and check that scores and the explorer arrive. Uses
4 * the system Chrome; no microphone is involved (demo data is synthetic).
5 * Run `npm run build` first, then `vite-node scripts/smoke-browser.ts`.
6 */
7import { chromium } from 'playwright-core';
8import { preview } from 'vite';
10const server = await preview({ preview: { port: 4173, strictPort: false } });
11const url = server.resolvedUrls!.local[0];
12console.log('serving', url);
14const browser = await chromium.launch({
15 executablePath: '/usr/bin/google-chrome',
16 headless: true,
17});
18const page = await browser.newPage();
19const errors: string[] = [];
20page.on('pageerror', (e) => errors.push(`pageerror: ${e.message}`));
21page.on('console', (m) => { if (m.type() === 'error') errors.push(`console: ${m.text()}`); });
23try {
24 await page.goto(url, { waitUntil: 'networkidle' });
26 await page.click('#load-demo');
27 await page.waitForFunction(() => document.querySelectorAll('.type-row').length === 3);
28 const counts = await page.$$eval('.type-row .count', (els) => els.map((e) => e.textContent));
29 console.log('type rows:', counts);
31 // shrink the benchmark so the smoke test stays quick
32 await page.evaluate(() => {
33 const inputs = [...document.querySelectorAll<HTMLInputElement>('#config-grid input')];
34 const set = (label: string, v: string) => {
35 const el = inputs.find((i) => i.parentElement!.textContent!.includes(label))!;
36 el.value = v;
37 el.dispatchEvent(new Event('change'));
38 };
39 set('dataset duration', '15');
40 set('events per type', '15');
41 set('runs', '2');
42 });
44 await page.click('#run-bench');
45 await page.waitForFunction(
46 () => document.getElementById('status')!.textContent!.includes('benchmark complete'),
47 undefined,
48 { timeout: 180000 },
49 );
50 const rows = await page.$$eval('#results > table.results tr', (trs) =>
51 trs.slice(1).map((tr) => [...tr.children].map((td) => td.textContent).join(' | ')));
52 console.log('results:');
53 for (const r of rows) console.log(' ', r);
55 const explorerVisible = await page.$eval('#explorer', (c) => (c as HTMLCanvasElement).height > 100);
56 console.log('explorer canvas populated:', explorerVisible);
58 // accuracy of the two real baselines should beat 0.5 on demo data
59 const accs = rows.map((r) => Number(r.split('|')[1].trim().split(' ')[0]));
60 if (rows.length !== 4) throw new Error(`expected 4 result rows, got ${rows.length}`);
61 if (!(accs[0] > 0.5 && accs[1] > 0.5)) throw new Error(`accuracies too low: ${accs.join(', ')}`);
62 if (errors.length) throw new Error(`page errors:\n${errors.join('\n')}`);
63 console.log('SMOKE PASS');
64} finally {
65 await browser.close();
66 await server.close();
67}