返回 DeepSeek-Reasonix
recoverable-toast-lifecycle.test.tsx
根目录 / desktop / frontend / src / __tests__ / recoverable-toast-lifecycle.test.tsx
1 import assert from "node:assert/strict";
2 import React, { act, StrictMode, useLayoutEffect } from "react";
3 import { createRoot } from "react-dom/client";
4 import { JSDOM } from "jsdom";
5 import { useRecoverableErrorToasts } from "../app-runtime/useAppEffectHosts";
6 import { RECOVERABLE_ERROR_EVENT } from "../lib/globalCrashHandlers";
7
8 const dom = new JSDOM("<div id='root'></div>", { url: "http://localhost", pretendToBeVisual: true });
9 Object.assign(globalThis, { window: dom.window, document: dom.window.document,
10 Node: dom.window.Node, HTMLElement: dom.window.HTMLElement, IS_REACT_ACT_ENVIRONMENT: true });
11 const root = createRoot(document.getElementById("root")!);
12 const delivered: string[] = [];
13 const fire = (message: string) => window.dispatchEvent(new dom.window.CustomEvent(RECOVERABLE_ERROR_EVENT, { detail: { message } }));
14 function Fixture({ owner }: { owner: string }) {
15 useRecoverableErrorToasts((message, level, options) => {
16 assert.equal(level, "warn"); assert.equal(options?.durationMs, 6000);
17 delivered.push(`${owner}:${message}`);
18 });
19 useLayoutEffect(() => () => { fire("layout-cleanup"); }, []);
20 return null;
21 }
22 try {
23 for (let index = 0; index < 32; index++) {
24 await act(async () => root.render(<StrictMode><Fixture owner={String(index)} /></StrictMode>));
25 await act(async () => { fire("backend-error"); });
26 assert.equal(delivered.length, index + 1, "one subscription survives StrictMode and callback replacement");
27 assert.equal(delivered.at(-1), `${index}:backend-error`, "delivery uses the latest committed toast sink");
28 }
29 await act(async () => root.unmount());
30 fire("after-unmount");
31 assert.equal(delivered.length, 32, "layout teardown revokes delivery before passive unsubscribe, with no late toast");
32 console.log("recoverable toast lifecycle: current sink, single subscription and synchronous teardown passed");
33 } finally { dom.window.close(); }
34
34 lines Plain Text