返回 DeepSeek-Reasonix
ipc.browserControl.test.ts
根目录 / desktop / electron / src / main / ipc.browserControl.test.ts
1 import assert from "node:assert/strict";
2 import type { IpcMain } from "electron";
3 import { test } from "node:test";
4 import { IPC, type BrowserControlState, type IpcResult } from "../shared/ipc.js";
5 import { parseContract } from "./contract.js";
6 import { registerRendererIpc } from "./ipc.js";
7 import type { BrowserControlApi } from "./browserControlHost.js";
8
9 const silent = { info() {}, warn() {}, error() {} };
10 const STATE: BrowserControlState = { controlEnabled: true, ignoreCertificateErrors: false, writable: true, warning: null };
11
12 function fakeIpc() {
13 const handlers = new Map<string, (event: unknown, ...args: unknown[]) => Promise<IpcResult>>();
14 const ipcMain = {
15 handle: (channel: string, fn: (event: unknown, ...args: unknown[]) => Promise<IpcResult>) => handlers.set(channel, fn),
16 on: () => undefined,
17 } as unknown as IpcMain;
18 return { ipcMain, handlers };
19 }
20
21 function register(options: { browserControl?: BrowserControlApi; withGraphics?: boolean } = {}) {
22 const { ipcMain, handlers } = fakeIpc();
23 const trusted = { sender: { id: 1 }, senderFrame: {} };
24 registerRendererIpc({
25 ipcMain,
26 contract: parseContract({ digest: "sha256:a", commands: ["ListTabs"] }),
27 window: {
28 isTrustedSender: (sender, frame) => sender === trusted.sender && frame === trusted.senderFrame,
29 minimise() {},
30 toggleMaximise() {},
31 isMaximised: () => false,
32 close() {},
33 bounds: () => ({ x: 0, y: 0, width: 0, height: 0, maximised: false }),
34 setTheme() {},
35 setBackgroundColour() {},
36 getAppZoom: async () => 1,
37 setAppZoom: async () => 1,
38 resetAppZoom: async () => 1,
39 },
40 serviceState: () => ({ phase: "ready" as const, generation: "g-test" }),
41 invoke: async () => undefined,
42 clipboard: { writeText: async () => undefined, readText: async () => "" },
43 openExternal: async () => undefined,
44 ...(options.browserControl ? { browserControl: options.browserControl } : {}),
45 log: silent,
46 });
47 return { handlers, trusted };
48 }
49
50 function apiStub(calls: string[]): BrowserControlApi {
51 return {
52 state: () => STATE,
53 setControlEnabled: async (enabled) => {
54 calls.push(`enabled:${enabled}`);
55 return { ...STATE, controlEnabled: enabled };
56 },
57 setIgnoreCertificateErrors: async (enabled) => {
58 calls.push(`certificates:${enabled}`);
59 return { ...STATE, ignoreCertificateErrors: enabled };
60 },
61 clearCache: async () => void calls.push("clearCache"),
62 clearAllData: async () => void calls.push("clearAllData"),
63 importChromeLogin: async () => {
64 calls.push("import");
65 return { ok: true, profile: "Default", cookies: 3, skipped: 1 };
66 },
67 };
68 }
69
70 test("browser control channels are sender-gated and typed", async () => {
71 const calls: string[] = [];
72 const { handlers, trusted } = register({ browserControl: apiStub(calls) });
73 const get = handlers.get(IPC.browserControlGet);
74 const setEnabled = handlers.get(IPC.browserControlSetEnabled);
75 const setCertificates = handlers.get(IPC.browserControlSetIgnoreCertificateErrors);
76 const clearCache = handlers.get(IPC.browserControlClearCache);
77 const clearAll = handlers.get(IPC.browserControlClearAll);
78 const importChrome = handlers.get(IPC.browserControlImportChrome);
79 assert.ok(get && setEnabled && setCertificates && clearCache && clearAll && importChrome);
80
81 assert.deepEqual(await get({ sender: { id: 9 }, senderFrame: trusted.senderFrame }), { ok: false, message: "untrusted sender" });
82 assert.deepEqual(await get(trusted), { ok: true, value: STATE });
83 assert.deepEqual(await setEnabled(trusted, false), { ok: true, value: { ...STATE, controlEnabled: false } });
84 assert.deepEqual(await setEnabled(trusted, "no"), { ok: false, message: "controlEnabled must be boolean" });
85 assert.deepEqual(await setCertificates(trusted, true), { ok: true, value: { ...STATE, ignoreCertificateErrors: true } });
86 assert.deepEqual(await setCertificates(trusted, 1), { ok: false, message: "ignoreCertificateErrors must be boolean" });
87 assert.deepEqual(await clearCache(trusted), { ok: true, value: undefined });
88 assert.deepEqual(await clearAll(trusted), { ok: true, value: undefined });
89 assert.deepEqual(await importChrome(trusted), { ok: true, value: { ok: true, profile: "Default", cookies: 3, skipped: 1 } });
90 assert.deepEqual(calls, ["enabled:false", "certificates:true", "clearCache", "clearAllData", "import"]);
91 });
92
93 test("browser control channels fail closed without a shell store", async () => {
94 const { handlers, trusted } = register();
95 assert.deepEqual(await handlers.get(IPC.browserControlGet)!(trusted), { ok: true, value: null });
96 const message = "browser control settings unavailable";
97 assert.deepEqual(await handlers.get(IPC.browserControlSetEnabled)!(trusted, true), { ok: false, message });
98 assert.deepEqual(await handlers.get(IPC.browserControlClearCache)!(trusted), { ok: false, message });
99 assert.deepEqual(await handlers.get(IPC.browserControlImportChrome)!(trusted), { ok: false, message });
100 });
101
101 lines TYPESCRIPT