aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 16:19:36 -0400
committerkj_sh6042026-03-15 16:19:36 -0400
commit673d272f6b16ae4da3851cd19705e5ca86748041 (patch)
tree9d8fd24e7b2e4cc374977ffa37654494f1a60988
parent72ece7c00b091011617fccf719df7f602cf4f7c7 (diff)
refactor: setupTests.ts
-rw-r--r--setupTests.ts122
1 files changed, 122 insertions, 0 deletions
diff --git a/setupTests.ts b/setupTests.ts
new file mode 100644
index 0000000..20d2cc5
--- /dev/null
+++ b/setupTests.ts
@@ -0,0 +1,122 @@
+// vitest.setup.ts
+import "vitest-canvas-mock";
+import "@testing-library/jest-dom";
+import fs from "fs";
+import { vi } from "vitest";
+import polyfill from "./packages/excalidraw/polyfill";
+import { testPolyfills } from "./packages/excalidraw/tests/helpers/polyfills";
+import { yellow } from "./packages/excalidraw/tests/helpers/colorize";
+
+// mock for pep.js not working with setPointerCapture()
+HTMLElement.prototype.setPointerCapture = vi.fn();
+
+Object.assign(globalThis, testPolyfills);
+
+require("fake-indexeddb/auto");
+
+polyfill();
+
+Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: vi.fn().mockImplementation((query) => ({
+ matches: false,
+ media: query,
+ onchange: null,
+ addListener: vi.fn(), // deprecated
+ removeListener: vi.fn(), // deprecated
+ addEventListener: vi.fn(),
+ removeEventListener: vi.fn(),
+ dispatchEvent: vi.fn(),
+ })),
+});
+
+Object.defineProperty(window, "FontFace", {
+ enumerable: true,
+ value: class {
+ private family: string;
+ private source: string;
+ private descriptors: any;
+ private status: string;
+ private unicodeRange: string;
+
+ constructor(family, source, descriptors) {
+ this.family = family;
+ this.source = source;
+ this.descriptors = descriptors;
+ this.status = "unloaded";
+ this.unicodeRange = "U+0000-00FF";
+ }
+
+ load() {
+ this.status = "loaded";
+ }
+ },
+});
+
+Object.defineProperty(document, "fonts", {
+ value: {
+ load: vi.fn().mockResolvedValue([]),
+ check: vi.fn().mockResolvedValue(true),
+ has: vi.fn().mockResolvedValue(true),
+ add: vi.fn(),
+ },
+});
+
+Object.defineProperty(window, "EXCALIDRAW_ASSET_PATH", {
+ value: `file://${__dirname}/`,
+});
+
+// mock the font fetch only, so that everything else, as font subsetting, can run inside of the (snapshot) tests
+vi.mock(
+ "./packages/excalidraw/fonts/ExcalidrawFontFace",
+ async (importOriginal) => {
+ const mod = await importOriginal<
+ typeof import("./packages/excalidraw/fonts/ExcalidrawFontFace")
+ >();
+ const ExcalidrawFontFaceImpl = mod.ExcalidrawFontFace;
+
+ return {
+ ...mod,
+ ExcalidrawFontFace: class extends ExcalidrawFontFaceImpl {
+ public async fetchFont(url: URL): Promise<ArrayBuffer> {
+ if (!url.toString().startsWith("file://")) {
+ return super.fetchFont(url);
+ }
+
+ // read local assets directly, without running a server
+ const content = await fs.promises.readFile(url);
+ return content.buffer;
+ }
+ },
+ };
+ },
+);
+
+vi.mock("nanoid", () => {
+ return {
+ nanoid: vi.fn(() => "test-id"),
+ };
+});
+// ReactDOM is located inside index.tsx file
+// as a result, we need a place for it to render into
+const element = document.createElement("div");
+element.id = "root";
+document.body.appendChild(element);
+
+const _consoleError = console.error.bind(console);
+console.error = (...args) => {
+ // the react's act() warning usually doesn't contain any useful stack trace
+ // so we're catching the log and re-logging the message with the test name,
+ // also stripping the actual component stack trace as it's not useful
+ if (args[0]?.includes?.("act(")) {
+ _consoleError(
+ yellow(
+ `<<< WARNING: test "${
+ expect.getState().currentTestName
+ }" does not wrap some state update in act() >>>`,
+ ),
+ );
+ } else {
+ _consoleError(...args);
+ }
+};