はじめに
Vue v3及び、CompositionAPIで作られたコンポーネントでvee-validate v3系を対象に、Jestでテストを書きます
以下のようなコンポーネントを想定
- validationProviderでinputをvalidate
- validationObserverで各Providerを監視
<template>
<validation-provider mode="eager" rules="required">
<input
v-model="val"
name="input"
>
<ul v-if="errors.length" class="errors">
<li v-for="(error, i) in errors" :key="i">
{{ error }}
</li>
</ul>
</validation-provider>
</template>
<script lang="ts">
export default {
setup(_, { emit }) {
const val = ref<string>('')
watch(() => {
emit('update', val.value)
})
return { val }
}
}
</script>
<template>
<validation-observer ref="observer">
<form>
<child-input @update="update" />
</form>
</validation-observer>
</template>
<script lang="ts">
export default {
setup(_, { emit }) {
const val = ref<string>('')
const update = (value: string) => {
val.value = value
}
return {
val,
update
}
}
}
</script>
テスト
それではテストを書いていきます
import { createLocalVue, mount } from '@vue/test-utils'
import { ValidationObserver, ValidationProvider, extend } from 'vee-validate'
import ParentForm from '@your/path/parent-form.vue'
const localVue = createLocalVue()
localVue.component('ValidationObserver', ValidationObserver)
localVue.component('ValidationProvider', ValidationProvider)
const { required } = require('vee-validate/dist/rules.umd')
extend('required', required)
jest.useFakeTimers()
describe('フォームのバリデーションチェック', () => {
test('未入力でバリデーションされること', async (): Promise<any> => {
const wrapper = mount(ParentForm, { localVue })
const observer: InstanceType<typeof ValidationObserver> = wrapper.vm.$refs.observer
await observer.validate()
jest.runAllTimers()
await wrapper.vm.$nextTick()
expect(wrapper.find('.errors').exists()).toBeTruthy()
})
test('入力が完了すること', async (): Promise<any> => {
const wrapper = mount(ParentForm, { localVue })
wrapper.find('input').setValue('hoge')
const observer: InstanceType<typeof ValidationObserver> = wrapper.vm.$refs.observer
await observer.validate()
jest.runAllTimers()
await wrapper.vm.$nextTick()
expect(wrapper.find('.errors').exists()).toBeFalsy()
})
})
テストの解説
それぞれの処理について見ていきます。
const wrapper = mount(ParentForm, { localVue })
今回は子コンポーネントもテスト対象のためshalowMount
ではなくmount
を利用しています。古い記事を参照するとmount
のオプションに{ sync: false }
を追加するという情報がありますがそのオプションは廃止されています。
https://github.com/vuejs/vue-test-utils/issues/1137
const observer: InstanceType<typeof ValidationObserver> = wrapper.vm.$refs.observer
await observer.validate()
ValidationObserverインスタンスを取得してvalidate
メソッドを実行します。これによってvee-validateのバリデーションが実行されます。
jest.runAllTimers()
ValidationObserverの処理に16msかかるそうで、それを待ちます。
https://logaretm.github.io/vee-validate/advanced/testing.html#testing-validationobserver-debounced-state
await wrapper.vm.$nextTick()
先程{ sync: false }
オプションがなくなったことで画面描画を待つために、$nextTick
を利用します。このメソッドがPromiseを返すためawaitで待つことによってこの後の処理ではDOMに反映された状態を取得することができます。
vee-validate公式ではflush-promises
を使う例を紹介されていますが$nextTickを利用することで同様の結果を得られるので不要になるかと思います。
まとめ
-
sync
オプションはもう使えない -
flush-promises
ではなく$nextTick
を使おう