Vuetify + Veevalidate 3 + Jest(test:unit) を動くところまでもってく

#Vuetify

本家のドキュメントのtestに関する章を参照
https://vuetifyjs.com/ja/getting-started/unit-testing/

Vuetifyの組み込み方は、specの最初に、次のように書く。

```javascript
import Vue from 'vue'
import Vuetify from 'vuetify'
Vue.use(Vuetify)
```

本家のドキュメントに次のような記述がありますが、この方法でlocalVueにvuetifyを読み込んでもうまくいきませんでした。

```javascript
  //うまくいかなかった方法
  let vuetify

  beforeEach(() => {
    vuetify = new Vuetify()
  })

  it('should have a custom title and match snapshot', () => {
    const wrapper = mount(CustomCard, {
      localVue,
      vuetify,
      propsData: {
        title: 'Foobar',
      },
    })
```

#Veevalidate

今回使用したのはVeevalidate 3.3.9 です。2系だと記述が違うので気を付けてください。

本家のドキュメントのtestに関する章を参照
https://logaretm.github.io/vee-validate/advanced/testing.html#asynchronous-testing

次のような記述例がありますが、$refを使った方法はうまく動作しませんでした（テンプレートもドキュメントと同じものにしてみたんですが…）

```javascript
const error = wrapper.vm.$refs.provider.errors[0];
```
実際のinputやエラーを出力するDOMを見つけて値セットしたり、エラーメッセーを確認する方法は動作しました。以下の方法を参照してください。

##値のセット方法

次のテンプレートの場合

```javascript
<ValidationProvider name="email" v-slot="{ errors }" id="ID1" rules="required|email">
<v-text-field
  id="input_email"
  v-model="email"
  :error-messages="errors"
  label="E-mail"
  required
></v-text-field>
</ValidationProvider>
```
次のような方法で、値をセットして、エラーメッセージを確認できます

###inputにIDを付けて直接見つける方法

```javascript
wrapper.find('input_email').setValue('aaa');
```
###ValiidationProviderにIDを付けて見つける方法
(エラー出力を得る方法と統一できるのでお勧め）

```javascript
wrapper.find('#ID1').find('input').setValue('aaa');
```

###バリデーション結果のチェック方法

```javascript
const errorEl = wrapper.find('#ID1').find('.v-messages__message');
expect(errorEl.text()).toBe('Email must be valid');
```


##Vuetifyが組み込まれているかの確認方法

どこまで動作してるのか全く掴めず、デバックに非常に苦労しました。
Vuetifyが取り込まれていないとレンダリングが実行されず、バリデーションの動作が成功するはずもありません。
動作確認として、次のコードを含んだテストを実行して、作成されたスナップショットファイルを確認する（スナップショットファイルが存在しない時は、結果をファイルに保存する動作になる。存在する時は、比較する動作）のがお勧めです

```javascript
expect(wrapper.html()).toMatchSnapshot()
```

※余談
スナップショットを更新（正解データを更新する）時には、次のコマンドを実行

```bash
npm run test:unit -- --updateSnapshot
```


# エラーと対処方

```
SyntaxError: Unexpected token 'export'
```
Veevalidateや、Vuetifyのモジュールの中で、SyntaxErrorが出ます。
これは、jestがTypescriptの記述を認識していないために発生しています。
paclage.jsonのtransformIgnorePatternsに"<rootDir>/node_modules"のtransformを行わない設定がある為に起きています。この行を削除するか、次の例のように、vurtifyとvee-validateディレクトリは除く記述にします。

```json
  "jest": {
    "transformIgnorePatterns": [
      "<rootDir>/node_modules/(?!(vuetify|vee-validate))"
    ],
    "preset": "@vue/cli-plugin-unit-jest"
  }
```
#specファイル全体

```javascript
import Vue from 'vue'
import Vuetify from 'vuetify'
Vue.use(Vuetify)

import flushPromises from 'flush-promises';
import { mount, createLocalVue } from '@vue/test-utils'
const localVue = createLocalVue()

import AddEmail from '@/views/AddEmail.vue'

describe('AddEmail.vue', () => {
  // バリデーションエラーのテスト開始
  const mount_AddEmail = function() {
    return mount(AddEmail, {
      localVue,
      sync: false
    })
  }
  
  it('snapshot check', async () => {
    const wrapper = mount_AddEmail()
    expect(wrapper.html()).toMatchSnapshot()
  })
  it('dupcheck error if input "mike" in input of name', async () => {
    const wrapper = mount_AddEmail()
    wrapper.find('#ID2').find('input').setValue('mike');    
    await flushPromises();
    const errorEl = wrapper.find('#ID2').find('.v-messages__message');
    expect(errorEl.text()).toBe('同じ名前は登録できません');
  })
  it('email address format check', async () => {
    const wrapper = mount_AddEmail()
    wrapper.find('#ID1').find('input').setValue('aaa');    
    await flushPromises();
    const errorEl = wrapper.find('#ID1').find('.v-messages__message');
    expect(errorEl.text()).toBe('Email must be valid');
  })
  it('required condition of name', async () => {
    const wrapper = mount_AddEmail()
    wrapper.find('#ID2').find('input').setValue('');    
    await flushPromises();
    const errorEl = wrapper.find('#ID2').find('.v-messages__message');
    expect(errorEl.text()).toBe('name can not be empty');
  })
  it('required condition of email', async () => {
    const wrapper = mount_AddEmail()
    wrapper.find('#ID1').find('input').setValue('');    
    await flushPromises();
    const errorEl = wrapper.find('#ID1').find('.v-messages__message');
    expect(errorEl.text()).toBe('email can not be empty');
  })
})
```