import { JSDOM } from "jsdom"; const dom = new JSDOM( '
', { url: "http://localhost", pretendToBeVisual: true, }, ); // Use Object.defineProperty to avoid getter-only issues Object.defineProperty(globalThis, "window", { value: dom.window, writable: true, configurable: true, }); Object.defineProperty(globalThis, "document", { value: dom.window.document, writable: true, configurable: true, }); Object.defineProperty(globalThis, "navigator", { value: dom.window.navigator, writable: true, configurable: true, }); Object.defineProperty(globalThis, "HTMLElement", { value: dom.window.HTMLElement, writable: true, configurable: true, }); Object.defineProperty(globalThis, "Element", { value: dom.window.Element, writable: true, configurable: true, }); Object.defineProperty(globalThis, "HTMLCanvasElement", { value: dom.window.HTMLCanvasElement, writable: true, configurable: true, }); Object.defineProperty(globalThis, "HTMLInputElement", { value: dom.window.HTMLInputElement, writable: true, configurable: true, }); Object.defineProperty(globalThis, "Event", { value: dom.window.Event, writable: true, configurable: true, }); // Mock URL.createObjectURL for file uploads URL.createObjectURL = () => `blob:http://localhost/${Math.random()}`; URL.revokeObjectURL = () => {}; // Mock matchMedia Object.defineProperty(globalThis, "matchMedia", { value: (query: string) => ({ matches: false, media: query, onchange: null, addListener: () => {}, removeListener: () => {}, addEventListener: () => {}, removeEventListener: () => {}, dispatchEvent: () => true, }), writable: true, configurable: true, }); // Mock ResizeObserver Object.defineProperty(globalThis, "ResizeObserver", { value: class ResizeObserver { observe() {} unobserve() {} disconnect() {} }, writable: true, configurable: true, }); // Mock WebGL context dom.window.HTMLCanvasElement.prototype.getContext = function ( this: HTMLCanvasElement, contextType: string, ) { if (contextType === "webgl" || contextType === "webgl2") { return { canvas: this, getExtension: () => null, getParameter: () => null, createShader: () => ({}), shaderSource: () => {}, compileShader: () => {}, getShaderParameter: () => true, createProgram: () => ({}), attachShader: () => {}, linkProgram: () => {}, getProgramParameter: () => true, useProgram: () => {}, createBuffer: () => ({}), bindBuffer: () => {}, bufferData: () => {}, enable: () => {}, disable: () => {}, clear: () => {}, viewport: () => {}, createTexture: () => ({}), bindTexture: () => {}, texParameteri: () => {}, texImage2D: () => {}, getUniformLocation: () => ({}), getAttribLocation: () => 0, enableVertexAttribArray: () => {}, vertexAttribPointer: () => {}, uniform1f: () => {}, uniform2f: () => {}, uniform3f: () => {}, uniform4f: () => {}, uniformMatrix4fv: () => {}, drawArrays: () => {}, drawElements: () => {}, }; } if (contextType === "2d") { return { canvas: this as HTMLCanvasElement, fillRect: () => {}, clearRect: () => {}, getImageData: () => ({ data: [] }), putImageData: () => {}, createImageData: () => [], setTransform: () => {}, drawImage: () => {}, save: () => {}, restore: () => {}, beginPath: () => {}, moveTo: () => {}, lineTo: () => {}, closePath: () => {}, stroke: () => {}, fill: () => {}, translate: () => {}, scale: () => {}, rotate: () => {}, arc: () => {}, measureText: () => ({ width: 0 }), fillText: () => {}, }; } return null; } as unknown as typeof HTMLCanvasElement.prototype.getContext;