返回 DeepSeek-Reasonix
performanceHost.test.ts
根目录 / desktop / electron / src / main / performanceHost.test.ts
1 import assert from "node:assert/strict";
2 import { EventEmitter } from "node:events";
3 import type { BrowserWindow } from "electron";
4 import { test } from "node:test";
5 import { createPerformanceHost } from "./performanceHost.js";
6
7 test("heap export requires consent and an OS save choice, stays single flight, and never uploads", async () => {
8 const contents = Object.assign(new EventEmitter(), { isDestroyed: () => false, takeHeapSnapshot: async (path: string) => { paths.push(path); await pending; } });
9 const win = Object.assign(new EventEmitter(), { webContents: contents, isVisible: () => true, isFocused: () => true });
10 let consent = 0;
11 let release!: () => void;
12 const pending = new Promise<void>((resolve) => { release = resolve; });
13 const paths: string[] = [];
14 const host = createPerformanceHost({ window: () => win as unknown as BrowserWindow, workerPath: "unused", locale: () => "en", dialog: {
15 showMessageBox: async () => ({ response: consent, checkboxChecked: false }),
16 showSaveDialog: async () => ({ canceled: false, filePath: "chosen.heapsnapshot" }),
17 } });
18 assert.deepEqual(await host.exportHeapSnapshot(), { status: "cancelled" });
19 assert.deepEqual(paths, []);
20 consent = 1;
21 const exportWork = host.exportHeapSnapshot();
22 await Promise.resolve(); await Promise.resolve();
23 assert.deepEqual(await host.exportHeapSnapshot(), { status: "busy" });
24 assert.deepEqual(await host.captureRendererProfile(), { status: "busy" });
25 assert.deepEqual(paths, ["chosen.heapsnapshot"]);
26 release();
27 assert.deepEqual(await exportWork, { status: "saved" });
28 host.dispose();
29 assert.deepEqual(await host.exportHeapSnapshot(), { status: "unavailable" });
30 });
31
32 test("navigation while the consent dialog is open cancels export", async () => {
33 const contents = Object.assign(new EventEmitter(), { isDestroyed: () => false, takeHeapSnapshot: async () => { throw Error("must not capture"); } });
34 const win = Object.assign(new EventEmitter(), { webContents: contents, isVisible: () => true, isFocused: () => true });
35 const host = createPerformanceHost({ window: () => win as unknown as BrowserWindow, workerPath: "unused", locale: () => "en", dialog: {
36 showMessageBox: async () => { contents.emit("did-start-navigation", {}, "reasonix://app", false, true); return { response: 1, checkboxChecked: false }; },
37 showSaveDialog: async () => { throw Error("must not save"); },
38 } });
39 assert.deepEqual(await host.exportHeapSnapshot(), { status: "cancelled" });
40 assert.equal(contents.listenerCount("did-start-navigation"), 0);
41 });
42
43 test("production activity policy requires native focus and cancels on blur", async () => {
44 let focused = false;
45 let attached = false;
46 const debuggerApi = Object.assign(new EventEmitter(), {
47 isAttached: () => attached,
48 attach: () => { attached = true; },
49 detach: () => { attached = false; },
50 sendCommand: async () => ({ profile: { nodes: [], startTime: 0, endTime: 0 } }),
51 });
52 const contents = Object.assign(new EventEmitter(), { debugger: debuggerApi, isDestroyed: () => false, isDevToolsOpened: () => false });
53 const win = Object.assign(new EventEmitter(), { webContents: contents, isVisible: () => true, isFocused: () => focused });
54 const host = createPerformanceHost({ window: () => win as unknown as BrowserWindow, workerPath: "must-not-run", locale: () => "en", dialog: {
55 showMessageBox: async () => { throw Error("must not prompt"); }, showSaveDialog: async () => { throw Error("must not save"); },
56 } });
57 assert.deepEqual(await host.captureRendererProfile("inactive"), { status: "inactive" });
58 assert.deepEqual(await host.exportHeapSnapshot(), { status: "unavailable" });
59 assert.equal(attached, false);
60 focused = true;
61 const capture = host.captureRendererProfile("active");
62 for (let i = 0; i < 20; i++) await Promise.resolve();
63 assert.equal(attached, true);
64 focused = false;
65 win.emit("blur");
66 assert.deepEqual(await capture, { status: "cancelled" });
67 assert.equal(attached, false);
68 assert.equal(win.listenerCount("blur"), 0);
69 });
70
70 lines TYPESCRIPT