0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】vi.hoisted()が難しかったので使い方をメモ

0
Posted at

個人開発しているNext.jsのフルスタックアプリを用いて、VitestとReact Testing Libraryを使ったコンポーネントテストの方法を自習しました。

その中で、Vitestのモックを調べていたときにvi.hoisted()が出てきました。こちらが少し分かりにくかったので、備忘録としてまとめます。

vi.hoisted()とは

vi.hoisted()は、vi.mock()の中で使いたい値を、vi.mock()より先に用意するためのものです。

特に、モックした関数をテスト側で確認したいときによく使います。

const { mockPush } = vi.hoisted(() => ({
  mockPush: vi.fn(),
}))

vi.fn()vi.mock()って何だっけ

vi.fn()

vi.fn()は、偽物の関数を作るためのものです。
後から返り値を決めたり、何回呼ばれたか、どんな引数で呼ばれたかを確認したりできます。

const saveUser = vi.fn()

saveUser.mockResolvedValue({ id: '1' }) // mockResolvedValue(): 「Promiseが成功したときの返り値」を設定する関数

await saveUser({ name: 'Taro' })

expect(saveUser).toHaveBeenCalledWith({ name: 'Taro' }) // toHaveBeenCalledWith(): 指定した引数で関数が呼ばれたかを確認する関数

vi.mock()

vi.mock()は、モジュールごと偽物に差し替えるためのものです。vi.fn()が関数単位のモックなのに対して、vi.mock()はファイルからimportしている関数や値をまとめて差し替えられます。

この例では、@/authから読み込むauthsignInsignOutをすべてvi.fn()に置き換えています。
そのため、テスト中にこれらの関数が呼ばれても、本来の認証処理は実行されません。

vi.mock("@/auth", async () => {
  return {
    auth: vi.fn(),
    signIn: vi.fn(),
    signOut: vi.fn(),
  };
});

vi.mock()は見た目より先に実行される

ここがvi.hoisted()を使う理由です。

Vitestでは、vi.mock()はファイルの先頭へ移動して実行されます。つまり、テストコードでは他の値を先に書いても、先にvi.mock()が実行されます。

たとえば、次のように書くとします。

const mockPush = vi.fn()

vi.mock('next/navigation', () => ({
  useRouter: () => ({
    push: mockPush,
  }),
}))

mockPushを先に書いているので問題なさそうに見えます。しかしvi.mock()が先に実行されるため、モックの生成時点ではmockPushがまだ使えず、エラーになります。

vi.hoisted()で先にモック関数を作る

そこで、vi.mock()の中で使うvi.fn()vi.hoisted()で作ります。

const { mockAuth } = vi.hoisted(() => ({
  mockAuth: vi.fn(),
}))

vi.mock('@/auth', () => ({
  auth: mockAuth,
}))

mockAuth.mockResolvedValue({ user: { name: 'Taro' } })

こうすることで、
vi.hoisted()で作ったmockAuthは、vi.mock()より先に用意されます。そのため、auth部分の関数と、テストで返り値を決める関数に、同じmockAuthを使えます。

まとめ

英語でhoistは、「上に吊り上げる」という意味のようです。

Vitestではvi.mock()自体も上に移動して実行されます。vi.hoisted()は、vi.mock()より前に実行されるように上へ持っていくためのもの、と考えると覚えやすかったです。

テストを書くときにおそらく忘れるので、またこの記事に戻って思い出せるように書きました。

参考:
Vitest テストAPIリファレンス
フロントエンド単体テスト入門 [vitestハンズオン]
フロントエンドテスト入門 Part 2 — Reactコンポーネントを実際にテストしてみよう

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?