Jest vue/test-utilsの使い方

# VueやJestについて
[前回記事](https://qiita.com/ayadoguchi/items/a12fd8089ecd9baad894
) をご参照ください。


# 環境

- Vue-CLI 3系をインストール済み
- 上記インストール時、UnitTestライブラリーに「Jest」、「TypeScript」を選択済み
- テスト対象のvueファイルを用意した


# ディレクトリ構造

今回は、viewsのSample.vueのテストを書きたいと思います。

```
root/
├ src/
│  ├ api/
│  │  └ request.ts(サーバーサイドのAPIに対する、リクエストメソッドが定義されている)
│  ├ views/
│  │  └ Sample.vue(テスト対象のファイル)
│  └ store.ts（actionsが定義されている）
└ tests/
  └ unit 
    └ Sample.spec.ts（テストを記述するファイル）

```

# Sample.vue(テスト対象のファイル)

`onClickSample()` でstore actionを呼び出します。
リクエストに成功した場合は、`error`を空に、失敗した場合は何等かのエラーメッセージを格納するようになっています。

```vue
<template>
  <div class="page-container">
    <p class="error" v-if="error">{{error}}</p>
    <button type="button" v-on:click="onClickSample">Sample Button</button>
  </div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';

@Component
export default class Sampleextends Vue {
  private error: string = '';
  private async onClickSample(): Promise<any> {
    this.$store.dispatch('sample')
      .then((response) => {
        this.error = '';
      })
      .catch((error) => {
        for (error of error.response.data.error_list) {
          this.error = error.message;
        }
      });
  }
}
</script>

```

# request.ts

サーバーサイドのAPIに対する、リクエストメソッドが定義されています。`/sample` へgetしていますが、このファイル内のテストは今回の対象には含んでおりません。

```typescript 

import axios from 'axios';

axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.baseURL = process.env.VUE_APP_API_ENDPOINT + '/app-name';

export default {
  async sample_get() {
    return axios.get('/sample');
  },
};
```

# store.ts

actionsにsendメソッドを定義しています。ここからrequestファイルのpostメソッドを呼び出してAPIをリクエストしています。

```typescript
import Vue from 'vue';
import Vuex from 'vuex';
import requestfrom './api/request';

Vue.use(Vuex);

export default new Vuex.Store({
  actions: {
    async sample({ commit }) {
      const result = await request.sample_get();
      return result;
    },
  },
});
```

# tests/unit/Sample.spec.ts（テストを記述するファイル）

- 使用しているモジュールやライブラリーはテストファイルでも読み込む必要があります。
vueに関してそのまま使うと、グローバル Vue クラスを汚染してしまうので、`createLocalVue`を使います。
https://vue-test-utils.vuejs.org/ja/api/#createlocalvue

- axiosモジュールを利用する際、実際のAPIにアクセスせずにテストをさせたいので、jestのモックを利用します。`jest.mock('axios')`の記述をすると、モックでaxiosモジュールが利用出来ます。
https://jestjs.io/docs/ja/mock-functions#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E3%83%A2%E3%83%83%E3%82%AF

- beforeEachでactions、store をshallowMountする際に、モックストアとしてコンポーネントと一緒に渡す。
https://vue-test-utils.vuejs.org/ja/guides/using-with-vuex.html

```typescript
// Vueをimportする代わりに、'@vue/test-utils'を使いcreateLocalVue、shallowMount をimportします
import { createLocalVue, shallowMount } from '@vue/test-utils';
// vuexをimport
import Vuex from 'vuex';
// テスト対象ファイル（@/views/Sample.vue）をimportする
import Samplefrom '@/views/Sample.vue';
// axiosをimport
import axios from 'axios';

// モジュールを自動的にモックさせる
jest.mock('axios');

const localVue = createLocalVue();

// localVueでVueXを使える様にする
localVue.use(Vuex);

describe('Sample.vue', () => {

  let wrapper;
  let vm;
  let actions;
  let store;

  describe('success onClickSample', () => {
    beforeEach(() => {
      actions = {
        sample: jest.fn(), // store.tsのsampleメソッドをスタブ
        onClickSample: jest.fn(),// Sample.vueのonClickSampleをスタブ
      },
      store = new Vuex.Store({
        state: {},
        actions,
      });
      // SampleはSample.vueを見ている。モックストア（↑でnewしたstore）をSampleに設定してマウントしている。
      wrapper = shallowMount(Sample, {
        store,
        localVue,
      });
      // Sample.vueの、ViewMountを取得している。it内でvmを使う事が出来る。
      vm = wrapper.vm;
    });

    // errorに文言が入っている状態で、onClickSample()を実行し、リクエスト成功時にerrorが空になるかをテストしている。
    // テストするメソッドがasyncを利用している場合、テスト側もasyncで書かないと動かない。
    it('success: onClickSample() async/await', async () => {
      vm.error= 'エラーが入っていますよ';
      await vm.onClickSample();
      expect(vm.error).toBe('');
    });
  });
});
```


マッチャはこちらでお探しを..
https://jestjs.io/docs/ja/expect