💚

Nuxt3+VitestでuseStateのテストを書く

2022/08/13に公開

Nuxt3で提供されているuseStateを使用したcomposableのテストを書く必要があり、mockを作成してテストを書きました。vitestを使うことと、テストを書くことの経験が浅いので、もっと良い書き方があるかもしれません。

nuxtは3.0.0-rc.8, vitestは0.21.1を使用しています。

方針

Nuxt3のAuto importsによって各関数等のimportを書かずに済みます。このことを利用して、テストではReference ErrorとなるuseStateを'グローバル関数'としてモックします。

テスト対象

以下のような簡単なcomposableを考えてみます。

useSomething.ts
import { readonly } from 'vue'

export const useSomething = () => {
  const state = useState('something', () => {
    return {
      hoge: true,
    }
  })

  const toggleHoge = () => {
    state.value.hoge = !state.value.hoge
  }

  return {
    state: readonly(state),
    toggleHoge,
  }
}

テストコード

useStateMocknuxt3のuseStateの実装を引っ張ってきて、一部を書き換えています。

useSomething.test.ts
import { describe, vi, test, expect } from 'vitest'
import { reactive, toRef, isRef, Ref } from 'vue'
import { useSomething } from 'composables/useSomething'

describe('useSomething', () => {
  // Nuxtのpayloadの一部をmockする
  const payload = reactive<{ state: Record<string, any> }>({
    state: {},
  })

  // useStateをmockする
  const useStateMock = vi.fn((key: string, init?: () => any) => {
    const state = toRef(payload.state, key)
    if (state.value === undefined && init) {
      const initialValue = init()
      if (isRef(initialValue)) {
        payload.state[key] = initialValue
        return initialValue as Ref<any>
      }
      state.value = initialValue
    }
    return state
  })

  // モックをグローバルに使えるようにする
  vi.stubGlobal('useState', useStateMock)

  test('Stateが取得できる', () => {
    const smth = useSomething()
    expect(smth.state.value).toEqual({ hoge: true })
  })

  test('Stateが変更できる', () => {
    const smth = useSomething()
    smth.toggleHoge()
    expect(smth.state.value).toEqual({ hoge: false })
  })

  test('Stateの変更が共有される', () => {
    const smth = useSomething()
    // NOTE: 一つ前のテストでhogeの値が変わったままのはず
    expect(smth.state.value).toEqual({ hoge: false })
  })
})

Discussion