VitestのspyOnは同一ファイルの別関数をモックできない
375 words
2min read
vi.spyOn とは
vi.spyOn を用いると、vi.mock と異なり部分的なモックが可能。そのためプライベートメソッドやプリミティブなメソッドをモックすることもできる。
jest.spyOn(window, "fetch").mockImplementation((...args) => { console.warn("window.fetch is not mocked for this call", ...args); throw new Error("This must be mocked!");});
spy と付いているが、返り値は vi.fn()であり、スパイではなくモックとして使われていることが多い。
同一ファイルの別関数をモックできない
次のようなコードを実行すると TypeError: Cannot redefine property
エラーが出る。
import * as example from "./example";
vi.spyOn(example, "message").mockImplementationOnce(() => "hello");
it("test", () => { expect(example.greet()).toBe("hello");});
Jest で同一のコードを記述すると問題なく実行できる。正確には、Jest でも esbuild/swc を利用する場合、同様のエラーが出る。
Vitest と Jest でなぜ違うか
esbuild/swc と、tsc/babel の esm→cjs 変換方法の違いによって発生している。tsc/babel では exports.someMethod を呼ぶのに対して、esbuild/swc では、standalone なメソッドをコールするため、同一ファイルにある別関数をモックできなくなる。
Vitest spyOn has different behaviour than jest’s · Issue #1329 · vitest-dev/vitest
どうすればいいか
これは Vitest の問題であるとは言い難く、そもそも同一ファイルの別関数をモックすることは、テストの設計上あまり推奨されないため、メソッドを別ファイルに分けることを推奨する。
全く推奨しないが、class やオブジェクトにモックするものをまとめるという手段も存在する。