/** * lib/dom-dump.js hygiene, exercised in a real browser through gstack's own * browse binary (`$B eval --out --raw`, the same fallback path * /design-review renders). Self-skips when no browse binary is built * (`bun run build:gates`), like the other render gates. * * Pins the rules the DOM dump promises before a page leaves the browser: * input values dropped, long data: URLs replaced (attributes, inlined CSS, and * existing
x
`); const url = `http://127.0.0.1:${server.port}/index.html`; // Own daemon: BROWSE_STATE_FILE scopes the state dir, lock, port file, and // profile to this test, so it never shares (or stops) another session's daemon. fs.mkdirSync(path.join(tmp, '.gstack'), { recursive: true }); const env = { ...process.env, BROWSE_STATE_FILE: path.join(tmp, '.gstack', 'browse.json') }; const browse = (args: string[]) => spawnSync(BROWSE!, args, { encoding: 'utf-8', timeout: 90_000, env }); try { // A cold daemon start can miss the CLI's ~8 s health window on a loaded // machine (CI shards, a concurrent eval run). Bounded retries, then fail loud. let go = browse(['goto', url]); for (let attempt = 0; attempt < 6 && go.status !== 0; attempt++) { Bun.sleepSync(10_000); go = browse(['goto', url]); } expect(go.status, go.stderr + go.stdout).toBe(0); // The same invocation the skill renders for the fallback engine: the arrow // function spliced from lib/dom-dump.js and called in the page. const dump = fs.readFileSync(path.join(ROOT, 'lib', 'dom-dump.js'), 'utf-8'); const out = path.join(tmp, 'index.dom.html'); const ev = browse(['js', `(${dump})()`, '--out', out, '--raw']); expect(ev.status, ev.stderr + ev.stdout).toBe(0); const html = fs.readFileSync(out, 'utf-8'); expect(html.startsWith('')).toBe(true); expect(html).toContain(`