返回 DeepSeek-Reasonix
pageRuntime.test.ts
根目录 / desktop / electron / src / main / browser / pageRuntime.test.ts
1 import assert from "node:assert/strict";
2 import { test } from "node:test";
3 import { build } from "esbuild";
4 import { createRequire } from "node:module";
5 import { mkdtemp, copyFile, rm } from "node:fs/promises";
6 import { tmpdir } from "node:os";
7 import { resolve, join } from "node:path";
8 import { JSDOM } from "jsdom";
9
10 test("production minification cannot leak main-world bundler helpers into page scripts", async () => {
11 const dir = await mkdtemp(join(tmpdir(), "reasonix-page-bundle-"));
12 const dom = new JSDOM('<body><button aria-label="Save">Save</button></body>', { runScripts: "outside-only", pretendToBeVisual: true });
13 try {
14 // Same failure mechanism as the former nested snapshot walker: keepNames
15 // introduces a module helper which Function#toString cannot carry along.
16 const legacy = await build({ stdin: { contents: 'export function pageSnapshot() { const role = element => element.getAttribute("aria-label"); return role(document.querySelector("button")); }', loader: "js" }, bundle: true, platform: "node", format: "cjs", minify: true, keepNames: true, write: false });
17 const oldModule = { exports: {} as { pageSnapshot?: () => string } };
18 new Function("module", "exports", legacy.outputFiles[0].text)(oldModule, oldModule.exports);
19 assert.throws(() => dom.window.eval(`(${oldModule.exports.pageSnapshot!.toString()})()`), /not defined/, "the old serialization mechanism must fail in the same isolated page environment");
20 for (const name of ["browser-page.js", "browser-page.json"]) await copyFile(resolve("dist", name), join(dir, name));
21 await build({ entryPoints: [resolve("src/main/browser/pageScripts.ts")], bundle: true, platform: "node", target: "node22", format: "cjs", minify: true, keepNames: true, outfile: join(dir, "main.cjs"), logLevel: "silent" });
22 const runtime = createRequire(import.meta.url)(join(dir, "main.cjs")) as { scriptCall(method: string, input: unknown): string };
23 dom.window.Element.prototype.getBoundingClientRect = () => ({ width: 50, height: 20, x: 0, y: 0, left: 0, top: 0, right: 50, bottom: 20, toJSON() {} });
24 const out = dom.window.eval(runtime.scriptCall("pageSnapshot", { key: "test", snapshotId: "s1", prefix: "", selector: "", budget: 4000 })) as { tree: string; docId: string };
25 assert.match(out.tree, /button "Save" ref=e1/);
26 assert.equal(dom.window.eval("typeof __name"), "undefined");
27 assert.equal(dom.window.eval(runtime.scriptCall("pageIdentity", { key: "test", docId: out.docId })), true);
28 const picking = dom.window.eval(runtime.scriptCall("pagePickElement", { key: "test" })) as Promise<unknown>;
29 assert.equal(dom.window.document.querySelectorAll("div").length, 1);
30 dom.window.eval(runtime.scriptCall("pageCancelPicker", {}));
31 assert.equal(await picking, null);
32 assert.equal(dom.window.document.querySelectorAll("div").length, 0, "closing the panel cancels and removes the picker overlay");
33 } finally {
34 dom.window.close();
35 await rm(dir, { recursive: true, force: true });
36 }
37 });
38
38 lines TYPESCRIPT