前提条件
- バージョン情報
- Vue 2.6.10
- Jest 24.5.0
TL;DR
DOMが絡むなら $nextTick
, 絡まないなら setTimeout
を使う。
実例
test.vue
<template>
<div id="piyo">
{{ hoge }}
</div>
</template>
<script>
export default {
data() {
return {
hoge: '',
};
},
async created() {
this.hoge = await this.huga();
},
methods: {
huga() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('it works');
}, 100);
});
},
},
};
</script>
test.spec.js
import { shallowMount } from '@vue/test-utils';
import Target from 'test.vue';
test('DOMをチェックする時', async () => {
const wrapper = await shallowMount(Target);
wrapper.vm.$nextTick(() => {
const val = wrapper.find('#piyo');
expect(val.text()).toEqual('it works');
});
});
test('dataをチェックする時', (done) => {
const wrapper = shallowMount(Target);
setTimeout(() => {
expect(wrapper.vm.hoge).toEqual('it works');
done();
}, 200);
});
問題点
1. $nextTick
を使っている場合
mounted, Promise が resolve された時の2回チェックされることになり、テストには通るのですが Error in nextTick: "Error: expect(received).toEqual(expected)
というエラー出てしまいます。。 参考文献にあるとおり、 FlushPromises
を使えば解消するかもしれません(試してないです)。
2. setTimeout
を使っている場合
待つ時間は長めに確保しないとうまく動かないことがあります。例えば、私の環境では待つ時間を 96ms にすると、1回目はうまく動き、2回目はコケます(キャッシュが効いて2回目のテストがちょっと早く動作し始めるためと思ってます)。こちらは、 huga()
をモックしてしまえば解消できます。
test.spec.js
test('dataをチェックする時2', (done) => {
const wrapper = shallowMount(Target, {
methods: {
huga: jest.fn().mockResolvedValue('it works'),
},
});
setTimeout(() => {
expect(wrapper.vm.hoge).toEqual('it works');
done();
}, 1); // 限りなく小さい値で良い
});
この場合、 huga()
は Promise を返す関数なので、 huga()
のテストも行ってあげるべきですが、Axios で API を叩いているだけな関数であればテストしなくてもよいかと(システム境界の外側なので)。Promise を返す関数であれば Jest でちゃんとテストできます。
参考文献