もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

vueでテストをやってみた

はじめに

こんばんは。

皆さんjsのテストって書いてますでしょうか?

僕はほぼほぼか書かないです!!

2〜3個前の案件で jestで書いて以来、そこから全く触っていません。

これはそろそろ...

と思い、重い腰を上げてやってみました。

今回は、今の案件でも使用している vueのテストをjestでやってみました。

多分新規プロジェクトとかだと、インストールツールでインタラクティブインストール時にテストツールとか選択できてたと思うのですが、テストだけ導入するにはどする?ってところでやってみました。

参考はこちらのサイト

本題

1. セットアップ

1. テストツールのinstall

現在の自分のプロジェクトでは、以下のライブラリをインストールすることになりました。

$ npm install --save-dev jest vue-jest babel-jest @vue/test-utils babel-core@bridge babel-preset-env

2. package.jsonの修正

  "scripts": {
    "test": "jest"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "vue"
    ],
    "transform": {
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    }
  }

3. .babelrcの修正

{
  "presets": [
    [ "env", { "modules": false } ]
  ],
  "env": {
    "test": {
      "presets": [
        [ "env", { "targets": { "node": "current" } } ]
      ]
    }
  }
}

テスト

テストで使うvueは以下

特定のステータスをラジオボタンで変更するコンポーネントなイメージです。

<template>
  <label :class="{ 'status-checked': checked }">
    <input
      v-model="innerChoiceStatusId"
      type="radio"
      name="status[]"
      :value="statusId"
    >
    {{ label }}
  </label>
</template>

<script>
export default {
  name: "StatusRadioButton",
  props: {
    statusId: {
      type: Number,
      default: null
    },
    label: {
      type: String,
      default: ''
    },
    choiceStatusId: {
      type: Number,
      default: null
    }
  },
  computed: {
    innerChoiceStatusId: {
      get() {
        return this.choiceStatusId
      },
      set(choiceStatusId) {
        if (this.choiceStatusId !== choiceStatusId) {
          this.$emit('update:choiceStatusId', choiceStatusId)
        }
      }
    },
    checked() {
      return this.statusId === this.innerChoiceStatusId
    }
  }
}
</script>

<style scoped>

</style>

1. 参考サイトにあったやつのテスト

import { mount } from '@vue/test-utils'
import StatusRadioButton from '@js/StatusRadioButton'

describe('Component', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(StatusRadioButton)
    expect(wrapper.vm).toBeTruthy()
  })
})
実行
 npm test

> jest

 PASS  tests/example.spec.js
  Component
    ✓ is a Vue instance (15 ms)

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

参考サイトにあった expect(wrapper.isVueInstance()).toBeTruthy() を行うと、エラーが出まして、次期バージョンでは削除されるとのことでした。

なので、こちらの方法で試すことにしました。

2. emitされてるか

describe('Component', () => {
  test('チェックされたら値が更新される', async () => {
    const wrapper = mount(StatusRadioButton, {
      propsData: {
        statusId: 100,
        label: 'タイプ100',
        choiceStatusId: null,
      }
    })
    const radioInput = wrapper.find('input[type="radio"]')
    await radioInput.setChecked()
    expect(wrapper.emitted('update:choiceStatusId')).toBeTruthy()
    expect(wrapper.emitted('update:choiceStatusId')[0][0]).toBe(100)
  })
})
実行
$ npm test
> jest

 PASS  tests/Spec/example.spec.js
  Component
    ✓ is a Vue instance (16 ms)
    ✓ チェックされたら値が更新される (10 ms)

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

propsDataをセットして、 emitされたかどうかのチェックは emitted でみるみたいです。

3. クラスが変更されているか

  test('チェックされたらlabelにstatus-checkedクラスが付与される', async () => {
    const wrapper = mount(StatusRadioButton, {
      propsData: {
        statusId: 100,
        label: 'タイプ100',
        choiceStatusId: null,
      }
    })
    const radioInput = wrapper.find('input[type="radio"]')
    await radioInput.setChecked()
    await wrapper.setProps({ choiceStatusId: wrapper.emitted('update:choiceStatusId')[0][0]})
    expect(wrapper.vm.checked).toEqual(true)
  })
実行
$ npm test

> jest

 PASS  tests/Spec/example.spec.js
  Component
    ✓ is a Vue instance (15 ms)
    ✓ チェックされたら値が更新される (10 ms)
    ✓ チェックされたらlabelにstatus-checkedクラスが付与される (5 ms)

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

syncでpropsを指定している際、update emit後本来ならば値が変更されているんですが、テストではどう書くかわからなかったので、2番のテストと似たような感じになりました...

終わりに

テスト各事自体はやりやすいんですが、テスト環境を作ることが大変です...

現場からは以上です。