Nuxt.jsビギナーズガイド
posted with ヨメレバ
花谷拓磨 シーアンドアール研究所 2018年10月
Vuexストアのテスト
- 単一ファイルコンポーネントのテストにはJestプラグイン(vue-jest)が必要だが、まずピュアなJavaScriptだけで書かれたVuexストアのテストを体験してみる。
- Vue Test Utilsを利用したテストでは、createLocalVue()でVueインスタンスを生成する必要がある。
- Vuexを利用する場合は、Vueインスタンスのuseメソッドで Vuex を使用するように指示する必要がある。
1. 以下のapp/store/index.jsのテストを作成する場合
const state = () => ({
count: 0
})
const getters = {
count: (state) => state.count
}
const mutations = {
increment(state) {
state.count++
}
}
const actions = {
increment({ commit }) {
commit('increment')
}
}
module.exports = {
state,
getters,
mutations,
actions
}
2. 以下のspec/store/index.spec.jsを作成する
const Vuex = require('vuex')
const index = require('../../../app/store')
const { createLocalVue } = require('@vue/test-utils')
const cloneDeep = require('lodash.clonedeep')
const localVue = createLocalVue()
localVue.use(Vuex)
describe('store/index.js', () => {
let store
beforeEach(() => {
store = new Vuex.Store(cloneDeep(index))
})
describe('mutations', () => {
test('increment ミューテーションがコミットされると、 count ステートの値が +1 される)', () => {
expect(store.getters['count']).toBe(0)
store.commit('increment')
expect(store.getters['count']).toBe(1)
})
})
describe('actions', () => {
test('increment アクションを dispatch するたびに、 increment ミューテーションがコミットされる', () => {
expect(store.getters['count']).toBe(0)
store.dispatch('increment')
expect(store.getters['count']).toBe(1)
})
})
})
3. npm run testでテスト実行
単一ファイルコンポーネントのテスト
単一ファイルコンポーネントのテスト
- vue/test-utilsのmount関数を使ってコンポーネントをマウントする。
1. 以下のapp/components/AppToggleButton.vueのテストを作成する場合
<template>
<div>
<p>{{status ? 'on' : 'off'}}</p>
<button type="button" @click="toggle">toggle</button>
</div>
</template>
<script>
export default {
data() {
return {
status: false
}
},
methods: {
toggle() {
this.status = !this.status
}
}
}
</script>
2. 以下のspec/components/AppToggleButton.spec.jsを作成する
import AppToggleButton from '~/components/AppToggleButton.vue'
import { mount } from '@vue/test-utils'
describe('AppToggleButton.vue', () => {
let wrapper
beforeEach(() => {
wrapper = mount(AppToggleButton)
})
test('デフォルト状態で off であるか', () => {
expect(wrapper.find('p').text()).toBe('off')
})
test('ボタンを押すことによって on となるか', async () => {
await wrapper.find('button').trigger('click')
expect(wrapper.find('p').text()).toBe('on')
})
})
3. npm run testでテスト実行
Vue Routerを使っている単一ファイルコンポーネントのテスト
- mount時にstoreとlocalVueを渡す必要がある。
1. 上述のapp/store/index.jsを使った以下のapp/pages/index.vueのテストを作成する場合
<template>
<div>
<h2>カウンター</h2>
<h3>Count: <span class="count">{{count}}</span></h3>
<button type="button" @click="increment">Increment</button>
<AppToggleButton />
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import AppToggleButton from '~/components/AppToggleButton.vue'
export default {
components: {
AppToggleButton
},
computed: {
...mapGetters(['count'])
},
methods: {
...mapActions(['increment'])
}
}
</script>
2. 以下のspec/pages/index.jsを作成する
import { mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import IndexPage from '~/pages/index'
import store from '~/store/index'
import cloneDeep from 'lodash.clonedeep'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('pages/index.vue', () => {
let wrapper
beforeEach(() => {
wrapper = mount(IndexPage, {
store: new Vuex.Store(cloneDeep(store)),
localVue
})
})
test('カウンターをクリックした時に、カウント値が 1 加算される', () => {
expect(wrapper.vm.count).toBe(0)
wrapper.find('button').trigger('click')
expect(wrapper.vm.count).toBe(1)
})
})
3. npm run testでテスト実行
Vue Routerを使っている単一ファイルコンポーネントのテスト
- mount時にstubsオプションでvue-test-utilsのRouterLinkStubコンポーネントを指定する。
1. 以下のapp/pages/child.vueのテストを作成する場合
<template>
<div>
<nuxt-link to="/">トップページへ戻る</nuxt-link>
</div>
</template>
<script>
export default {
}
</script>
2. 以下のspec/pages/child.jsを作成する
import { mount, createLocalVue, RouterLinkStub } from '@vue/test-utils'
import ChildPage from '~/pages/child'
const localVue = createLocalVue()
describe('pages/child.vue', () => {
test('トップページへ戻る導線が存在する', () => {
const wrapper = mount(ChildPage, {
localVue,
stubs: {
NuxtLink: RouterLinkStub
}
})
// 書籍ではfindだが非推奨のためfindComponentを使う
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/')
})
})
3. npm run testでテスト実行
スナップショットテスト
- コンポーネントの状態やレンダリング結果をシリアライズして保存し、それらに変化があるかどうかをテストすることができる。
- 通常のテストとは異なり、1度テストを記述するだけで恒久的に利用でき、コマンドひとつで正しい状態を再生成できる。
- とはいえ、精度が高いテストではないため、本当に必要かどうか考えて導入するべきである。
1. 上述のspec/components/AppToggleButton.spec.jsにexpect(wrapper.element).toMatchSnapshot()を追加する
import AppToggleButton from '~/components/AppToggleButton.vue'
import { mount } from '@vue/test-utils'
describe('AppToggleButton.vue', () => {
let wrapper
beforeEach(() => {
wrapper = mount(AppToggleButton)
})
test('デフォルト状態で off であるか', () => {
expect(wrapper.find('p').text()).toBe('off')
expect(wrapper.element).toMatchSnapshot()
})
test('ボタンを押すことによって on となるか', async () => {
await wrapper.find('button').trigger('click')
expect(wrapper.find('p').text()).toBe('on')
expect(wrapper.element).toMatchSnapshot()
})
})
2. npm run testでテスト実行
- 1度テストを実行するとspec/components/__snapshots__にスナップショットが生成され、2回目以降はそのスナップショットとの比較が行われる。
- スナップショットの更新は、Jest実行時に–updateSnapshotオプションを付与する。