setupTests.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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. constructor(family, source, descriptors) {
  33. this.family = family;
  34. this.source = source;
  35. this.descriptors = descriptors;
  36. this.status = "unloaded";
  37. }
  38. load() {
  39. this.status = "loaded";
  40. }
  41. },
  42. });
  43. Object.defineProperty(document, "fonts", {
  44. value: {
  45. load: vi.fn().mockResolvedValue([]),
  46. check: vi.fn().mockResolvedValue(true),
  47. has: vi.fn().mockResolvedValue(true),
  48. add: vi.fn(),
  49. },
  50. });
  51. Object.defineProperty(window, "EXCALIDRAW_ASSET_PATH", {
  52. value: `file://${__dirname}/`,
  53. });
  54. vi.mock(
  55. "./packages/excalidraw/fonts/ExcalidrawFont",
  56. async (importOriginal) => {
  57. const mod = await importOriginal<
  58. typeof import("./packages/excalidraw/fonts/ExcalidrawFont")
  59. >();
  60. const ExcalidrawFontImpl = mod.ExcalidrawFont;
  61. return {
  62. ...mod,
  63. ExcalidrawFont: class extends ExcalidrawFontImpl {
  64. public async getContent(): Promise<string> {
  65. const url = this.urls[0];
  66. if (url.protocol !== "file:") {
  67. return super.getContent(new Set());
  68. }
  69. // read local assets directly, without running a server
  70. const content = await fs.promises.readFile(url);
  71. return `data:font/woff2;base64,${content.toString("base64")}`;
  72. }
  73. },
  74. };
  75. },
  76. );
  77. vi.mock("nanoid", () => {
  78. return {
  79. nanoid: vi.fn(() => "test-id"),
  80. };
  81. });
  82. // ReactDOM is located inside index.tsx file
  83. // as a result, we need a place for it to render into
  84. const element = document.createElement("div");
  85. element.id = "root";
  86. document.body.appendChild(element);
  87. const _consoleError = console.error.bind(console);
  88. console.error = (...args) => {
  89. // the react's act() warning usually doesn't contain any useful stack trace
  90. // so we're catching the log and re-logging the message with the test name,
  91. // also stripping the actual component stack trace as it's not useful
  92. if (args[0]?.includes("act(")) {
  93. _consoleError(
  94. yellow(
  95. `<<< WARNING: test "${
  96. expect.getState().currentTestName
  97. }" does not wrap some state update in act() >>>`,
  98. ),
  99. );
  100. } else {
  101. _consoleError(...args);
  102. }
  103. };