Jest と Vue Test Utils による Vue コンポーネントのテスト

Vue CLI で作成した TypeScript 用の Vue プロジェクトに対して、JestVue Test Utils(@vue/test-utils) を追加導入し、Vue コンポーネントのテスト(TypeScript で実装)を実施するようにしてみました。

今回は、Vue CLIvue create 時に、Manually select features を選択して、Choose Vue versionTypeScript にだけチェックを付け、Vue.js 2.x と 3.x のプロジェクトをそれぞれ作成して実施しています。

今回のソースは http://github.com/fits/try_samples/tree/master/blog/20210621/

(a) Vue.js 2.x の場合

まずは、Vue.js 2.x のプロジェクトで実施してみます。

  • Vue.js 2.6.14

a-1. テストモジュールの導入

Jest と Vue Test Utils に必要なモジュールをインストールして設定します。

jest のインストールと設定

jestts-jest(テストコードを TypeScript で実装するため)、vue-jest(テストコードで Vue コンポーネントを扱うため)をインストールします。

> npm i -D jest ts-jest vue-jest

ts-jest と vue-jest を適用するように Jest を設定し、jsdom を適用してテストを実施するよう testEnvironmentjsdom を設定しておきます。

jest.config.js 設定例
module.exports = {
    testEnvironment: 'jsdom',
    preset: 'ts-jest',
    transform: {
        '.*\\.(vue)$': 'vue-jest'
    }
}

Vue Test Utils のインストール

@vue/test-utils をインストールします。

> npm i -D @vue/test-utils

@types/jest のインストールと設定

ついでに、VS Code で jest の関数を使ってもエラー表示にならないようにするための措置を行っておきます。

まずは、jest の型定義をインストールします。

> npm i -D @types/jest

tsconfig.jsontypesjest を追加します。

tsconfig.json 設定例
{
・・・
    "types": [
      ・・・
      "jest"
    ],
・・・
}

a-2. コンポーネントの実装

テスト対象のコンポーネントを実装します。

src/components/Counter.vue
<template>
  <div>
    <p>
      <button @click="countUp">count up</button>
    </p>
    <p>
      counter: {{ count }}
    </p>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  data() {
    return {
      count: 0
    }
  },
  methods: {
    countUp() {
      this.count++
    }
  }
})
</script>

a-3. テストの実装と実施

テストコードを実装し、テストしてみます。

TypeScript で実装する場合、型の都合上 counter.vm.count とする事はできなかったので、とりあえずは counter.vm.$data.count としています。

(counter.vm as any).count とする事も可能ですが、正直どちらも微妙な気がします。

tests/Counter.test.vue
import { mount } from '@vue/test-utils'
import Counter from '../src/components/Counter.vue'

test('count up', async () => {
    const counter = mount(Counter)

    expect(counter.vm.$data.count).toBe(0)
    // 以下でも可
    // expect((counter.vm as any).count).toBe(0)

    await counter.get('button').trigger('click')

    expect(counter.vm.$data.count).toBe(1)
})

jest コマンドでテストを実施します。

テスト実行
> npx jest

 PASS  tests/Counter.test.ts (5.907 s)
  ・・・

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

(b) Vue.js 3.x の場合

次は、Vue.js 3.x のプロジェクトで実施してみます。

  • Vue.js 3.1.1

b-1. テストモジュールの導入

基本的には 2.x と同じですが、インストールするモジュールのバージョンが多少異なります。

jest のインストールと設定

現時点で、Vue.s 3.x に対応した vue-jest をインストールするにはバージョンに next を指定する必要がありました。

また、(現時点で)インストールされる vue-jest 5.0.0-alpha.10 は、jest のバージョン 27 には対応しておらず、jest と ts-jest はバージョン 26 をインストールする必要がありました。

> npm i -D jest@26 ts-jest@26 vue-jest@next

Jest の設定は 2.x と同じですが、こちらは 2.x とは違って testEnvironment を設定しなくても特に支障は無さそうでした。

jest.config.js 設定例
module.exports = {
    testEnvironment: 'jsdom',
    preset: 'ts-jest',
    transform: {
        '.*\\.(vue)$': 'vue-jest'
    }
}

Vue Test Utils のインストール

@vue/test-utils のバージョンも next とする必要がありました。

> npm i -D @vue/test-utils@next

また、@types/jest は 2.x と同様に、必要に応じてインストールして設定しておきます。

b-2. コンポーネントの実装

テスト対象コンポーネントを実装します。

src/components/Counter.vue
<template>
  <div>
    <p>
      <button @click="countUp">count up</button>
    </p>
    <p>
      counter: {{ count }}
    </p>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  data() {
    return {
      count: 0
    }
  },
  methods: {
    countUp() {
      this.count++
    }
  }
})
</script>

上記を以下のように Composition API で実装しても、同じテストコードでテストできました。

src/components/Counter.vue(Composition API 版)
<template>
  <div>
    <p>
      <button @click="countUp">count up</button>
    </p>
    <p>
      counter: {{ count }}
    </p>
  </div>
</template>

<script lang="ts">
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const countUp = () => count.value++

    return {
      count,
      countUp
    }
  }
}
</script>

b-3. テストの実装と実施

こちらは 2.x とは違って、counter.vm.count とする事ができました。

tests/Counter.test.vue
import { mount } from '@vue/test-utils'
import Counter from '../src/components/Counter.vue'

test('count up', async () => {
    const counter = mount(Counter)

    expect(counter.vm.count).toBe(0)

    await counter.get('button').trigger('click')

    expect(counter.vm.count).toBe(1)
})

jest コマンドでテストを実施します。

テスト実行
> npx jest

 PASS  tests/Counter.test.ts
 ・・・

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