Vue.jsでのテスト環境(Jest)構築

Vue.jsでテスト環境の構築

プロジェクト作成時にテスト環境を自動で設定するオプションもありますが、どのような設定が必要か認識しておきたいので、書籍(Testing Vue.js)を参考に環境構築をしてみました。

初期設定

  • vue create projectでプロジェクト構築
  • npm run serveで動作確認
  • npm install --save-dev jest
  • package.jsonでscriptsに "test:unit" : "jest --no-cache"を追加
  • componentsディレクトリの下に__tests__というディレクトリを作成し、Item.spec.jsを作成
test('sanity test', () => {
  return
})
  • npm run testでテストが実行されるか(Pass)確認
  • testにdescribeを追加
describe('Item.vue', () => {
  test('sanity test', () => {
    expect(true).toBe(true)
  })
})

単一ファイル(Single File Component)のテスト

VueコンポーネントはJavaScriptファイルと異なるため事前にCompileが必要です。そのためjest, babel-coreをインストールします。
ちなみに、BabelはJavaScriptの新しいバージョンを古いバージョンでも動くように変換するツールです。JestはJavaScriptのテスト用フレームワークです。

  • npm install --save-dev babel-jest vue-jest
  • npm install --save-dev babel-core@^7.0.0-bridge.0 ←バージョンを特定しないとbabelでエラー(...provided an invalid property of "default"...)がでたため
  • npm install --save-dev @babel/core
  • package.jsonのjestにコンパイルの指定を追加します。
  "jest" : {
    "transform": {
      ".+\\.js$" : "babel-jest",
      ".+\\.vue$" : "vue-jest"
    }
  }
  • babel.config.jsに以下の行を追加
    process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true

ここまで設定を行ってItem.vueとそのテスト(Item.spec.js)が実行できるようになりました。

<template>
  <div>item</div>
</template>

<script>
export default {
}
</script>
import Item from '../Item.vue'
import Vue from 'vue'

describe('Item.vue', () => {
  test('sanity test', () => {
    const Ctor = Vue.extend(Item)
    const vm = new Ctor().$mount()
    expect(vm.$el.textContent).toContain("item")
  })
})

vue-test-utilsの利用

テストをより簡単に記述できるようにvue-test-utilsライブラリが用意されています。ここではそれをインストールしてテストを書き換えてみます。

  • npm install --save-dev @vue/test-utils
import { mount } from '@vue/test-utils'
import Item from '../Item.vue'

describe('Item.vue', () => {
  test('render test', () => {
    const wrapper = mount(Item)
    expect(wrapper.text()).toContain('item')
  })
})

コンポーネントのテスト

personプロパティを受け取るコンポーネントのテスト

import { shallowMount } from '@vue/test-utils'
import Item from '../Item.vue'

describe('Item.vue', () => {
  test('render property', () => {
    const wrapper = shallowMount(Item, {
      propsData: {person:{'name':'tanaka'}}
    })
    expect(wrapper.text()).toContain('tanaka')
  })
})

コンポーネントの実装

<template>
  <div>{{person.name}}</div>
</template>

<script>
export default {
  props:['person']
}
</script>

参考

ここまでの時点でのpackage.jsonの内容

{
  "name": "my-hackernews",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "test:unit": "jest --no-cache"
  },
  "dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10"
  },
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@vue/cli-plugin-babel": "^3.10.0",
    "@vue/cli-plugin-eslint": "^3.10.0",
    "@vue/cli-service": "^3.10.0",
    "@vue/test-utils": "^1.0.0-beta.29",
    "babel-core": "^7.0.0-bridge.0",
    "babel-eslint": "^10.0.1",
    "babel-jest": "^24.8.0",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "jest": "^24.8.0",
    "vue-jest": "^3.0.4",
    "vue-template-compiler": "^2.6.10"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true,
      "jest": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "rules": {},
    "parserOptions": {
      "parser": "babel-eslint"
    }
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {}
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ],
  "jest": {
    "transform": {
      ".+\\.js$": "babel-jest",
      ".+\\.vue$": "vue-jest"
    }
  }
}

参考書籍: Testing Vue.js Applications