返回 DeepSeek-Reasonix
message-reasoning-panel.test.tsx
根目录 / desktop / frontend / src / __tests__ / message-reasoning-panel.test.tsx
1 // Run: tsx src/__tests__/message-reasoning-panel.test.tsx
2
3 import { JSDOM } from "jsdom";
4 import React, { act } from "react";
5 import { createRoot } from "react-dom/client";
6 import { LocaleProvider } from "../lib/i18n";
7 import { AssistantMessage } from "../components/Message";
8
9 let passed = 0;
10 let failed = 0;
11
12 function ok(value: boolean, label: string) {
13 if (value) {
14 process.stdout.write(` PASS ${label}\n`);
15 passed += 1;
16 } else {
17 process.stdout.write(` FAIL ${label}\n`);
18 failed += 1;
19 }
20 }
21
22 console.log("\nmessage reasoning panel");
23
24 const dom = new JSDOM("<!doctype html><html><body><div id=\"root\"></div></body></html>", {
25 pretendToBeVisual: true,
26 url: "http://localhost/",
27 });
28 (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
29 globalThis.window = dom.window as unknown as Window & typeof globalThis;
30 globalThis.document = dom.window.document;
31 Object.defineProperty(globalThis, "navigator", { configurable: true, value: { ...dom.window.navigator, language: "en-US" } });
32 globalThis.Node = dom.window.Node;
33 globalThis.HTMLElement = dom.window.HTMLElement;
34 globalThis.Event = dom.window.Event;
35 globalThis.MouseEvent = dom.window.MouseEvent;
36 globalThis.localStorage = dom.window.localStorage;
37 globalThis.requestAnimationFrame = dom.window.requestAnimationFrame.bind(dom.window);
38 globalThis.cancelAnimationFrame = dom.window.cancelAnimationFrame.bind(dom.window);
39
40 const rootEl = document.getElementById("root");
41 if (!rootEl) throw new Error("missing root");
42 const root = createRoot(rootEl);
43
44 await act(async () => {
45 root.render(
46 <LocaleProvider>
47 <AssistantMessage
48 item={{
49 kind: "assistant",
50 id: "a1",
51 text: "",
52 reasoning: "line one\nline two",
53 streaming: false,
54 reasoningComplete: true,
55 reasoningDurationMs: 2_600,
56 }}
57 />
58 </LocaleProvider>,
59 );
60 });
61
62 const header = document.querySelector<HTMLButtonElement>(".reasoning__head");
63 ok(Boolean(header), "completed reasoning renders a toggle header");
64 ok(header?.textContent?.includes("thinking") ?? false, "header keeps the reasoning label");
65 ok(header?.textContent?.includes("lasted 3s") ?? false, "header shows rounded reasoning duration");
66 ok(!document.querySelector(".reasoning__body"), "completed reasoning is collapsed by default");
67
68 await act(async () => {
69 header?.dispatchEvent(new dom.window.MouseEvent("click", { bubbles: true }));
70 });
71
72 ok(document.querySelector(".reasoning__body")?.textContent?.includes("line two") ?? false, "clicking the header expands the reasoning body");
73
74 await act(async () => {
75 root.unmount();
76 });
77 dom.window.close();
78
79 console.log(`\n${passed} passed, ${failed} failed`);
80 if (failed > 0) process.exit(1);
81
81 lines Plain Text