返回 DeepSeek-Reasonix
desktop-preferences-lifecycle.test.tsx
根目录 / desktop / frontend / src / __tests__ / desktop-preferences-lifecycle.test.tsx
1 import assert from "node:assert/strict";
2 import React, { act } from "react";
3 import { createRoot } from "react-dom/client";
4 import { JSDOM } from "jsdom";
5 import { useDesktopPreferences } from "../app-runtime/useDesktopPreferences";
6 import { getSessionExperience, hydrateSessionExperience } from "../lib/sessionExperience";
7 import { LocaleProvider } from "../lib/i18n";
8 import type { DesktopStartupSettingsView } from "../lib/types";
9 import { installDesktopHostStub } from "./desktopHostStub";
10
11 const dom = new JSDOM("<div id='root'></div>", { url: "http://localhost", pretendToBeVisual: true });
12 Object.assign(globalThis, { window: dom.window, document: dom.window.document, localStorage: dom.window.localStorage,
13 CustomEvent: dom.window.CustomEvent, IS_REACT_ACT_ENVIRONMENT: true });
14 window.matchMedia = (() => ({ matches: false, addEventListener() {}, removeEventListener() {} })) as typeof window.matchMedia;
15 let requests = 0;
16 let fullSettings = 0;
17 let resolveStartup!: (settings: DesktopStartupSettingsView) => void;
18 const startup = new Promise<DesktopStartupSettingsView>(resolve => { resolveStartup = resolve; });
19 const appStubTable = {
20 DesktopStartupSettings: () => { requests++; return startup; },
21 Settings: () => { fullSettings++; throw new Error("startup must not request full Settings"); },
22 BotRuntimeStatus: async () => null,
23 SetTrayLocale: async () => {},
24 GetThemeExperience: async () => ({ themeMode: "light", baseStyle: "graphite", effectiveStyle: "graphite" }),
25 };
26 const desktopStub = installDesktopHostStub(appStubTable);
27 let current!: ReturnType<typeof useDesktopPreferences>;
28 function Probe() { current = useDesktopPreferences(); return <div>{current.configLoadWarnings.join("|")}</div>; }
29 const root = createRoot(document.getElementById("root")!);
30 const snapshot = { sessionExperience: "deep", desktopTheme: "light", desktopThemeStyle: "graphite",
31 desktopLanguage: "en", checkUpdates: true, updaterEnabled: true, configWarnings: ["warning"], configWarningsRevision: 3 } as DesktopStartupSettingsView;
32 try {
33 localStorage.setItem("reasonix-process-fold", "auto");
34 await act(async () => root.render(<LocaleProvider><Probe /></LocaleProvider>));
35 assert.equal(requests, 1);
36 await act(async () => { resolveStartup(snapshot); await import("../lib/themeExperience"); });
37 assert.equal(getSessionExperience(), "deep", "backend wins over an old localStorage mirror");
38 assert.equal(current.startupUpdateChecksEnabled, true, "stable build and enabled preference allow automatic checks");
39 assert.deepEqual(current.configLoadWarnings, ["warning"]);
40 await act(async () => { desktopStub.emit("config:load-warnings", ["stale"], 2); });
41 assert.deepEqual(current.configLoadWarnings, ["warning"], "stale runtime warning cannot replace startup snapshot");
42 await act(async () => { desktopStub.emit("config:load-warnings", ["current"], 4); });
43 assert.deepEqual(current.configLoadWarnings, ["current"]);
44 await act(async () => { await current.reload({ ...snapshot, sessionExperience: undefined }); });
45 assert.equal(getSessionExperience(), "standard", "old backend missing field resolves standard");
46 await act(async () => { await current.reload({ ...snapshot, sessionExperience: undefined, updaterEnabled: undefined }); });
47 assert.equal(current.startupUpdateChecksEnabled, false, "old backend missing updater capability fails closed");
48 await act(async () => { await current.reload({ ...snapshot, sessionExperience: undefined, updaterEnabled: false }); });
49 assert.equal(current.startupUpdateChecksEnabled, false, "disabled build capability overrides the user preference");
50 assert.equal(fullSettings, 0, "preferences and IM projection never request full Settings");
51 const oldReload = current.reload;
52 await act(async () => root.unmount());
53 assert.equal(desktopStub.events.get("config:load-warnings")?.size ?? 0, 0);
54 await oldReload(snapshot);
55 assert.equal(getSessionExperience(), "standard", "disposed commands cannot mutate global experience");
56 const originalWarn = console.warn;
57 console.warn = () => {};
58 const failedRoot = createRoot(document.getElementById("root")!);
59 try {
60 Object.assign(appStubTable, { DesktopStartupSettings: async () => { throw new Error("offline"); } });
61 hydrateSessionExperience("deep");
62 await act(async () => failedRoot.render(<LocaleProvider><Probe /></LocaleProvider>));
63 await act(async () => { await current.reload(); });
64 assert.equal(getSessionExperience(), "standard", "failed first snapshot uses canonical standard, not a legacy local preference");
65 assert.equal(current.startupUpdateChecksEnabled, false, "startup RPC failure disables automatic checks");
66 } finally { await act(async () => failedRoot.unmount()); console.warn = originalWarn; }
67 console.log("desktop preferences: lightweight snapshot, legacy mirror, warning revision and disposal passed");
68 } finally { dom.window.close(); }
69
69 lines Plain Text