Files
openidea/src/test/setup.ts
T
l0ng-ai 5670c2e8dd test: stub Range layout methods once in the test setup (#53)
Root cause: jsdom has no layout and CodeMirror measures text ranges in an animation frame, sometimes after a test finished; test files that did not stub Range.getClientRects (e.g. search/codePreview) threw an unhandled TypeError that failed whole CI runs at random (seen on #41).
Fix: stub Range.getClientRects / getBoundingClientRect once in src/test/setup.ts; drop the six per-file copies.
Verified: vitest on editor/lsp, editor/refactor, templates, search (55 files, 458 tests, no unhandled errors).

Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
2026-10-27 10:38:11 +08:00

48 lines
2.1 KiB
TypeScript

import "@testing-library/jest-dom/vitest";
import { afterEach } from "vitest";
import { cleanup } from "@testing-library/react";
afterEach(() => cleanup());
// jsdom has no layout: give elements a size so virtualized lists render rows.
if (typeof window !== "undefined") {
// jsdom's user agent names the host OS; tests are written for macOS (⌘ keymaps) and opt into Windows explicitly.
Object.defineProperty(window.navigator, "userAgent", {
configurable: true,
get: () => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) jsdom",
});
Object.defineProperty(HTMLElement.prototype, "clientHeight", { configurable: true, get: () => 600 });
Object.defineProperty(HTMLElement.prototype, "clientWidth", { configurable: true, get: () => 400 });
Object.defineProperty(HTMLElement.prototype, "offsetHeight", { configurable: true, get: () => 600 });
Object.defineProperty(HTMLElement.prototype, "offsetWidth", { configurable: true, get: () => 400 });
if (!("ResizeObserver" in window)) {
class ResizeObserverStub {
observe() {}
unobserve() {}
disconnect() {}
}
(window as unknown as { ResizeObserver: unknown }).ResizeObserver = ResizeObserverStub;
(globalThis as unknown as { ResizeObserver: unknown }).ResizeObserver = ResizeObserverStub;
}
if (!window.matchMedia) {
window.matchMedia = (query: string) =>
({
matches: false,
media: query,
onchange: null,
addEventListener() {},
removeEventListener() {},
addListener() {},
removeListener() {},
dispatchEvent: () => false,
}) as MediaQueryList;
}
Element.prototype.scrollIntoView ??= function () {};
// No layout either: CodeMirror measures text ranges when it positions the caret,
// tooltips and line heights, sometimes in an animation frame after a test ends.
Range.prototype.getClientRects ??= () => Object.assign([], { item: () => null }) as unknown as DOMRectList;
Range.prototype.getBoundingClientRect ??= () => new DOMRect();
Element.prototype.scrollTo ??= function () {} as Element["scrollTo"];
}