⚡
Vitestでクラスをmockする
前提条件
まず、vite.config.ts
でglobals: true
に設定していることを前提としています。これは、テストでグローバルにviオブジェクトを使用するための設定です。
Vitestでクラスをモックしたかったのですが、Jestと同様の方法が使えなくて困っていました。
今回はGoogleカレンダーのAPIライブラリをサンプルとして、JestとVitestでの違いを見ていきます。
Jestでのクラスのモック
Jestでは、以下のようにクラスをモックすることができます。
import { calendar_v3 } from "@googleapis/calendar";
jest.mock('@googleapis/calendar');
test("example jest mock", async () => {
const mockCalendar = {
events: {
list: jest.fn(),
},
} as unknown as jest.Mocked<calendar_v3.Calendar>;
(calendar_v3.Calendar as jest.Mock).mockImplementation(() => mockCalendar);
(mockCalendar.events.list as jest.Mock).mockImplementation(() => ({
data: {
items: [
{
start: { dateTime: '2023-05-01T10:00:00+09:00' },
end: { dateTime: '2023-05-01T11:00:00+09:00' },
},
]
}
}));
const calendar = new calendar_v3.Calendar({});
const result = await calendar.events.list();
expect(mockCalendar.events.list).toHaveBeenCalledTimes(1);
});
mockCalendar
をbeforeEach
に配置して、(mockCalendar.events.list as jest.Mock).mockImplementation
をtest内で変更する、というような使い方をしてました。
Vitestでの解決策
Vitestでは、Jestと同じコードがそのまま使えないため、少し異なるモックの方法を用います。
以下のように、vi.mocked
でCalendar
クラスをモックし、mockImplementation
でevents.list
のオブジェクトを返すようにしています。
import { calendar_v3 } from "@googleapis/calendar";
import { MockedObject } from "vitest";
vi.mock('@googleapis/calendar');
test("example vi mock", () => {
const mockCalendar = {
events: {
list: vi.fn().mockResolvedValue({
data: {
items: [
{
start: { dateTime: '2023-05-01T10:00:00+09:00' },
end: { dateTime: '2023-05-01T11:00:00+09:00' },
},
]
}
}),
},
} as unknown as MockedObject<calendar_v3.Calendar>;
vi.mocked(calendar_v3.Calendar).mockImplementation(() => mockCalendar);
const calendar = new calendar_v3.Calendar({});
const result = await calendar.events.list();
expect(mockCalendar.events.list).toHaveBeenCalledTimes(1);
});
試したこと
- jestをviに置き換えたが
vi.mock
の型アサーションが効かない
(calendar_v3.Calendar as typeof vi.mock).mockImplementation(() => mockCalendar);
});
- 公式ドキュメントにあるようにvi.mocked()で囲む
vi.mocked(calendar_v3.Calendar.prototype.events.list).mockImplementation(() => mockCalendar);
class.prototype
のvi.mocked
を試みましたが、Cannot read properties of undefined (reading 'list')
エラーが発生します。
Discussion