今回はVue.jsのバリデーションライブラリである「VeeValidate」とコンポーネントテストライブラリの「Vue Test Utils」を使用してコンポーネントテストでバリデーションエラーを検証します。
「VeeValidate」を「Vue Test Utils」で使うためにはいくつか設定を行う必要があるので、記事の前半ではその設定内容を解説し、記事の後半で実際にテストを書いていきます。
設定
「VeeValidate」を「Vue Test Utils」で使用するために、まず以下の設定をjest.config.jsに追加します。
const config = {
setupFiles: ['./tests/setup.js'],
transform: {
'vee-validate/dist/rules': 'babel-jest',
},
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!vee-validate/dist/rules)',
],
}
module.exports = config
次にVeeValidateのコンポーネントを読み込み、ルールをextendします。
setup.jsでもコンポーネントのテストファイルでもどちらに記述してもOKです。
import { ValidationObserver, ValidationProvider, extend } from 'vee-validate'
Vue.component('ValidationProvider', ValidationProvider);
Vue.component('ValidationObserver', ValidationObserver);
// ルールを使用している場合
import { required, email, alpha_num } from 'vee-validate/dist/rules';
extend('required', required)
extend('email', email)
extend('alpha_num', alpha_num)
入力フォームのテスト
それではテストを実装していきます。
今回は、メールアドレス入力フォームでバリデーションを実装していると想定します。
バリデーションルールは、VeeValidateのemail ruleをそのまま使用していますが、入力された文字列がメールアドレスの形式でなければ「有効なメールアドレスではありません」とエラーメッセージが表示されます。
<validation-provider
name="メールアドレス"
:rules="{
email: {},
required: {}
}"
v-slot="{ errors }"
tag="div"
ref="email_provider"
>
<v-text-field
v-model="email"
label="メールアドレス"
hide-details
outlined
autofocus
dense
data-test-id="inputEmail"
></v-text-field>
<div class="input-error-message">{{ errors[0] }}</div>
</validation-provider>
テスト仕様
メールアドレスの入力フォームのテストで確認したいことは下記です。
- コンポーネントをマウントする
- input要素に「e2etest」というメールアドレスではない文字列をセットする
- class=”input-error-message”の要素に「有効なメールアドレスではありません」が表示される
- v-slot=”{ errors }”にエラーメッセージが格納されている
テスト実装
vuetifyやVeeValidateなどの初期設定が正常に行われているのが前提条件ではありますが、下記のテストコードでバリデーションが正常に動作しているかをテストできます。
import Signup from '@/components/pages/auth/Signup.vue'
import Vuetify from 'vuetify'
import { createLocalVue, mount } from '@vue/test-utils'
import flushPromises from 'flush-promises';
describe('入力フォームテスト', () => {
const localVue = createLocalVue()
let vuetify
beforeEach(() => {
vuetify = new Vuetify()
})
it('バリデーションエラー email', async () => {
const wrapper = mount(Signup, {
localVue,
})
wrapper.get('[data-test-id="inputEmail"]').setValue("e2etest")
await flushPromises();
console.log(wrapper.get('.input-error-message').text());
console.log(wrapper.vm.$refs.provider.errors[0]);
expect(wrapper.get('.input-error-message').text()).toBe("有効なメールアドレスではありません");
expect(wrapper.vm.$refs.email_provider.errors[0]).toBe("有効なメールアドレスではありません");
});
});
テスト結果
console.log
有効なメールアドレスではありません
at Object.<anonymous> (tests/unit/auth/Signup.spec.js:153:13)
console.log
有効なメールアドレスではありません
PASS tests/unit/auth/Signup.spec.js
Signup.vue
✓ バリデーションエラー email (106 ms)
✓ バリデーションエラーnull email (51 ms)
○ skipped 初期表示
○ skipped 入力テスト data側 値なし
○ skipped data値あり→input反映
○ skipped input入力→data反映
○ skipped 認証エラーメッセージ data側
Test Suites: 1 passed, 1 total
Tests: 5 skipped, 2 passed, 7 total
Snapshots: 0 total
Time: 0.911 s, estimated 1 s
解説
VeeValidateは非同期で実行される
まずVeeValidateのバリデーションチェックは非同期で実行されます。
つまり、下記のコードでinput要素にデータをセットした後に同期的にバリデーションエラーが表示されるわけではありません。
wrapper.get('[data-test-id="inputEmail"]').setValue("e2etest")
非同期処理が完了してから、エラーメッセージが表示されているかを確認しなければなりません。
非同期処理の完了を待つためには、$nextTickかflushPromisesプラグインを使用します。
今回はflushPromisesを使用して、非同期処理の完了を待ちます。
wrapper.get('[data-test-id="inputEmail"]').setValue("e2etest")
await flushPromises();
expect(wrapper.get('.input-error-message').text()).toBe("有効なメールアドレスではありません");
expect(wrapper.vm.$refs.email_provider.errors[0]).toBe("有効なメールアドレスではありません");
input要素に”e2etest”という文字列をセットして、非同期にDOMが更新されるのを待ちます。
DOMが更新されたら、エラーメッセージを表示する予定のHTML要素に「有効なメールアドレスではありません」が表示されているかを確認します。
ちなみに、VeeValidateのエラーメッセージはwrapper.vm.$refs.ref指定.errors[0]でも取得できます。
より正確にバリデーションエラーを検証するためにも、ダブルでチェックするといいかもしれませんね。
メールアドレスが正常に入力された場合
上記ではエラーをテストしましたが、実際に正しいメールアドレス形式で入力された場合のテストも行いましょう。
確認したいことは下記です。
- コンポーネントをマウントする
- input要素に「example@example.com」というメールアドレスをセットする
- class=”input-error-message”の要素は””(空文字である)
- v-slot=”{ errors }”はundefinedである
it.only('バリデーションエラーnull email', async () => {
const mockFunction = jest.fn();
const wrapper = mount(Signup, {
localVue,
})
wrapper.get('[data-test-id="inputEmail"]').setValue("example@example.com")
await flushPromises();
console.log(wrapper.get('.input-error-message').text());
console.log(wrapper.vm.$refs.provider.errors[0]);
expect(wrapper.get('.input-error-message').text()).toBe("");
expect(wrapper.vm.$refs.provider.errors[0]).toBeUndefined();
});
無事にテストがパスしました。
console.log
at Object.<anonymous> (tests/unit/auth/Signup.spec.js:175:13)
console.log
undefined
at Object.<anonymous> (tests/unit/auth/Signup.spec.js:176:13)
PASS tests/unit/auth/Signup.spec.js
Signup.vue
✓ バリデーションエラー email (90 ms)
✓ バリデーションエラーnull email (46 ms)
○ skipped 初期表示
○ skipped 入力テスト data側 値なし
○ skipped data値あり→input反映
○ skipped input入力→data反映
○ skipped 認証エラーメッセージ data側
Test Suites: 1 passed, 1 total
Tests: 5 skipped, 2 passed, 7 total
Snapshots: 0 total
Time: 0.87 s, estimated 1 s
参照:テストに関する注意事項
この記事は役に立ちましたか?
もし参考になりましたら、下記のボタンで教えてください。
コメント