なんかいろいろと書いてくブログ

関東のどこかで働く、一般人

【Vue】vue-test-utils でVDialogを置き換える

Vutifyを使用しているVueプロジェクトで
vue-test-utils を用いてVueインスタンスをマウントする際に
Vutifyで提供されている一部コンポーネントが正常に動かないことがままある

v-dialogコンポーネントもその一つで、
マウントしたインスタンス内では表示されず、
対応するには、v-dialogのモックを作成してマウント時にラップする必要があった

VDialogMock.vue

以下のモックはVue2.xでComposition APIで作成している

<!-- propによって表示切り替えされるスロットが存在するだけの簡単なモック -->
<template>
    <div>
        <slot v-if="isOpen" /> 
        <slot name="activator" />  
    </div>
</template>  
  
<script lang="ts">  
import { computed, defineComponent, SetupContext } from '@nuxtjs/composition-api'  

export default defineComponent({  
  props: {  
    value: { type: Boolean, required: true }
  },  
  setup (props, context: SetupContext) {  
    const isOpen = computed({  
      get: () => props.value,  
      set: (value: boolean) => context.emit('input', value)  
    })  
    return {  
      isOpen  
    }  
  }  
})  
</script>

spec.ts

spec.ts内ではmount時にstubを指定する

const localVue = createLocalVue()
const vuetify = new Vuetify()  

const wrapper = mount(Component, {
    localVue,
    vuetify,
    stubs: {
        // 使用しているカスタムタグをStubに指定
        'v-dialog': VDialogMock,  
        'VDialog': VDialogMock,  
    }
})

VDialogがマウントしたインスタンス内で表示されない原因は
おそらく、VDialogは条件がtrueになった時にattachで指定がなければ id=appの下にレンダリングされる仕様だったので、おそらくそれが原因

追記

vue-utile-testのGithubないで以下のIssueを見かけた https://github.com/vuejs/vue-test-utils/issues/1333

内容的には、mountオプションのattachTodata-app属性を追加したdiv要素を指定するもの
(議論の最中に登場するattachToDocumentは2023年現在では非推奨になっている)
この方法はVDialogをstubにしなくてよいし、
VDialogの仕様にも沿っているのでこちらのほうがよさそう

const div = document.createElement('div')
div.setAttribute('data-app', 'true')

const wrapper = mount(Component, {
    localVue,
    vuetify,
    // <div data-app='true'>配下にVueComponentを配置
    attachTo: div
})

参考

Dialog component — Vuetify (vuetifyjs.com) How to test UX of v-dialog (Vuetify) components which is not appears in wrapper? - Get Help - Vue Forum (vuejs.org)

vuetify/index.ts at 1b22a664b2ebe5f7cd8a385a0b54968ed20dede5 · vuetifyjs/vuetify · GitHub