みなさん、フロントエンドのテスト書いていますか?
Nuxt.js(Vue.js)でJestを使ってコンポーネントのテストについては情報がいろいろありましたが、VuexのStoreのテストについてあまり情報がなかったので、今回はVuexStoreのテストについてまとめました。
「Nuxt v2とFirebase(CloudFirestore)でPWA対応Webアプリ開発」で作成したアプリケーションをJestでテストする手順についてまとめていきます。
テストの準備
テストに必要なツール
Jest
https://github.com/facebook/jest
JestはFacebookが開発を進めるフロントエンドのテストランナです。
Facebook製なので当然Reactに対応していますが、その他JavaScriptアプリケーションのテストにも使用でき、Vue.jsでも利用できます。
RSpecライクな記法でテストコーディングが可能です。
Vue Test Utils
https://vue-test-utils.vuejs.org/ja/
Vue.jsアプリケーション用の公式単体テストライブラリです。
Vue-Router、VuexなどVue.jsのテストコーディングのために必要です。
Babel (@babel/core)
BabelはES2015以降のバージョンで記載されたJavaScriptをECMAScript5に変換するためのトランスコンパイラです。
babel-jest
JestをBabelに対応するためのツールです。
babel-preset-env
環境に従って必要なBabelプラグインを自動で決定するツールです。
babel-preset-vue-app
Vue開発のためのBabel設定を提供するツールです。
lodash.clonedeep
テスト実行のために直接必要になるわけではありませんが、VuexのテストでStoreオブジェクトをコピーするために利用します。
必要なツールを設定
必要なツールをインストールします。
> yarn add jest @vue/test-utils lodash.clonedeep babel-jest @babel/core @babel/preset-env babel-preset-vue-app lodash.clonedeep --dev
package.jsonにtestコマンド、Jest、Babelの設定を追加します。
targets->browsersオプションで対象ブラウザを指定しています。
オプションの詳細はこの辺りに記載があります。
https://babeljs.io/docs/en/babel-preset-env
"scripts": {
"test": "jest"
},
"jest": {
"transform": {
"^.+\\.js$": "babel-jest"
}
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 versions"
]
},
"debug": true
}
]
]
},
この状態でテストを実行してみます。
> yarn run test
yarn run v1.10.1
$ jest
No tests found
まだテストコードがないので、エラーになりますが、テストが実行されています。
テストコーディング
Vuexのテスト
VuexのStoreのテストはこちらの書籍を参考にしました。
[Nuxt.jsビギナーズガイド]
(https://www.amazon.co.jp/Nuxt-js%E3%83%93%E3%82%AE%E3%83%8A%E3%83%BC%E3%82%BA%E3%82%AC%E3%82%A4%E3%83%89%E2%80%95Vue-js-%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B7%E3%83%B3%E3%82%B0%E3%83%AB%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E8%8A%B1%E8%B0%B7-%E6%8B%93%E7%A3%A8/dp/4863542569/ref=sr_1_1?ie=UTF8&qid=1544104962&sr=8-1&keywords=nuxt.js%E3%83%93%E3%82%AE%E3%83%8A%E3%83%BC%E3%82%BA%E3%82%AC%E3%82%A4%E3%83%89)
GitHubにソースも公開されています。
require('dotenv').config()
const Vuex = require('vuex')
const messages = require('../../store/messages')
const { createLocalVue } = require('@vue/test-utils')
const cloneDeep = require('lodash.clonedeep')
const localVue = createLocalVue()
localVue.use(Vuex)
describe('store/message.js', () => {
let store
beforeEach(() => {
store = new Vuex.Store(cloneDeep(messages))
})
describe('actions', () => {
test('initMessagesでmessagesが初期化される', async () => {
expect(store.getters['messages'].length).toBe(0)
await store.dispatch('initMessages')
expect(store.getters['messages'].length).not.toBe(0)
})
})
})
少し説明すると、require('dotenv').config()
で、.envの値を読み込みます。
beforeEachで、cloneDeepを使ってmessagesのStoreをコピーし、オブジェクトを生成します。
beforeEach(() => {
store = new Vuex.Store(cloneDeep(messages))
})
実際のテストはこちらです。
StoreのinitMessagesアクションをdispatchして、messagesステートにデータがセットされることを確認しています。
describe('actions', () => {
test('initMessagesでmessagesが初期化される', async () => {
expect(store.getters['messages'].length).toBe(0)
await store.dispatch('initMessages')
expect(store.getters['messages'].length).not.toBe(0)
})
})
テストを実行します。
PASS spec/store/messages.spec.js
store/message.js
actions
✓ initMessagesでmessagesが初期化される (830ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.223s
Ran all test suites.
テストが成功しました!
まとめなど
テスト環境構築の際、Babelのエラーで苦しみました。。
this.setDynamic is not a function
とか、
Cannot find module '@babel/preset-env'
とか。
Babelのバージョンに気をつけつつ、GitHubのissue情報や、Babel公式ドキュメントあたりにいろいろ情報ありますので、参考にしてください!
今回の記事では書かなかったですが、コンポーネント周りのテストをやろうとすると、やはりコンポーネントがテストしやすいIOの単位でまとまっていないと辛いです・・テストどう書けばいいの?ってなります。
やはり、TDDでテストを最初に書くことが大事ですね。