はじめに
nuxt.jsをJest+vue-test-utilsでテストする際に、nuxt.js特有のメソッド(this.$router.push
など)やcontextをモックするのに大変苦労しました。
他の人が同じ苦労をせずにすんなりテストを書く手助けになればいいな〜と思います!
asyncDataやfetch以外でモックする方法
shallowMountやmountで用意されている、こちらのmocksというオプションを利用します。
https://vue-test-utils.vuejs.org/guides/#mocking-injections
$storeを使った例
以下は$store
のモックを作成した簡単な例です。
Vue
<template>
<div>
<p v-if="isLoggedIn">
ログインしています😊
</p>
<p v-if="!isLoggedIn">
ログインしていません😢
</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['isLoggedIn'])
}
}
</script>
テスト
今回使っているのはstore
のgetters
内のisLoggedIn
メソッドのみなので、
const store = {
getters: {
isLoggedIn: jest.fn(() => true)
}
}
↑みたいな感じでstore.getters.isLoggedIn
が機能するようなモックを作成して、shallowMount
に渡していきます!
import { shallowMount } from '@vue/test-utils'
import SomePage from '~/pages/somePage'
describe('SomePage', () => {
let wrapper, store
beforeEach(() => {
wrapper = shallowMount(SomePage, {
mocks: { $store: store }
})
})
describe('when logged in', () => {
beforeAll(() => {
store = {
getters: {
isLoggedIn: jest.fn(() => true)
}
}
})
it('shows logged in text', () => {
expect(wrapper.text()).toContain('ログインしています😊')
})
})
})
$routerを使った例
Vue
<template>
<div class="home" @click="pushToHome()">
ホーム
</div>
</template>
<script>
export default {
methods: {
pushToHome() {
this.$router.push('/')
}
}
}
</script>
「nuxt-link使えよ!!!」っていう話なんですが、例のためなので今回は許してください。笑
テスト
今回使っているのは$router.push
というメソッドなので、$store
をモックしたときと同様、
const router = { push: jest.fn() }
↑こんな感じでrouter.push
が機能するようなモックをshallowMount
に渡します。
import { shallowMount } from '@vue/test-utils'
import SomePage from '~/pages/somePage'
describe('SomePage', () => {
let wrapper
const router = { push: jest.fn() }
beforeEach(() => {
wrapper = shallowMount(SomePage, {
mocks: { $router: router }
})
})
describe('when home is clicked', () => {
beforeEach(() => {
const home = wrapper.find('.home')
home.trigger('click')
})
it('pushes to home', () => {
expect(router.push).toBeCalledWith('/')
})
})
})
asyncDataやfetched内でcontextをモックする方法
asyncDataとfetchedはnuxtが用意してくれている関数なので、vue-test-utilsのmountを使ってテストをしようとしても、asyncDataは実行されません。
なので、こちらから手動で実行させる必要があります。
asyncDataでstoreを使った例
Vue
<template>
<div>
<p v-if="isLoggedIn">
ログインしています😊
</p>
<p v-if="!isLoggedIn">
ログインしていません😢
</p>
</div>
</template>
<script>
export default {
data() {
return {
isLoggedIn: false
}
},
asyncData({ store }) {
return { isLoggedIn: store.getters.isLoggedIn }
}
}
</script>
テスト
「asyncDataやfetch以外でモックする方法」でもやったように、store.getters.isLoggedIn
が機能するようなstore
のモックを作ります。
ただ、今回はshallowMount
のmocks
に渡すのではなく、asyncData
を呼び出す際に直接渡します。
import { shallowMount } from '@vue/test-utils'
import SomePage from '~/pages/somePage'
describe('SomePage', () => {
let wrapper, store
beforeEach(() => {
wrapper = shallowMount(SomePage)
// 1. asyncDataを呼び出す
const data = wrapper.vm.$options.asyncData({ store })
// 2. asyncDataが返す値をVue instanceのデータに設定する
wrapper.setData(data)
})
describe('when logged in', () => {
beforeAll(() => {
store = {
getters: {
isLoggedIn: jest.fn(() => true)
}
}
})
it('shows logged in text', () => {
expect(wrapper.text()).toContain('ログインしています😊')
})
})
})
store
以外にも、asyncData
内でapp
やerror
などを使う場合も、この例と同様にモックできます。
最後に
以上を使えば、nuxt特有のメソッドを簡単にモックできるはずです!
プラグインのモックの方法も、需要があれば後々記事を書くかもしれません。
筆者はまだnuxtを使い始めたばかりなので、間違いやよりよい方法があればガシガシご指摘ください!