🧑‍🍳

Nuxt3でVue-Test-Utilsで非同期コンポーネントのテストメモ

2024/03/06に公開

はじめに

Nuxt3で非同期コンポーネントをテストする際に詰まった点があるので、自分用にメモレベルで残しておく。

事前情報

バージョン情報

  • vitest: 1.3.1
  • @vue/test-utils: 2.4.4
  • unplugin-auto-import: 0.17.5
  • unplugin-auto-component: 0.26.0

コンポーネント情報

  • setup内でAPI通信を行なっておりそこでgetした情報をデータに反映させている
  • 内部に何個かの子コンポーネントがある
  • 子コンポーネントに対してpropsしているデータにはcomposableの関数を使用して引き渡しているものあり  例: :data=useComposable(data2)
  • 内部で状態管理としてpiniaを使用

詰まった点

①Vue-Test-Utilsで非同期コンポーネントでマウントできない

問題点

非同期コンポーネントをマウントした際にマウントしたものが空になる。また、async awaitを使ってもうまく動作しなかった。

解決方法

公式ドキュメントにも記載あるとおりSuspenseで対象コンポーネントを囲んだコンポーネントテストファイル内で作成しそいつをマウントさせる必要があった。
(ただそうなるとshallowmountができないのでは?と思う。)

テストファイル
import TestA from '@/components/TestA'

// ラップしたコンポーネント
const SuspenseTestA = defineComponent({
    name: 'Test',
    components: {
      TestA
    },
    props: ['label'],
    template: `<Suspense><TestA label="label" /></Suspense>`,
  },
)

 // マウント時
const wrap = mount(SuspenseTestA, {
      props: {label: 'ラベル'},
});

②上記ラップしたコンポーネントをfindComponentで取得できない

問題点

以下のようにfindComponentで取得してもundefinedとなる。

テストファイル
const wrap = mount(SuspenseTestA, {
      props: {label: 'ラベル'},
});
const testA = wrap.findComponent(TestA)
console.log(TestA) // undefined

解決方法

これも公式にある通りflushPromises()を使用する。
どうやらDOMだけではなく、Componentのsetup完了まで識別してくれるらしい。
以下例。

テストファイル
// 以下追加
import { flushPromises } from '@vue/test-utils'

const wrap = mount(SuspenseTestA, {
      props: {label: 'ラベル'},
});
// 以下追加
await flushPromises()
const testA = wrap.findComponent(TestA)
console.log(TestA) // OK

③piniaの部分でエラーがでた

問題点

以下エラーが表示される。

Error: [:pineapple:]: "getActivePinia()" was called but there was no active Pinia. Did you forget to install pinia?

解決方法

まずはvitst.config.js(nuxt.config)側で以下を追加。

vitest.config.js
AutoImport({
      imports: [
        // 以下追加
        'pinia',
      ]
})

その後に上記にもあるようテストファイル内でのマウントタイミングに以下を追加。

テストファイル
const wrap = mount(SuspenseTestA, {
      props: {label: 'ラベル'},
            // 以下追加
           global: { plugins: [ createPinia() ] }
});

④composableの部分でエラー

問題点

composableで定義している関数が未定義というエラーが表示。

解決方法

unplugin-auto-importでdirsプロパティ単位で定義して解決する。
以下追記。

vitest.config.js
AutoImport({
        // こちらを追記
    dirs: [
        './src/composables/'
    ],
}

⑤子componentsのautoImport部分でエラー

問題点

autoImportしているコンポーネントが未定義というエラーが表示。

解決方法

nplugin-auto-componentでresolverプロパティ単位で定義して解決する。
以下追記。

vitest.config.js

Components({
    // こちらを追記
       resolvers: [
        (componentName: string) => {
          if (componentName === 'PartsRadioButton') {
            return {
              name: 'default',
              as: componentName,
              from: '@/components/parts/RadioButton.vue',
            }
          }
       }
   ]
}

⑤bindしているcomposablesでエラー

問題点

コンポーネント条件に記載した、下記に対して以下エラーが発生。

  • 子コンポーネントに対してpropsしているデータにはcomposableの関数を使用して引き渡しているものあり
エラー文
"_ctx.composableの関数名is not a function"

おそらくはcomposableの関数がsetup内のものだと定義されていない?

解決策

vitest側ではcomposableが定義されたが、Vue-Test-Utils側でcomposableを定義する必要があった。
なので以下のように定義

テストファイル
import { config } from '@vue/test-utils'

config.global.mocks = {
  useGetValue: useGetValue,
}

Discussion