返回 DeepSeek-Reasonix
scroll-content-observer.test.ts
根目录 / desktop / frontend / src / __tests__ / scroll-content-observer.test.ts
1 // Run: tsx src/__tests__/scroll-content-observer.test.ts
2
3 import { JSDOM } from "jsdom";
4 import { observeScrollContentSize } from "../lib/scrollContentObserver";
5
6 let passed = 0;
7 let failed = 0;
8
9 function eq(actual: unknown, expected: unknown, label: string) {
10 if (actual === expected) {
11 process.stdout.write(` PASS ${label}\n`);
12 passed += 1;
13 } else {
14 process.stdout.write(` FAIL ${label}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}\n`);
15 failed += 1;
16 }
17 }
18
19 console.log("\nscroll content observer");
20
21 const dom = new JSDOM("<!doctype html><html><body><div id=scroll><div id=first></div></div></body></html>");
22 globalThis.window = dom.window as unknown as Window & typeof globalThis;
23 globalThis.document = dom.window.document;
24
25 class FakeResizeObserver {
26 static current: FakeResizeObserver | null = null;
27 readonly observed = new Set<Element>();
28 disconnected = false;
29
30 constructor(private readonly callback: ResizeObserverCallback) {
31 FakeResizeObserver.current = this;
32 }
33
34 observe(target: Element) { this.observed.add(target); }
35 unobserve(target: Element) { this.observed.delete(target); }
36 disconnect() { this.disconnected = true; this.observed.clear(); }
37 trigger() { this.callback([], this as unknown as ResizeObserver); }
38 }
39
40 class FakeMutationObserver {
41 static current: FakeMutationObserver | null = null;
42 disconnected = false;
43
44 constructor(private readonly callback: MutationCallback) {
45 FakeMutationObserver.current = this;
46 }
47
48 observe() {}
49 disconnect() { this.disconnected = true; }
50 takeRecords(): MutationRecord[] { return []; }
51 trigger() { this.callback([], this as unknown as MutationObserver); }
52 }
53
54 globalThis.ResizeObserver = FakeResizeObserver as unknown as typeof ResizeObserver;
55 globalThis.MutationObserver = FakeMutationObserver as unknown as typeof MutationObserver;
56
57 const scroll = document.getElementById("scroll");
58 const first = document.getElementById("first");
59 if (!scroll || !first) throw new Error("missing test elements");
60
61 let changes = 0;
62 const stop = observeScrollContentSize(scroll, () => { changes += 1; });
63 eq(FakeResizeObserver.current?.observed.has(first), true, "observes existing transcript children");
64
65 FakeResizeObserver.current?.trigger();
66 eq(changes, 1, "content child resize refreshes scrollbar metrics");
67
68 const second = document.createElement("div");
69 scroll.appendChild(second);
70 FakeMutationObserver.current?.trigger();
71 eq(FakeResizeObserver.current?.observed.has(second), true, "observes children added after mount");
72 eq(changes, 2, "child-list changes refresh scrollbar metrics");
73
74 first.remove();
75 FakeMutationObserver.current?.trigger();
76 eq(FakeResizeObserver.current?.observed.has(first), false, "stops observing removed transcript children");
77
78 stop();
79 eq(FakeResizeObserver.current?.disconnected, true, "disconnects the resize observer on cleanup");
80 eq(FakeMutationObserver.current?.disconnected, true, "disconnects the mutation observer on cleanup");
81
82 dom.window.close();
83
84 console.log(`\n${passed} passed, ${failed} failed, ${passed + failed} total`);
85 if (failed > 0) process.exit(1);
86
86 lines TYPESCRIPT