Files
Alfred/tests/setup.ts

136 lines
4.6 KiB
TypeScript

/**
* 全局测试配置
* 为所有测试初始化 jsdom — bun worker 的 process.argv 无法保证携带文件路径
* 噪声过滤对所有测试生效
*/
const originalStderrWrite = process.stderr.write.bind(process.stderr);
process.stderr.write = (chunk: string | Uint8Array, encodingOrCb?: unknown, cb?: unknown) => {
const str = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
if (str.includes("NaN") && str.includes("height") && str.includes("css style property")) return true;
return originalStderrWrite(
chunk,
encodingOrCb as Parameters<typeof process.stderr.write>[1],
cb as Parameters<typeof process.stderr.write>[2],
);
};
const originalConsoleError = console.error;
console.error = (...args: unknown[]) => {
const message = args.map(String).join(" ");
if (message.includes("NaN") && message.includes("height") && message.includes("css style property")) return;
originalConsoleError(...args);
};
const originalConsoleWarn = console.warn;
console.warn = (...args: unknown[]) => {
const message = args.map(String).join(" ");
if (message.includes("NaN") && message.includes("height") && message.includes("css style property")) return;
originalConsoleWarn(...args);
};
const { JSDOM } = await import("jsdom");
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
pretendToBeVisual: true,
url: "http://localhost",
});
globalThis.document = dom.window.document;
globalThis.window = dom.window as unknown as typeof globalThis & Window;
globalThis.navigator = dom.window.navigator;
globalThis.HTMLElement = dom.window.HTMLElement;
globalThis.HTMLBodyElement = dom.window.HTMLBodyElement;
globalThis.HTMLHtmlElement = dom.window.HTMLHtmlElement;
globalThis.Element = dom.window.Element;
globalThis.getComputedStyle = (element: Element, pseudoElt?: null | string) => {
return dom.window.getComputedStyle(element, pseudoElt ? undefined : pseudoElt);
};
if (!globalThis.document.body) {
const body = globalThis.document.createElement("body");
globalThis.document.documentElement.appendChild(body);
}
const nodeProto = dom.window.Node.prototype;
const elementProto = dom.window.Element.prototype;
const htmlElementProto = dom.window.HTMLElement.prototype;
const attachEventFn = () => {};
const detachEventFn = () => {};
Object.defineProperty(nodeProto, "attachEvent", { configurable: true, value: attachEventFn, writable: true });
Object.defineProperty(nodeProto, "detachEvent", { configurable: true, value: detachEventFn, writable: true });
Object.defineProperty(elementProto, "attachEvent", { configurable: true, value: attachEventFn, writable: true });
Object.defineProperty(elementProto, "detachEvent", { configurable: true, value: detachEventFn, writable: true });
Object.defineProperty(htmlElementProto, "attachEvent", { configurable: true, value: attachEventFn, writable: true });
Object.defineProperty(htmlElementProto, "detachEvent", { configurable: true, value: detachEventFn, writable: true });
globalThis.ResizeObserver = class {
disconnect() {}
observe() {}
unobserve() {}
};
globalThis.MutationObserver = class {
disconnect() {}
observe() {}
takeRecords() {
return [];
}
unobserve() {}
};
globalThis.IntersectionObserver = class {
disconnect() {}
observe() {}
takeRecords() {
return [];
}
unobserve() {}
} as unknown as typeof IntersectionObserver;
globalThis.requestAnimationFrame = (cb: FrameRequestCallback) => setTimeout(cb, 16);
globalThis.cancelAnimationFrame = (id: number) => clearTimeout(id);
Object.defineProperty(dom.window, "matchMedia", {
value: (query: string) => ({
addEventListener: () => {},
addListener: () => {},
dispatchEvent: () => true,
matches: false,
media: query,
onchange: null,
removeEventListener: () => {},
removeListener: () => {},
}),
writable: true,
});
dom.window.Element.prototype.scrollTo = () => {};
dom.window.Element.prototype.scrollIntoView = () => {};
Object.defineProperty(dom.window, "customElements", {
value: {
define: () => {},
get: () => undefined,
},
writable: true,
});
globalThis.customElements = dom.window.customElements;
globalThis.ShadowRoot = class ShadowRoot extends dom.window.DocumentFragment {} as unknown as typeof ShadowRoot;
globalThis.SVGElement = class SVGElement extends dom.window.Element {} as unknown as typeof SVGElement;
globalThis.Selection = class Selection {
addRange() {}
removeAllRanges() {}
} as unknown as typeof Selection;
globalThis.Range = class Range extends dom.window.DocumentFragment {} as unknown as typeof Range;
const { afterEach } = await import("bun:test");
afterEach(() => {
document.body.innerHTML = "";
});