返回 DeepSeek-Reasonix
committed-command-lifecycle.test.tsx
根目录 / desktop / frontend / src / __tests__ / committed-command-lifecycle.test.tsx
1 import React, { act, useLayoutEffect } from "react";
2 import { createRoot } from "react-dom/client";
3 import { JSDOM } from "jsdom";
4 import assert from "node:assert/strict";
5 import { useCommittedCommand } from "../lib/useCommittedCommand";
6 import { useCommittedAsyncCommand } from "../lib/useCommittedAsyncCommand";
7 import type { CommandOutcome } from "../lib/commandOutcome";
8
9 const dom = new JSDOM("<div id='root'></div>");
10 Object.assign(globalThis, {
11 window: dom.window,
12 document: dom.window.document,
13 IS_REACT_ACT_ENVIRONMENT: true,
14 });
15 const root = createRoot(document.getElementById("root")!);
16 let retained!: () => void;
17 let effects = 0;
18 const failures: string[] = [];
19 function check(label: string, run: () => void) {
20 try { run(); console.log(`PASS ${label}`); }
21 catch (error) { failures.push(`${label}: ${String(error)}`); }
22 }
23
24 function Probe() {
25 retained = useCommittedCommand(() => { effects += 1; });
26 return null;
27 }
28
29 let release!: () => void;
30 const gate = new Promise<void>((resolve) => { release = resolve; });
31 let pending!: Promise<CommandOutcome<void>>;
32 const awaitGate = (input: Promise<void>) => input;
33 function LayoutProbe() {
34 const command = useCommittedAsyncCommand(() => gate, awaitGate);
35 useLayoutEffect(() => { pending = command(); }, [command]);
36 return null;
37 }
38
39 try {
40 await act(async () => root.render(<Probe />));
41 retained();
42 assert.equal(effects, 1);
43 act(() => {
44 root.unmount();
45 retained();
46 check("unmount revokes command authority synchronously", () => assert.equal(effects, 1));
47 });
48 const layoutRoot = createRoot(document.createElement("div"));
49 await act(async () => layoutRoot.render(<LayoutProbe />));
50 release();
51 const result = await pending;
52 check("normal passive setup does not invalidate layout-started work", () => {
53 assert.deepEqual(result, { status: "completed", value: undefined });
54 });
55 await act(async () => layoutRoot.unmount());
56 assert.deepEqual(failures, []);
57 } finally {
58 dom.window.close();
59 }
60
60 lines Plain Text