Closed2

vitest の spyOn で `Cannot assign to read only property` が出た時に無理やり spyOn する方法

ピン留めされたアイテム
uttkuttk

vitest でモジュールを vi.spyOn() した時、Cannot assign to read only property 'xxx' of object みたいなエラーが出る場合があります 👇

import * as react from "react";

// 👺 [Error]: Cannot assign to read only property 'useState' of object '[object Module]'
vi.spyOn(react, "useState");

回避策

このエラーの回避策として vi.mock() を使用して、vi.spyOn() したいオブジェクトを新しいオブジェクトに変換してあげることで、エラーを回避できます 👇

import * as react from "react";

vi.mock("react", async () => {
  const mod = awiat vi.importActual("react"); // 元々のモジュールをimportする
  return { ...mod }; // 新しいオブジェクトを生成して返す
}); 

// ✅ spyOn できるようになります。
vi.spyOn(react, "useState");
uttkuttk

注意点

vi.mock() は巻き上げ処理がされるのですが、以下のようにenableSpyOn関数を作ってモックしても正しく機能しませんでした👇

./helper.ts
export const enableSpyOn = (path: string) => {
  vi.mock(path, async () => ({ ...(await vi.importActual(path)) })
}
./test.ts
import * as react from "react";
import { enableSpyOn } from "./helper";

enableSpyOn("react");

// 👺 [Error]: Cannot assign to read only property 'useState' of object '[object Module]'
vi.spyOn(react, "useState");

知らべてみると、vi.mock() 内の処理では変数を参照できないようでしたので、おそらく直接書くしかなさそうです 👀

If factory is defined, will return its result. Factory function can be asynchronous. You may call vi.importActual inside to get the original module. Since the call to vi.mock is hoisted, you don't have access to variables declared in the global file scope!

このスクラップは2022/11/21にクローズされました