返回 DeepSeek-Reasonix
automation-navigation-lifecycle.test.tsx
根目录 / desktop / frontend / src / __tests__ / automation-navigation-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 { useAutomationNavigation } from "../app-runtime/useAutomationNavigation";
6 import { useAppNavigationStore as navigation } from "../store/appNavigation";
7 import type { DesktopNavigationIntent } from "../app-runtime/desktopNavigationOwner";
8
9 const dom = new JSDOM("<div id='root'></div>");
10 Object.assign(globalThis, { window: dom.window, document: dom.window.document, IS_REACT_ACT_ENVIRONMENT: true });
11 const root = createRoot(document.getElementById("root")!);
12 let seq = 0;
13 const queued: { request: DesktopNavigationIntent; intent: number; resolve(): void }[] = [];
14 let commands!: ReturnType<typeof useAutomationNavigation>;
15 function Probe() {
16 commands = useAutomationNavigation({ noteIntent: () => ++seq,
17 enqueue: (request, intent) => new Promise<void>(resolve => queued.push({ request, intent, resolve })) });
18 return null;
19 }
20 try {
21 await act(async () => root.render(<Probe />));
22 navigation.getState().openPage({ kind: "automation" });
23 const a = commands.openAutomationTopic("project", "fixture", "A");
24 assert.deepEqual(queued[0].request, { kind: "topic", scope: "project", workspaceRoot: "fixture", topicId: "A" });
25 assert.equal(navigation.getState().page.kind, "automation", "keep the management page until the target is accepted");
26 commands.topicAccepted(queued[0].intent);
27 assert.equal(navigation.getState().page.kind, "workspace");
28 assert.equal(navigation.getState().automationReturn, true);
29 navigation.getState().openPage({ kind: "automation" });
30 const b = commands.openAutomationTopic("project", "fixture", "B");
31 queued[0].resolve(); await a;
32 commands.topicAccepted(queued[1].intent);
33 assert.equal(navigation.getState().page.kind, "workspace", "old finally cannot retire the newer link");
34 queued[1].resolve(); await b;
35 navigation.getState().openPage({ kind: "automation" });
36 const c = commands.openAutomationTopic("project", "fixture", "C");
37 const original = queued[2].intent;
38 navigation.getState().openPage({ kind: "settings", tab: "general" });
39 navigation.getState().openPage({ kind: "automation" });
40 commands.topicAccepted(original);
41 assert.equal(navigation.getState().page.kind, "automation", "ABA page replacement cannot regain navigation rights");
42 assert.ok(seq > original, "page replacement revokes the controller's navigation intent");
43 queued[2].resolve(); await c;
44 const d = commands.openAutomationTopic("project", "fixture", "D");
45 const last = queued[3].intent;
46 queued[3].resolve(); await d;
47 commands.topicAccepted(last);
48 assert.equal(navigation.getState().page.kind, "automation", "an unaccepted terminal request leaves no live link");
49 await act(async () => root.unmount());
50 const before = seq;
51 commands.openAutomationTopic("project", "fixture", "disposed");
52 navigation.getState().returnToWorkspace();
53 assert.equal(seq, before, "unmount releases both command and page subscription");
54 console.log("automation navigation: accepted-target return, page ABA, exact finally and disposal passed");
55 } finally { dom.window.close(); }
56
56 lines Plain Text