Skip to content

Commit 8cbf406

Browse files
committed
Fix tests broken by Vitest v4 and React 19 upgrades
Vitest v4 changed how vi.fn() handles `new` calls: when a mock has an arrow-function implementation, calling it with `new` now routes through Reflect.construct which rejects arrow functions as constructors. Replace all arrow-function implementations in Image mocks with regular functions. Also fix the duplicate-script-prevention test: in Vitest v4, vi.spyOn on an already-spied method returns the same spy object (shared call history), so the previous appendSpy approach incorrectly counted pre-existing calls. Replaced with mockClear() + re-check on the original spy.
1 parent ae744ae commit 8cbf406

3 files changed

Lines changed: 12 additions & 8 deletions

File tree

tests/OpenCVCanvas.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe('OpenCVCanvas', () => {
6262
it('calls onError when image fails to load', async () => {
6363
// Override Image mock to trigger error instead of load
6464
const OriginalImage = global.Image;
65-
global.Image = vi.fn().mockImplementation(() => {
65+
global.Image = vi.fn(function(this: unknown) {
6666
const img: Partial<HTMLImageElement> = {};
6767
Object.defineProperty(img, 'src', {
6868
set() {
@@ -209,7 +209,7 @@ describe('OpenCVCanvas', () => {
209209
const OriginalImage = global.Image;
210210
const triggers: Array<() => void> = [];
211211

212-
global.Image = vi.fn().mockImplementation(() => {
212+
global.Image = vi.fn(function(this: unknown) {
213213
const img: Partial<HTMLImageElement> = {
214214
naturalWidth: 100,
215215
naturalHeight: 100,

tests/setup.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ HTMLCanvasElement.prototype.getContext = vi.fn(
4242
export function mockImageLoad(naturalWidth = 100, naturalHeight = 100) {
4343
const originalImage = global.Image;
4444

45-
const MockImage = vi.fn().mockImplementation(() => {
45+
// Regular function (not arrow) required: vi.fn() called with `new` in Vitest v4
46+
// passes the constructor call through to the implementation, and arrow functions
47+
// cannot be constructors.
48+
const MockImage = vi.fn(function MockImageImpl(this: unknown) {
4649
const img: Partial<HTMLImageElement> & { _triggerLoad?: () => void; _triggerError?: () => void } = {
4750
naturalWidth,
4851
naturalHeight,

tests/useOpenCV.test.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,22 @@ describe('useOpenCV', () => {
105105
await r1.current.load();
106106
});
107107

108-
// Second hook instance should not inject another script
109-
const appendSpy = vi.spyOn(document.head, 'appendChild');
108+
// Second hook instance should not inject another script.
109+
// In Vitest v4, vi.spyOn on an already-spied method returns the same spy
110+
// object (shared call history), so we verify via the DOM instead.
111+
spy.mockClear();
110112
const { result: r2 } = renderHook(() => useOpenCV({ autoLoad: false }));
111113
await act(async () => {
112114
await r2.current.load();
113115
});
114116

115-
// No new script appended
116-
const scriptAppends = appendSpy.mock.calls.filter(
117+
// No new script appended after the clear point
118+
const scriptAppends = spy.mock.calls.filter(
117119
([node]) => node instanceof HTMLScriptElement,
118120
);
119121
expect(scriptAppends).toHaveLength(0);
120122

121123
spy.mockRestore();
122-
appendSpy.mockRestore();
123124
});
124125
});
125126

0 commit comments

Comments
 (0)