本文書はJestとVue Test Utilを利用したVue.jsでのテストに関する2回目の記事で2回目となる今回はテスト入門者にとって少しわかりずらいStub(スタブ)やMock(モック)、Shallow Mountに注目して説明を行っています。

Stub, ShallowMountとMountの違いを説明した後にVue.jsのHTTPリクエストで頻繁に利用されるaxiosのMock(モック)の方法についても説明を行っています。コンポーネントの単体テストでは、axiosライブラリやfetch関数を利用した外部へのアクセスを伴う機能を実装している場合モックを利用することで外部へのアクセスを行うことなくコンポーネントのテストを実施することができます。

Vueでのテストを実施したまたは学習した経験がない人であれば先に前回公開した”【基本編】Jestを利用してVue コンポーネントをテストする方法(Unit Test)”を読んでおくことをお勧めします。

mountとshallowMountの違い

Vueのコンポーネントをテストする場合は必ずテストしたいコンポーネントをマウントする必要があります。

Vue Test Utilsにはコンポーネントをマウントする関数が2つあります。一つはmount関数でもう一つはshallowMount関数です。mountでは子コンポーネントを持っている場合に子コンポーネントも一緒に表示することができますが、shallowMountでは子コンポーネントは一緒に表示されません。

表示するしないという言葉よりも実際に動作確認をすることで簡単に理解をすることができます。mountとshallowMountの違いを確認するためにUser、UserListコンポーネントをcomponentsフォルダに作成します。Userコンポーネントは子コンポーネントにUserListコンポーネントを持ちます。


<template>
  <h1>Vue Test Utilsの使い方</h1>
  <user-list />
</template>
<script>
import UserList from "@/components/UserList"
export default {
  components:{
    UserList,
  }
}
</script>

<template>
  <h2>ユーザ一覧</h2>
</template>

tests/unitフォルダにuser.spec.jsファイルを作成してテストコードを記述します。一つ目のテストはmount関数を利用し二つ目のテストではshallowMount関数を利用しています。wrapperオブジェクトのhtmlメソッドでHTMLの中身を表示させることで違いを確認します。


import { mount, shallowMount } from '@vue/test-utils';
import User from "@/components/User.vue";

describe('User', () => {
  it("mount render a child component",() => {
    const wrapper = mount(User);
    console.log(wrapper.html())
  })
  it("shallowMount not render a child component",() => {
    const wrapper = shallowMount(User);
    console.log(wrapper.html())
  })
})

user.spec.jsファイルを作成後、npm run test:unitコマンドでテストを実施します。


 % npm run test:unit

> vue-unit-test@0.1.0 test:unit
> vue-cli-service test:unit

 PASS  tests/unit/user.spec.js
  User
    ✓ mount render a child component (34ms)
    ✓ shallowMount not render a child component (4ms)

  console.log tests/unit/user.spec.js:7
    <h1>Vue Test Utilsの使い方</h1>
    <h2>ユーザ一覧</h2>

  console.log tests/unit/user.spec.js:11
    <h1>Vue Test Utilsの使い方</h1>
    <user-list-stub></user-list-stub>

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.927s, estimated 2s
Ran all test suites.

shallowMountの場合は子コンポーネントのHTMLではなくstubタグuser-list-stubが表示されています。つまり子コンポーネントがダミーのuser-list-stubタグに置き換えられておりUserListコンポーネントの中に記述されているHTMLタグの内容は表示されません。mountの場合はUserListコンポーネントの中に記述されている内容(<h2>ユーザ一覧</h2>)がそのままUserコンポーネントの中身と一緒に表示されていることが確認できます。

console.logでHTMLの中身を確認しましたが、toContain関数(ユーザ一覧という文字列が含まれているかチェック)を利用してテストを実行することでテストへの影響も確認します。mount関数のテストは先ほど確認した通り子UserListの中身が表示されているのでPASS(成功)しますが、shallowMountはFAIL(失敗)します。


describe('User', () => {
  it("mount render a child component",() => {
    const wrapper = mount(User);
    expect(wrapper.html()).toContain('ユーザ一覧')
  })
  it("mount render a child component",() => {
    const wrapper = shallowMount(User);
    expect(wrapper.html()).toContain('ユーザ一覧')
  })
})
//エラーメッセージの内容の一部
  ● User > mount render a child component

    expect(received).toContain(expected) // indexOf

    Expected substring: "ユーザ一覧"
    Received string:    "<h1>Vue Test Utilsの使い方</h1>
    <user-list-stub></user-list-stub>"

Userコンポーネントのみの単体テストを実施したい場合であればUserListコンポーネントの影響を受けないShallowMountを利用したテストを実施したほうがいいことがわかります。

Stub(スタブ)の設定方法

Vue Test UtilsではStubは実際のコンポーネントの代わりになるダミーのコンポーネントのことです。

mount関数でのStubの設定

shallowMount関数を使った場合は子コンポーネントは自動でStubになっていましたが、mount関数の場合はグローバルオプションを利用することで子コンポーネントをStubにすることができます。グローバルオプションの中で子コンポーネントを置き換えるStubにHTMLを設定することも可能です。


import { mount } from '@vue/test-utils';
import User from "@/components/User.vue";

describe('User', () => {
  it("mount render a child component",() => {
    const wrapper = mount(User,{
      global:{
        stubs:{
          UserList:{
            template:"<h2>Stubで置き換え</h2>"
          }
        }
      }
    });
    console.log(wrapper.html())
  })
})

テストを実行すると置き換えられた子コンポーネントのHTMLが表示されます。UserListには<h2>ユーザ一覧</h2>と記述しているのでStubの設定によって本来に記述されている内容とは全く異なるダミーの内容を表示することができます。


% npm run test:unit

> vue-unit-test@0.1.0 test:unit
> vue-cli-service test:unit

 PASS  tests/unit/user.spec.js
  User
    ✓ mount render a child component (27ms)

  console.log tests/unit/user.spec.js:23
    <h1>Vue Test Utilsの使い方</h1>
    <h2>Stubで置き換え</h2>

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.234s, estimated 2s
Ran all test suites.

StubにダミーのHTMLを設定しない場合はUserListの値にtrueを設定します。テストを実行すると子コンポーネントがuser-list-stubタグに置き換わっていることを確認することができます。


import { mount } from '@vue/test-utils';
import User from "@/components/User.vue";

describe('User', () => {
  it("mount render a child component",() => {
    const wrapper = mount(User,{
      global:{
        stubs:{
          UserList:true
        }
      }
    });
    console.log(wrapper.html())
  })
})
// npm run unit:test実行時の一部
  console.log tests/unit/user.spec.js:24
    <h1>Vue Test Utilsの使い方</h1>
    <user-list-stub></user-list-stub>

shallowプロパティによる設定

マウントオプションにはshallowプロパティがありtrueに設定することですべての子コンポーネントがStubとなります。shallowMount関数を利用した時と同じ動作になります。


describe('User', () => {
  it("mount render a child component",() => {
    const wrapper = mount(User,{
      shallow:true,
    });
    console.log(wrapper.html())
  })
})

ここまでの動作確認でShallowMount, Mountの違いやStubについての理解を深めることができました。

axiosのHTTPリクエストをMockする方法

UserListコンポーネントにユーザ一覧を表示するためには通常axios, fetch関数を利用して外部リソースにアクセスすることで取得します。

axiosがインストールされていない場合はaxiosのインストールを行います。


 % npm install axios

ここでは無料のJSONPlaceHolderからaxiosのgetメソッドを利用してユーザ情報を取得します。JSONPlaceHolderではhttps://jsonplaceholder.typicode.com/usersにアクセスすると10件分のダミーのユーザ情報を取得することができます。


<template>
  <h2>ユーザ一覧</h2>
  <ul>
    <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
</template>
<script>
import axios from "axios"
export default {
  data(){
    return {
      users:[]
    }
  },
  mounted(){
    axios.get('https://jsonplaceholder.typicode.com/users')
    .then(response => {
      this.users = response.data;
    })
  }
}
</script>

ブラウザ上でユーザ一覧が表示されるか確認するためにApp.vueファイルでUserコンポーネントをimportします。


<template>
  <User />
</template>

<script>
import User from './components/User.vue';

export default {
  name: 'App',
  components: {
    User,
  },
};
</script>

npm run serveコマンドを実行してeslintのmulti-word-component-namesが表示された場合は.eslintrcでmulti-word-component-namesを”OFF”にすることでエラーをなくすことができます。コンポーネント名をUserではなくUserListのように複数の単語で組み合わせた名前にすればエラーは発生しません。


  1:1  error  Component name "User" should always be multi-word  vue/multi-word-component-names

rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'vue/multi-word-component-names': 'off', //追加
},

作成したUser, UserListをブラウザ上で確認するとaxiosのgetメソッドで取得したユーザ一覧が表示されます。

ブラウザ上にユーザ一覧表示
ブラウザ上にユーザ一覧表示

UserListコンポーネントでは、実際に外部リソースであるJSONPlaceHolderのサービスにアクセスを行ってユーザ情報を取得していますがテストで実際に外部リソースへのアクセスを行わない場合はmockを利用してテストを行うことができます。

axiosのmock設定

axiosのモジュールをmockするためにjest.mockを利用します。またUserListではaxiosのgetメソッドを使っているのでmock関数のjest.fnを利用します。jest.mockとjest.fnを利用することでテスト中にaxios.getメソッドを実行した場合は設定したMockのgetメソッドが代わりに実行されることになります。

axiosのgetメソッドは実行するとPromiseを返すのでmock関数でもPromise.resolveを利用してユーザの一覧をPromiseで戻しています。


jest.mock('axios', () => ({
  get: jest.fn(() =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Leanne Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    })
  ),
}));
Promise.resolveについてはnew Promise(() => resolove(…))の記述を簡略化したものです。

axiosをMockすることでPromise.resolveで設定したユーザ一覧が表示されるかwapper.html()を利用して確認します。


import { mount } from '@vue/test-utils';
import User from '@/components/User.vue';

jest.mock('axios', () => ({
  get: jest.fn(() =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Leanne Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    })
  ),
}));

describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    console.log(wrapper.html());
  });
});

テストを実行するとexpect関数を利用していないのでテストにはPASSしますが、残念ながらulタグの中には何も表示されません。liにユーザ名が表示されないのはaxiosで設定したユーザ一覧がDOMに反映されていないためです。Mockで設定したデータを反映させるためにflush-promisesパッケージのインストールを行います。


 PASS  tests/unit/user.spec.js
  User
    ✓ mount render a child component (35ms)

  console.log tests/unit/user.spec.js:26
    <h1>Vue Test Utilsの使い方</h1>
    <h2>ユーザ一覧</h2>
    <ul></ul>

flush-promisesパッケージはnpmコマンドを利用してインストールを行います。


 % npm install flush-promises --save-dev

インストールしたflushPromisesをuser.spec.jsファイルに追加します。


import { mount } from '@vue/test-utils';
import User from '@/components/User.vue';
import flushPromises from 'flush-promises';

jest.mock('axios', () => ({
  get: jest.fn(() =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Leanne Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    })
  ),
}));

describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    await flushPromises();
    console.log(wrapper.html());
  });
});

再度テストを実行すると今度はulタグの中にaxiosのMockで設定したユーザ名が表示されることが確認できます。


 PASS  tests/unit/user.spec.js
  User
    ✓ mount render a child component (36ms)

  console.log tests/unit/user.spec.js:26
    <h1>Vue Test Utilsの使い方</h1>
    <h2>ユーザ一覧</h2>
    <ul>
      <li>Leanne Graham</li>
      <li>Ervin Howell</li>
    </ul>

これでmockしたaxiosを利用することで設定したデータがテストの中で表示され、mockしたaxiosをテストで問題なく利用できることが確認できました。

jest.mockの中でモック関数jest.fnを利用していましたが利用するmatchers関数によってはjest.fnを利用せずに下記のように記述することができます。


jest.mock('axios', () => ({
  get: () =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Lee Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    }),
}));

jest.fnを利用する場合としない場合の違いを確認したい場合はテストコードの中でaxios.getを確認すると理解が深まります。jest.fnを利用していない場合を確認します。


jest.mock('axios', () => ({
  get: () =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Lee Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    }),
}));
//略
mount(User);
await flushPromises();
console.log(axios.get);

実行すると関数であることがわかります。


  console.log
    [Function: get]

次にjest.fn()を利用した場合を確認します。


jest.mock('axios', () => ({
  get: jest.fn(() =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Leanne Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    })
  ),
}));
//略
mount(User);
await flushPromises();
console.log(axios.get);

さまざまなメソッドが含まれていることがわかります。この中に含まれているメソッドは後ほどが確認します。


  console.log
    [Function: mockConstructor] {
      _isMockFunction: true,
      getMockImplementation: [Function (anonymous)],
      mock: [Getter/Setter],
      mockClear: [Function (anonymous)],
      mockReset: [Function (anonymous)],
      mockRestore: [Function (anonymous)],
      mockReturnValueOnce: [Function (anonymous)],
      mockResolvedValueOnce: [Function (anonymous)],
      mockRejectedValueOnce: [Function (anonymous)],
      mockReturnValue: [Function (anonymous)],
      mockResolvedValue: [Function (anonymous)],
      mockRejectedValue: [Function (anonymous)],
      mockImplementationOnce: [Function (anonymous)],
      mockImplementation: [Function (anonymous)],
      mockReturnThis: [Function (anonymous)],
      mockName: [Function (anonymous)],
      getMockName: [Function (anonymous)]
    }

toHaveBeenCalled関数などを利用したい場合はmock関数が呼ばれたかのチェックなのでjest.fn()を利用しない場合はエラーになります。

jest.fn()の中身を変更

一部の読者の中にaxiosとPromiseのことがあまり理解できておらず、なぜPromise.resolveを利用しているのかPromise.resolveを利用せずにそのままユーザ一覧の配列を入れた場合はどうなるのかと疑問を持つ人もいるかと思います。理解を深めるために実際にPromise.resloveから配列に変更して再度テストを実施してみましょう。


jest.mock('axios', () => ({
  get: jest.fn(() => [
    { id: 1, name: 'Leanne Graham' },
    { id: 2, name: 'Ervin Howell' },
  ]),
}));

テストを実行すると下記のエラーが発生してテストが途中で失敗します。


    TypeError: _axios.default.get(...).then is not a function

しかし、ライフサイクルメソッドのmountedをaync, await関数を利用して書き換えるとmock関数でPromiseを利用しなくてもユーザ一覧は表示されます。awaitではPromiseが戻ってくることを待っていますが、Promiseが戻ってこない場合はそのままの値を返すためです。


async mounted() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  this.users = response.data;
},

mockのaxiosのテスト方法

UserListコンポーネントで実行されるaxiosについてmatchers関数を使ってテストを行うことができます。

matchers関数であるtoHaveBeenCalledTimes関数ではテスト中にaxiosが何回呼ばれたかのテストを実行することができます。テストを実行するとライフサイクルフックでaxiosは1度だけ呼ばれるのでtoHaveBeenCalledTimesの引数に1と回数を設定することでテストにPASS(成功)します。


import axios from 'axios';
//略
describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    await flushPromises();
    expect(axios.get).toHaveBeenCalledTimes(1);
  });
});

axios.getメソッドが呼ばれたかどうかの確認であればtoHaveBeenCalled関数を利用することができます。


describe('User', () => {
  it("mount render a child component",async() => {
    const wrapper = mount(User);
    await flushPromises()
    expect(axios.get).toHaveBeenCalled()
  })
})

もしaxios.getメソッドが呼ばれなかった場合は下記のエラーが表示されます。


 FAIL  tests/unit/user.spec.js
  User
    ✕ mount render a child component (16ms)

  ● User › mount render a child component

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      19 |     // console.log(wrapper.html())
      20 |     // expect(axios.get).toHaveBeenCalledTimes(1)
    > 21 |     expect(axios.get).toHaveBeenCalled()
         |                       ^
      22 |   })
      23 | })

      at Object.<anonymous> (tests/unit/user.spec.js:21:23)

axios.getメソッドで指定した引数をチェックしたい場合にはtoHaveBeenCalledWith関数を利用することができます。URLのスペルが間違っている場合にはエラーがテストでFAIL(失敗)します。


describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    await flushPromises();
    expect(axios.get).toHaveBeenCalledWith(
      'https://jsonplaceholder.typicode.com/users'
    );
  });
});

Mockで設定したデータを使ってテストも行うことができます。findAllメソッドli要素を取得して要素の数をtoHaveLength関数でチェックしています。


describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    await flushPromises();
    const users = wrapper.findAll('li');
    expect(users).toHaveLength(2);
  });
});

findAllではDomWrapperオブジェクトを取得することができるのでtextメソッドを利用して要素のコンテンツを取得し、toContains関数で含まれている文字列のチェックを行います。


describe('User', () => {
  it('mount render a child component', async () => {
    const wrapper = mount(User);
    await flushPromises();
    const users = wrapper.findAll('li');
    expect(users[0].text()).toContain('Leanne');
    expect(users[1].text()).toContain('Howell');
  });
});

動作確認を行ったテストは下記の通りです。


import { mount, shallowMount } from '@vue/test-utils';
import User from "@/components/User.vue";
import flushPromises from 'flush-promises'
import axios from "axios"

jest.mock("axios", () => ({
  get: jest.fn(() => Promise.resolve({ data: [
        {id:1,name:"Leanne Graham"},
        {id:2,name:"Ervin Howell"},
      ]
  }))
})
);

describe('User', () => {
  it("mount render a child component",async() => {
    const wrapper = mount(User);
    await flushPromises()
    expect(axios.get).toHaveBeenCalledTimes(1)
    expect(axios.get).toHaveBeenCalled()
    expect(axios.get).toHaveBeenCalledWith('https://jsonplaceholder.typicode.com/users')
    const users = wrapper.findAll('li')
    expect(users).toHaveLength(2)
    expect(users[0].text()).toContain('Leanne')
    expect(users[1].text()).toContain('Howell')    
  })
})

Mock関数のメソッドとプロパティの確認

Jestのドキュメントを確認するとMock関数のメソッドの一覧が表示されていますが初めてMock関数を利用する人にとってはどのように使うのかわかりにくいと思います。axiosのmockを利用しながら各メソッドの利用方法を確認しながら理解を深めていきましょう。

Mock関数のメソッド一覧
Mock関数のメソッド一覧

UserListのコンポーネントのライフサイクルフックmountedで実行されているaixosのコードは以下の通りです。


mounted(){
  axios.get('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    this.users = response.data;
  })
}

mockImplementationメソッド

mockImplementationメソッドを使ってテストコードを下記のように書き換えることができます。書き換えを行ってもテストの結果は変わりません。


jest.mock('axios', () => ({
  get: jest.fn().mockImplementation(() =>
    Promise.resolve({
      data: [
        { id: 1, name: 'Leanne Graham' },
        { id: 2, name: 'Ervin Howell' },
      ],
    })
  ),
}));

axiosモジュールをmockした後にaxios.getメソッドを別の行として記述することもできます。


jest.mock('axios');
axios.get.mockImplementation(() =>
  Promise.resolve({
    data: [
      { id: 1, name: 'Leanne Graham' },
      { id: 2, name: 'Ervin Howell' },
    ],
  })
);

一度だけcallしたい場合にはmockImplementationOnceメソッドがあります。UserListの中で2回axiosを実行した場合は1回目はmockImplementationOnceで設定した値を戻しますが2回目のaxiosではエラーになります。

mockResolvedValueメソッド

mockResolvedValueメソッドを利用した場合はPromise.resolveを省略してもPromiseを戻してくれるのでmockImplementationとは異なりPromiseの設定を行う必要がありません。


jest.mock('axios', () => ({
  get: jest.fn().mockResolvedValue({
    data: [
      { id: 1, name: 'Leanne Graham' },
      { id: 2, name: 'Ervin Howell' },
    ],
  }),
}));

mockReturnValueメソッド

UserList.vueで実行しているaxiosのgetメソッドはPromiseを戻す必要があるのでそのままの値を戻すmockReturnValueメソッドではテストでエラーが発生します。Promiseを戻す必要のないMock関数であればmockReturnValueメソッドを利用することができます。


jest.mock('axios', () => ({
  get: jest.fn().mockReturnValue({
    data: [
      { id: 1, name: 'Leanne Graham' },
      { id: 2, name: 'Ervin Howell' },
    ],
  }),
}));

ライフサイクルフックのmountedでasync, awaitを利用している場合はmockReturnValueでもエラーは発生しません。


async mounted() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  this.users = response.data;
},

mock関数のプロパティの確認

mock関数はメソッドだけではなくプロパティも持っています。持っているプロパティは.mockで確認することができます。axios.getの場合はaxios.get.mockと設定します。


describe('User', () => {
  it("mount render a child component",async() => {
    const wrapper = mount(User);
    await flushPromises()
    console.log(axios.get.mock)   
  })
})

テストを実行するとmockプロパティはcalls, instances, invocationCallOrder, resultsの4つのプロパティから構成されていることが確認できます。


{
  calls: [ [ 'https://jsonplaceholder.typicode.com/users' ] ],
  instances: [ { get: [Function] } ],
  invocationCallOrder: [ 1 ],
  results: [ { type: 'return', value: [Promise] } ]
}

callsはgetメソッドの引数に入っている文字列を取得することができるのでcallsを利用してテストを実施することができます。


expect(axios.get.mock.calls[0][0]).toBe('https://jsonplaceholder.typicode.com/users');

callsプロパティの配列はaxios.getが呼ばれる度に要素が追加されるので呼ばれる回数はcalls.lengthと一致します。呼び出される回数でテストを実施したい場合は下記のようにテストすることができます。


expect(axios.get.mock.calls.length).toBe(1);

さらにaxios.get.mock.results[0].valueを確認することでmockで戻される値を確認することができます。mockReturnValueを利用した場合は下記のように値として戻されていることがここでもわかります。


  console.log
    {
      data: [ { id: 1, name: 'Leanne Graham' }, { id: 2, name: 'Ervin Howell' } ]
    }

mockResolvedValueの場合はPromiseが戻されていることがわかります。


  console.log
    Promise { { data: [ [Object], [Object] ] } }

spyOnの利用

spyOnを下記のように記述することでaxios.getが実行されるとmockResolvedValueに設定された値がPromiseで戻されます。


jest.spyOn(axios, 'get').mockResolvedValue({
  data: [
    { id: 1, name: 'Lee Graham' },
    { id: 2, name: 'Ervin Howell' },
  ],
});

スナップショットテスト

スナップショットを利用することでテスト実行時のコンポーネントのUIの情報をファイルとして保存することができます。スナップショットで保存を行うと次回のテストでUIに違いがあるかチェックを行うことができます。expect(wrapper.element).toMatchSnapshot()でUserコンポーネントのスナップショットを取得することができます。


it('mount render a child component', async () => {
  const wrapper = mount(User);
  await flushPromises();
  expect(wrapper.element).toMatchSnapshot();
});

テストを実行すると__snapshots__フォルダが自動作成されその下にuser.spec.js.snapファイルが作成されます。

ファイルの中身を見るとUserコンポーネントのHTMLを確認することができます。Userコンポーネントではaxiosでユーザ一覧も取得しているので取得した情報も反映されています。


// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`User mount render a child component 1`] = `
<div
  data-v-app=""
>
  
  <h1>
    Vue Test Utilsの使い方
  </h1>
  
  <h2>
    ユーザ一覧
  </h2>
  <ul>
    
    <li>
      Lee Graham
    </li>
    <li>
      Ervin Howell
    </li>
    
  </ul>
  
  
</div>
`;

テストを実行すると自動でファイルが保存されるのでMockで設定しているダミーのユーザ名を”Lee Graham”から”John Doe”に変更します。テストを実行すると表示される内容が異なるためエラーになります。どこに違いが発生しているのかも確認することができます。


  Snapshot name: `User mount render a child component 1`

    - Snapshot  - 1
    + Received  + 1

    @@ -10,11 +10,11 @@
          ユーザ一覧
        </h2>
        <ul>
          
          <li>
    -       Lee Graham
    +       Joh Doe
          </li>
          <li>
            Ervin Howell
          </li>
//略
 › 1 snapshot failed.
Snapshot Summary
 › 1 snapshot failed from 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.

保存したスナップショットの情報を更新したい場合は– -uオプションをつけて実行します。


 % npm run test:unit -- -u

スナップショットのファイルの内容が更新されていることが確認できます。

まとめ

本文書と前回公開した”【基本編】Jestを利用してVue コンポーネントをテストする方法(Unit Test)”を一通り読んだ人であれば、Vue.jsのVue Test Utils、Jestの公式ドキュメントを読みこなせるようになっていると思います。実際に手を動かしてテストを実行して、テストの自分なりの方法論を考えバグの少ない高品質なコードを記述できるようになってください。