【Vitest】vi.mockで巻き上げられる時はvi.hoistedを使う

vi.mockでモジュールをモック化する際、対象モジュールの同じ関数に対して複数回モックを定義する場合などは巻き上げを考慮する必要がある。

it('"foo"を返すこと', () => {
vi.mock('./utils', () => ({
someFunc: () => 'foo',
}));
expect(someFunc()).toBe('foo'); // AssertionError: expected 'bar' to be 'foo'
});
it('"bar"を返すこと', () => {
vi.mock('./utils', () => ({
someFunc: () => 'bar',
}));
expect(someFunc()).toBe('bar');
});

例えば上記のようにテストケース毎にsomeFuncモックの振る舞いを定義する場合、巻き上げにより定義順に関係なく最後に定義したもので上書きされてしまう。

解決法

const someFuncMock = vi.hoisted(() => vi.fn());
vi.mock('./utils', () => ({
someFunc: someFuncMock,
}));
it('"foo"を返すこと', () => {
someFuncMock.mockReturnValue('foo');
expect(someFunc()).toBe('foo');
});
it('"bar"を返すこと', () => {
someFuncMock.mockReturnValue('bar');
expect(someFunc()).toBe('bar');
});

vi.hoisted()でモックを初期化し、vi.mock()のファクトリ関数から返すようにする。モックの振る舞いは各テストケース内で定義する。

1

参考
  1. Vitest の vi.mock は巻き上げられる