Vue.js を使った画面の入力フォームで、バリデーションの確認をするための単体テストを作成してみました。
*参考
*環境
- MacOS
- Vue 2.9.6
- Vee-validate 2.2.0
- Vue/test-utils 1.0.0-beta.29
- Jest 24.5.0
*Vueプロジェクトの作成
Vueプロジェクトを作成してテストフレームワークのJestを導入します。今回は下記記事の内容を行なった前提で進めていきます。
*Vee-validate の追加
下記コマンドを実行してインストールします。$ npm install vee-validate --save
Vee-validate を使えるようにするために
main.js
に import を追加します。vee-validate
だけだとエラーメッセージが英語になるので、日本語で使えるようにlocale/ja
も import します。<main.js>
import Vue from 'vue'
import App from './App'
import router from './router'
import VeeValidate, { Validator } from 'vee-validate' <--追加
import ja from 'vee-validate/dist/locale/ja' <--追加
Vue.config.productionTip = false
Validator.localize('ja', ja) <--追加
Vue.use(VeeValidate, { locale: ja }) <--追加
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
*入力フォームの実装
日本語と数値の入力フォームにバリデーションを実装してみます。プロジェクト作成時のデフォルトのままだとVueのロゴが各画面に入ってしまうので、App.vue
のロゴ画像を削除します。<App.vue>
<template>
<div id="app">
<img src="./assets/logo.png"> <-- 削除
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
入力フォームを実装するために、新規画面を追加します。
data-vv-as=
に設定した文字列がエラーメッセージの主語に反映されます。validate=
に追加したいバリデーションの種類を設定します。今回は「名前」については必須と最大10桁のチェック、「数値」については必須と数字、1〜15の間チェックを追加しました。<components/Form.vue>
<template>
<div class="form-content">
<div>
<label>名前</label>
<input type="text" name="name1" data-vv-as="名前" v-validate="'required|max:10'"/>
<span v-show="errors.has('name1')" class="alert-label">{{ errors.first('name1') }}</span>
</div>
<div>
<label>数値</label>
<input type="text" name="num1" data-vv-as='数値' v-validate="'required|numeric|between:1,15'" />
<span v-show="errors.has('num1')" class="alert-label">{{ errors.first('num1') }}</span>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.form-content {
margin-left: 100px;
text-align: left;
}
.alert-label {
color: red;
font-size: 12px;
}
</style>
新規作成した画面にアクセスできるようにするため、
index.js
に path を追加します。デフォルトのままだとアクセスした際にURLに「
#
」が入ってしまうので、入らないようにmode: 'history'
の設定を追加します。<router/index.js>
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Form from '@/components/Form' <-- 追加
Vue.use(Router)
export default new Router({
mode: 'history', <-- 追加
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
// ↓追加ここから
{
path: '/form',
name: 'Form',
component: Form
}
// ↑追加ここまで
]
})
下記コマンドを実行してWebアプリケーションを起動します。
npm run dev
入力フォームにエラーになるような値を入力すると、エラーメッセージが表示されます。
*テストを追加
Vueの公式テストライブラリtest-utils
が用意されていて、これを使うと通常よりも少し便利にテストの実装ができるようになります。下記コマンドを実行して
test-utils
をインストールします。npm i @vue/test-utils
デフォルトで作成されている
/test/unit/specs/
ディレクトリに新規ファイルForm.spec.js
を追加します。vee-validate
を使うために、createLocalVue
でグローバルプラグインのコンストラクタを作成する必要があります。テスト1つごとに
it()
で定義し、引数にテスト名を設定します。shallowMount
を使うと子コンポーネントをスタブとして使うことができ、コンポーネントの要素にアクセスできるようになります。また、
sync: false
のオプションを設定することで非同期で描画させることができます。</test/unit/specs/Form.spec.js>
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VeeValidate, { Validator } from 'vee-validate'
import Form from '@/components/Form'
import ja from "vee-validate/dist/locale/ja";
// Vueコンストラクタを作成
const localVue = createLocalVue()
Validator.localize('ja', ja)
// プラグインをインストール
localVue.use(VeeValidate, { locale: ja })
describe('Form.vue', () => {
// バリデーションエラーのテスト開始
it('validate required error message', async () => {
// コンポーネントのスタブを作成
const wrapper = shallowMount(Form, { localVue, sync: false })
// 要素に値を設定
wrapper.find('[name="name1"]').setValue('')
wrapper.find('[name="num1"]').setValue('')
// バリデートを実行
await wrapper.vm.$validator.validateAll()
// 実行結果の確認
expect(wrapper.vm.errors.first('name1')).toEqual('名前は必須項目です')
expect(wrapper.vm.errors.first('num1')).toEqual('数値は必須項目です')
})
})
下記コマンドを実行してテストを実施します。
$ npm run unit
実行結果が出力され、カバレッジを見ることができます。
PASS test/unit/specs/Form.spec.js
Form.vue
✓ validate required error message (39ms)
PASS test/unit/specs/HelloWorld.spec.js
HelloWorld.vue
✓ should render correct contents (9ms)
----------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
HelloWorld.vue | 100 | 100 | 100 | 100 | |
----------------|----------|----------|----------|----------|-------------------|
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.877s
Ran all test suites.
*所感
バリデーションのテストケースを異なるパターンで大量に書くと見辛くなるので、もう少し綺麗に書く方法を見つけたいです。バリデーションのテスト以外にもAPIをモックにする方法なども試してみたいと思います。
Sign up here with your email
ConversionConversion EmoticonEmoticon