返回 DeepSeek-Reasonix
context-panel-capacity.test.tsx
根目录 / desktop / frontend / src / __tests__ / context-panel-capacity.test.tsx
1 // Run: tsx src/__tests__/context-panel-capacity.test.tsx
2
3 import { JSDOM } from "jsdom";
4 import React from "react";
5 import { act } from "react";
6 import { createRoot } from "react-dom/client";
7 import { ContextPanel } from "../components/ContextPanel";
8 import { LocaleProvider } from "../lib/i18n";
9 import type { ContextPanelInfo } from "../lib/types";
10 import { installDesktopHostStub } from "./desktopHostStub";
11
12 let passed = 0;
13 let failed = 0;
14
15 function ok(value: boolean, label: string) {
16 if (value) {
17 process.stdout.write(` PASS ${label}\n`);
18 passed += 1;
19 } else {
20 process.stdout.write(` FAIL ${label}\n`);
21 failed += 1;
22 }
23 }
24
25 function eq(actual: unknown, expected: unknown, label: string) {
26 if (actual === expected) ok(true, label);
27 else ok(false, `${label}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
28 }
29
30 function wait(ms = 0): Promise<void> {
31 return new Promise((resolve) => setTimeout(resolve, ms));
32 }
33
34 class TestResizeObserver {
35 observe() {}
36 unobserve() {}
37 disconnect() {}
38 }
39
40 function installDom() {
41 const dom = new JSDOM("<!doctype html><html><body><div id=\"root\"></div></body></html>", {
42 pretendToBeVisual: true,
43 url: "http://localhost/",
44 });
45 (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
46 globalThis.window = dom.window as unknown as Window & typeof globalThis;
47 globalThis.document = dom.window.document;
48 globalThis.Node = dom.window.Node;
49 globalThis.HTMLElement = dom.window.HTMLElement;
50 globalThis.Event = dom.window.Event;
51 globalThis.ResizeObserver = TestResizeObserver;
52 return dom;
53 }
54
55 function emptyPanelInfo(): ContextPanelInfo {
56 return {
57 usedTokens: 0,
58 windowTokens: 0,
59 promptTokens: 0,
60 completionTokens: 0,
61 totalTokens: 0,
62 reasoningTokens: 0,
63 cacheHitTokens: 0,
64 cacheMissTokens: 0,
65 sessionCacheHitTokens: 0,
66 sessionCacheMissTokens: 0,
67 sessionCompletionTokens: 0,
68 requestCount: 0,
69 elapsedMs: 0,
70 sessionCost: 0,
71 readFiles: [],
72 changedFiles: [],
73 };
74 }
75
76 console.log("\ncontext panel capacity");
77
78 const dom = installDom();
79 installDesktopHostStub(({
80 main: { App: { ContextPanel: async () => emptyPanelInfo() } },
81 }).main.App);
82 const rootEl = document.getElementById("root");
83 if (!rootEl) throw new Error("missing root");
84 const root = createRoot(rootEl);
85
86 await act(async () => {
87 root.render(
88 <LocaleProvider>
89 <ContextPanel
90 tabId="tab-capacity"
91 context={{ used: 1_001, window: 1_000, sessionTokens: 1_001, compactRatio: 0.8 }}
92 />
93 </LocaleProvider>,
94 );
95 await wait();
96 });
97
98 const capacity = document.querySelector(".context-panel__capacity-card");
99 const meter = capacity?.querySelector(".context-panel__capacity-meter");
100 const fill = meter?.querySelector(".context-panel__progress-fill") as HTMLElement | null;
101 const usedPin = meter?.querySelector(".context-panel__capacity-pin--used");
102 const compactMarker = meter?.querySelector(".context-panel__compact-marker") as HTMLElement | null;
103
104 eq(capacity?.querySelector(".context-panel__capacity-status")?.textContent, "Over context limit", "over-limit status is explicit");
105 eq(usedPin?.textContent, "101%", "just-over-limit percentage pin remains visibly over 100 percent");
106 eq(fill?.style.width, "100%", "capacity fill is capped at the physical track width");
107 eq(meter?.querySelectorAll(".context-panel__progress-segment").length, 0, "capacity meter does not mix token composition into its fill");
108 eq(compactMarker?.style.left, "80%", "compression threshold marker stays at the configured ratio");
109 ok(meter?.getAttribute("aria-label")?.includes("101% used") === true, "accessible summary reports the over-limit ratio");
110
111 await act(async () => {
112 root.unmount();
113 });
114 dom.window.close();
115
116 console.log(`\n${passed} passed, ${failed} failed`);
117 if (failed > 0) process.exit(1);
118
118 lines Plain Text