import "@testing-library/jest-dom/vitest"; import { cleanup } from "@testing-library/react"; import { afterEach } from "vitest"; afterEach(() => cleanup()); // jsdom 缺口 polyfill(spec S2):radix 原语在 jsdom 下的已知缺失,一次配好全体组件测试共用。 class ResizeObserverStub { observe() {} unobserve() {} disconnect() {} } globalThis.ResizeObserver ??= ResizeObserverStub as unknown as typeof ResizeObserver; Element.prototype.scrollIntoView ??= function scrollIntoView() {}; // radix 的焦点/拖拽逻辑会探测 pointer capture API,jsdom 未实现 Element.prototype.hasPointerCapture ??= (() => false) as never; Element.prototype.setPointerCapture ??= (() => {}) as never; Element.prototype.releasePointerCapture ??= (() => {}) as never; // jsdom 未实现 matchMedia(theme.tsx 按 prefers-color-scheme 求值):EventTarget 基类覆盖 // addEventListener/removeEventListener,addListener/removeListener 是旧版 legacy API 兼容面。 class MediaQueryListStub extends EventTarget { media: string; matches: boolean; onchange: ((this: MediaQueryList, ev: MediaQueryListEvent) => unknown) | null = null; constructor(media: string) { super(); this.media = media; this.matches = false; } addListener(listener: (this: MediaQueryList, ev: MediaQueryListEvent) => unknown) { this.addEventListener("change", listener as EventListener); } removeListener(listener: (this: MediaQueryList, ev: MediaQueryListEvent) => unknown) { this.removeEventListener("change", listener as EventListener); } } globalThis.matchMedia ??= ((media: string) => new MediaQueryListStub(media)) as unknown as typeof matchMedia;