前回(JestでNuxt+Vuetifyのテストを書いてみる)に続き、今回は初期表示の正常系テストを書いてみました。
最初に対応する時に役立つのでメモしておきます。
injectしている関数のMockを作らなくても動くようにする
前回(pluginでinjectしている関数のテスト)では、使用するテストファイル毎にMockを作っていましたが、手間なのと期待値の確認(表示されたか)もしやすくなので、どこでも関数が呼ばれるようにする事にしました。
test/setup.js に追加
import Vue from 'vue'
import Vuetify from 'vuetify'
import { TestPluginUtils } from '~/plugins/utils.js'
Vue.use(Vuetify)
Vue.use(TestPluginUtils)
plugins/utils.js のTestPluginを修正
export const TestPluginUtils = {
install (Vue) {
Vue.prototype.$dateFormat = dateFormat
Vue.prototype.$timeFormat = timeFormat
Vue.prototype.$pageFirstNumber = pageFirstNumber
Vue.prototype.$pageLastNumber = pageLastNumber
}
}
呼び出し元
下記のように定義していたmocksが不要になりました。
test/page/users/undo_delete.spec.js
return shallowMount(Page, {
localVue,
vuetify,
mocks: {
- $dateFormat: jest.fn(),
- $timeFormat: jest.fn()
i18nの値がネスト(入れ子)だと取れない
前回作成した($tが無いと言われる)ではネスト(入れ子)にした連想配列だと、undefinedになってしまうバグがありました。
こんな感じで定義していて、
locales/ja.js
network: {
failure: '通信に失敗しました。しばらく時間をあけてから、やり直してください。',
error: '通信エラーが発生しました。しばらく時間をあけてから、やり直してください。'
},
テストで使うとundefinedに。
Expected: "通信に失敗しました。しばらく時間をあけてから、やり直してください。"
Received: undefined
test/setup.js を修正
import Vue from 'vue'
import Vuetify from 'vuetify'
import { config, RouterLinkStub } from '@vue/test-utils'
import { TestPluginUtils } from '~/plugins/utils.js'
import locales from '~/locales/ja.js'
Vue.use(Vuetify)
Vue.use(TestPluginUtils)
// Mock i18n
config.mocks = {
$t: (key) => {
let locale = locales
const parts = key.split('.')
for (const part of parts) {
locale = locale[part]
}
// eslint-disable-next-line no-throw-literal
if (locale == null) { throw 'Not found: i18n(' + key + ')' }
return locale
}
}
// Stub NuxtLink
config.stubs.NuxtLink = RouterLinkStub
NuxtLinkのパスが存在するかのテスト
RouterLinkStubのprops().toで取れますが、複数ある場合が多いので、先に一覧化して、含まれるかをテストするようにしました。
また、よく使うのでclass作って、importしています。
test/page/infomations/index.spec.js
import { Helper } from '~/test/helper.js'
const helper = new Helper()
const links = helper.getLinks(wrapper)
expect(links.includes('/infomations/' + list.id)).toBe(list.body_present) // [本文あり]お知らせ詳細
test/helper.js
import { RouterLinkStub } from '@vue/test-utils'
export class Helper {
// NuxtLinkのURL一覧を配列で返却
getLinks = (wrapper) => {
const routerlinks = wrapper.findAllComponents(RouterLinkStub)
const links = []
for (let i = 0; i < routerlinks.length; i++) {
const link = routerlinks.at(i).props().to
if (link.name === 'infomations-id___ja') {
links.push('/infomations/' + link.params.id) // お知らせ一覧
} else {
links.push(link)
}
}
return links
}
}
> <NuxtLink to="/infomations">
toがlinksに含まれるかでテストできます。
> <NuxtLink :to="{ name: 'infomations-id___ja', params: { id: list.id }}">
ただ、こんな感じにパラメータを渡している場合、props().toで取れる値には下記のように設定されますが、includesだとtrueにならないので、linksに入れる時に実際のパスを保存するように、テストも実際のパスで行っています。
> { name: 'infomations-id___ja', params: { id: 1 } }
async/awaitの挙動について
下記のように、awaitの後に処理があった場合、
pages/users/delete.vue
async created () {
try {
await this.$auth.fetchUser()
} catch (error) {
if (error.response == null) {
this.$toasted.error(this.$t('network.failure'))
} else if (error.response.status === 401) {
return this.appSignOut()
} else {
this.$toasted.error(this.$t('network.error'))
}
return this.$router.push({ path: '/' })
}
if (!this.$auth.loggedIn) {
return this.appRedirectAuth()
}
if (this.$auth.user.destroy_schedule_at !== null) {
return this.appRedirectDestroyReserved()
}
this.processing = false
this.loading = false
},
下記のようにテストを書くと、上のawaitの所までの状態となり、
その後(今回はloadingがfalse)を期待したテストが失敗します。
console.log(wrapper.html())も途中の状態が表示されます。
test/page/users/delete.spec.js
await expect(authFetchUserMock).toBeCalledTimes(1)
expect(wrapper.findComponent(Loading).exists()).toBe(false)
sleepして対応
毎回定義するのは手間なので、上で作成したhelperに追加しました。
import { Helper } from '~/test/helper.js'
const helper = new Helper()
await helper.sleep(1)
expect(authFetchUserMock).toBeCalledTimes(1)
expect(wrapper.findComponent(Loading).exists()).toBe(false)
await/sleepの前は、awaitの前の状態のテスト、
後は最終的な状態のテストを書けるようになります。
test/helper.js
export class Helper {
// 一定時間停止
sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
}

“JestでNuxt+Vuetifyのテストを書く時のTips #1” に対して1件のコメントがあります。