I have a number of geometry functions that use DOMPoint
and DOMRect
, which I want to test using jest. The framework is configured to use jsdom
as test environment. Unfortunately, jsdom does not have definitions for DOMPoint
and DOMRect
, hence I need to mock them.
In my setupUnitTests.ts file, which is set as setupFilesAfterEnv
value in jest.config.ts I have this mock call:
Object.defineProperty(globalThis, "DOMPoint", {
writable: true,
enumerable: true,
value: jest.fn().mockImplementation((x?: number, y?: number, z?: number, w?: number) => {
return {
x: x ?? 0,
y: y ?? 0,
z: z ?? 0,
w: w ?? 0,
matrixTransform: jest.fn(),
toJSON: jest.fn(),
};
}),
});
const p = new DOMPoint(1, 2, 3, 4);
The call at the end returns a DOM point instance with the expected values, fine.
In my test spec, however, the DOMPoint
instance is not initialised. The mock implementation function is not called, like it is when I create a DOM point in the setup file. My spec file is very simple:
import { inflateRect, pointInRect, rectsAreEqual } from "../../../utilities/graphics";
describe("Graphics Tests", () => {
it("Rectangles", () => {
const point1 = new DOMPoint(2, 1, 3, 4);
const point2 = new DOMPoint(-95, 3, 4, 1);
const rect1 = new DOMRect(0, 0, 0, 0);
const rect2 = new DOMRect(-100, 0, 10, 10);
const rect3 = new DOMRect(0, 0, 10, 10);
const rect4 = new DOMRect(0, 0, 10, 10);
const rect5 = new DOMRect(-1, -1, 12, 12);
expect(pointInRect()).toBe(false);
expect(pointInRect(point1)).toBe(false);
expect(pointInRect(point1, rect1)).toBe(false);
expect(pointInRect(point1, rect2)).toBe(false);
expect(pointInRect(point2, rect2)).toBe(true);
expect(rectsAreEqual(rect1, rect2)).toBe(false);
expect(rectsAreEqual(rect3, rect4)).toBe(true);
expect(rectsAreEqual(rect4, rect3)).toBe(true);
expect(inflateRect(rect3, 1, 1, 1, 1)).toStrictEqual(rect5);
});
});
What's missing here? Why is the function given to jest.fn().mockImplementation
not called?
The mock itself is definitely used, because when I remove it I get the error about DOMPoint
not being defined.
I then moved the mock to the spec file:
describe("Graphics Tests", () => {
Object.defineProperty(global.self, "DOMPoint", {
writable: true,
enumerable: true,
value: jest.fn().mockImplementation((x?: number, y?: number, z?: number, w?: number) => {
return {
x: x ?? 0,
y: y ?? 0,
z: z ?? 0,
w: w ?? 0,
matrixTransform: jest.fn(),
toJSON: jest.fn(),
};
}),
});
it("Rectangles", () => {
const point1 = new DOMPoint(2, 1, 3, 4);
...
});
});
and found the mock function still not being called (but the mock defined). This is pretty confusing...
While debugging through the Jest code to compare the execution paths between the constructor invocations, I saw that in the spec file I had no mock config anymore (the default was used), which ultimately led me to the solution of my problem. In the jest config file I had set resetMocks: true
, which caused the mocks to be removed. After setting that to false things started working as expected.