/** * jsdom implements no `CSS` interface at all, and React Aria's collection code * calls `CSS.escape` unguarded when it looks an item up by key * (`react-aria/dist/private/selection/utils.mjs:22`). Without this, opening a * RAC Select or moving between RAC Tabs throws in tests but works in a browser. * * The implementation is CSSOM's `serialize an identifier` algorithm * (https://drafts.csswg.org/cssom/#serialize-an-identifier), not an * approximation: a wrong escape would silently break the key lookups instead of * failing loudly. */ import { configure } from "@testing-library/react"; function escapeIdentifier(value: string): string { let result = ""; for (let index = 0; index < value.length; index += 1) { const code = value.charCodeAt(index); const char = value[index]!; if (code === 0x0000) { result += "�"; } else if ( (code >= 0x0001 && code <= 0x001f) || code === 0x007f || (index === 0 && code >= 0x0030 && code <= 0x0039) || (index === 1 && code >= 0x0030 && code <= 0x0039 && value.charCodeAt(0) === 0x002d) ) { result += `\\${code.toString(16)} `; } else if (index === 0 && code === 0x002d && value.length === 1) { result += `\\${char}`; } else if ( code >= 0x0080 || code === 0x002d || code === 0x005f || (code >= 0x0030 && code <= 0x0039) || (code >= 0x0041 && code <= 0x005a) || (code >= 0x0061 && code <= 0x007a) ) { result += char; } else { result += `\\${char}`; } } return result; } if (globalThis.CSS === undefined) { Object.defineProperty(globalThis, "CSS", { value: { escape: escapeIdentifier }, configurable: true }); } else if (typeof globalThis.CSS.escape !== "function") { globalThis.CSS.escape = escapeIdentifier; } /** * Testing Library retries a `findBy*` query for 1000 ms by default. That is * enough on an idle laptop — the whole suite resolves in well under a second — * but not on a CI runner whose container competes for CPU with a concurrent * zig build: `LocalDnsPage.test.tsx` timed out waiting for its heading while * the page was still suspended on its first query (gates run 516, job 696). * The budget is not the behaviour under test, so it is raised globally rather * than per call; a test that genuinely never resolves still fails, only later. */ configure({ asyncUtilTimeout: 5000 }); /** * jsdom implements no `Element.prototype.scrollTo`, and its `window.scrollTo` is * a stub that logs "Not implemented". The router's scroll restoration calls both * on every navigation, so without these the shell throws into its error boundary * in tests while working in a browser. jsdom has no layout, so a scroll is a * position assignment and nothing more. */ if (typeof Element.prototype.scrollTo !== "function") { Element.prototype.scrollTo = function scrollTo(...args: unknown[]) { const options = (typeof args[0] === "object" ? args[0] : { left: args[0], top: args[1] }) as ScrollToOptions; if (typeof options.top === "number") this.scrollTop = options.top; if (typeof options.left === "number") this.scrollLeft = options.left; } as typeof Element.prototype.scrollTo; } window.scrollTo = function scrollTo(...args: unknown[]) { const options = (typeof args[0] === "object" ? args[0] : { left: args[0], top: args[1] }) as ScrollToOptions; if (typeof options.top === "number") Object.defineProperty(window, "scrollY", { value: options.top, configurable: true }); if (typeof options.left === "number") Object.defineProperty(window, "scrollX", { value: options.left, configurable: true }); } as typeof window.scrollTo;