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);