setupTests.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // vitest.setup.ts
  2. import "vitest-canvas-mock";
  3. import "@testing-library/jest-dom";
  4. import fs from "fs";
  5. import { vi } from "vitest";
  6. import polyfill from "./packages/excalidraw/polyfill";
  7. import { testPolyfills } from "./packages/excalidraw/tests/helpers/polyfills";
  8. import { yellow } from "./packages/excalidraw/tests/helpers/colorize";
  9. Object.assign(globalThis, testPolyfills);
  10. require("fake-indexeddb/auto");
  11. polyfill();
  12. Object.defineProperty(window, "matchMedia", {
  13. writable: true,
  14. value: vi.fn().mockImplementation((query) => ({
  15. matches: false,
  16. media: query,
  17. onchange: null,
  18. addListener: vi.fn(), // deprecated
  19. removeListener: vi.fn(), // deprecated
  20. addEventListener: vi.fn(),
  21. removeEventListener: vi.fn(),
  22. dispatchEvent: vi.fn(),
  23. })),
  24. });
  25. Object.defineProperty(window, "FontFace", {
  26. enumerable: true,
  27. value: class {
  28. private family: string;
  29. private source: string;
  30. private descriptors: any;
  31. private status: string;
  32. private unicodeRange: string;
  33. constructor(family, source, descriptors) {
  34. this.family = family;
  35. this.source = source;
  36. this.descriptors = descriptors;
  37. this.status = "unloaded";
  38. this.unicodeRange = "U+0000-00FF";
  39. }
  40. load() {
  41. this.status = "loaded";
  42. }
  43. },
  44. });
  45. Object.defineProperty(document, "fonts", {
  46. value: {
  47. load: vi.fn().mockResolvedValue([]),
  48. check: vi.fn().mockResolvedValue(true),
  49. has: vi.fn().mockResolvedValue(true),
  50. add: vi.fn(),
  51. },
  52. });
  53. Object.defineProperty(window, "EXCALIDRAW_ASSET_PATH", {
  54. value: `file://${__dirname}/`,
  55. });
  56. // mock the font fetch only, so that everything else, as font subsetting, can run inside of the (snapshot) tests
  57. vi.mock(
  58. "./packages/excalidraw/fonts/ExcalidrawFontFace",
  59. async (importOriginal) => {
  60. const mod = await importOriginal<
  61. typeof import("./packages/excalidraw/fonts/ExcalidrawFontFace")
  62. >();
  63. const ExcalidrawFontFaceImpl = mod.ExcalidrawFontFace;
  64. return {
  65. ...mod,
  66. ExcalidrawFontFace: class extends ExcalidrawFontFaceImpl {
  67. public async fetchFont(url: URL): Promise<ArrayBuffer> {
  68. if (!url.toString().startsWith("file://")) {
  69. return super.fetchFont(url);
  70. }
  71. // read local assets directly, without running a server
  72. const content = await fs.promises.readFile(url);
  73. return content.buffer;
  74. }
  75. },
  76. };
  77. },
  78. );
  79. vi.mock("nanoid", () => {
  80. return {
  81. nanoid: vi.fn(() => "test-id"),
  82. };
  83. });
  84. // ReactDOM is located inside index.tsx file
  85. // as a result, we need a place for it to render into
  86. const element = document.createElement("div");
  87. element.id = "root";
  88. document.body.appendChild(element);
  89. const _consoleError = console.error.bind(console);
  90. console.error = (...args) => {
  91. // the react's act() warning usually doesn't contain any useful stack trace
  92. // so we're catching the log and re-logging the message with the test name,
  93. // also stripping the actual component stack trace as it's not useful
  94. if (args[0]?.includes?.("act(")) {
  95. _consoleError(
  96. yellow(
  97. `<<< WARNING: test "${
  98. expect.getState().currentTestName
  99. }" does not wrap some state update in act() >>>`,
  100. ),
  101. );
  102. } else {
  103. _consoleError(...args);
  104. }
  105. };