git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

scripts/web-probe/drive.mjs (3.6K)

 1 // drive.mjs <site-dir> <out-dir>: open the demo page (browser.mjs) and run
 2 // the native harness's input script against it — the same pointer moves,
 3 // presses, wheel notches and keys, with the same waits, and one screenshot
 4 // per step (00-start.rgba … 23-titlebar-band.rgba: premultiplied RGBA8, the
 5 // frame read back from the GPU — compare.py composites it). A native run of the same
 6 // script under headless sway (the pointer parked at the corner, the cursor
 7 // hidden, CCE_UI_MENU_POPUP=0 so the menu is drawn in the window as it is
 8 // here) is what each screenshot is compared with.
 9 import fs from 'fs';
10 import { open } from './browser.mjs';
11 
12 const [root, out] = process.argv.slice(2);
13 if (!root || !out) { console.error('usage: drive.mjs <site-dir> <out-dir>'); process.exit(2); }
14 fs.mkdirSync(out, { recursive: true });
15 const { page, logs, close } = await open(root, 'demo.html', 1280, 800);
16 const m = page.mouse, k = page.keyboard;
17 const wait = ms => page.waitForTimeout(ms);
18 // One pointer command, then the 150 ms the native script's `v` waits.
19 const v = async f => { await f(); await wait(150); };
20 const shot = async name => {
21   await wait(900);
22   const b64 = await page.evaluate(() => window.capture());
23   fs.writeFileSync(`${out}/${name}.rgba`, Buffer.from(b64, 'base64'));
24 };
25 const BTN = { 272: 'left', 273: 'right' };
26 const click = b => v(async () => { await m.down({ button: BTN[b] }); await m.up({ button: BTN[b] }); });
27 const abs = (x, y) => v(() => m.move(x, y));
28 
29 let ok = true;
30 try {
31   await abs(1279, 799);
32   await page.waitForFunction(() => window.demoReady === true, null, { timeout: 120000 });
33   await wait(5000);
34   await shot('00-start');
35   await abs(85, 91); await shot('01-hover-button');
36   await click(272); await shot('02-click-button');
37   await abs(202, 91); await click(272); await shot('03-toggle');
38   await abs(332, 91); await click(272); await shot('04-dropdown-open');
39   await abs(332, 122); await click(272); await shot('05-dropdown-pick');
40   await abs(640, 168); await click(272); await shot('06-textbox-focus');
41   await k.type('hello web'); await shot('07-typed');
42   await k.down('Control'); await k.press('z'); await k.up('Control'); await shot('08-undo');
43   for (let i = 0; i < 3; i++) await k.press('Backspace');
44   await shot('09-backspace');
45   await abs(900, 130); await v(() => m.down()); await abs(1000, 130); await abs(1100, 131); await v(() => m.up());
46   await shot('10-slider-drag');
47   await abs(517, 131); await v(() => m.wheel(0, -300)); await shot('11-slider-wheel');
48   await abs(600, 500); await click(273); await shot('12-context-menu');
49   await abs(640, 525); await shot('13-menu-hover');
50   await abs(1200, 750); await click(272); await shot('14-menu-dismiss');
51   await abs(600, 500); await click(273); await abs(640, 525); await click(272); await shot('15-menu-run');
52   await k.press('Tab'); await shot('16-tab');
53   await k.press('Escape'); await shot('17-esc');
54   await abs(640, 168); await click(272); await k.type('xyzxyz'); await shot('18-refocus-typed');
55   await k.down('Backspace'); await wait(1500); await k.up('Backspace'); await shot('19-hold-backspace');
56   await k.type('abcdef'); await k.down('ArrowLeft'); await wait(1500); await k.up('ArrowLeft'); await k.type('Z');
57   await shot('20-hold-left-then-type');
58   await abs(3, 400); await click(272); await shot('21-csd-left-edge');
59   await abs(640, 3); await click(272); await shot('22-csd-top-edge');
60   await abs(300, 20); await click(272); await shot('23-titlebar-band');
61 } catch (e) { ok = false; logs.push('[drive] ' + String(e)); }
62 for (const l of logs) console.log(l);
63 await close();
64 process.exit(ok ? 0 : 1);