使用 jest 和 avoriaz 时如何在 Vuejs 的组件中测试异步方法
Posted
技术标签:
【中文标题】使用 jest 和 avoriaz 时如何在 Vuejs 的组件中测试异步方法【英文标题】:How to test async method in Vuejs's component when using jest and avoriaz 【发布时间】:2018-01-14 11:34:54 【问题描述】:例如,我有一个组件看起来像这样。
<template>
<div id="app">
<button class="my-btn" @click="increment"> val </button>
</div>
</template>
<script>
export default
data()
return
val: 1,
;
,
methods:
increment()
fetch('httpstat.us/200').then((response) =>
this.val++;
).catch((error) =>
console.log(error);
);
,
,
</script>
你也可以查看this fiddle作为一个简化的演示
为了对这个组件做单元测试,我写了这样的代码。
// Jest used here
test('should work', () =>
// wrapper was generated by using avoriaz's mount API
// `val` was 1 when mounted.
expect(wrapper.data().val).toBe(1);
// trigger click event for testing
wrapper.find('.my-btn')[0].trigger('click');
// `val` should be 2 when the button clicked.
// But how can I force jest to wait until `val` was set?
expect(wrapper.data().val).toBe(2);
);
自从expect
在fetch
完成之前运行,它就不起作用了,但我不知道如何让笑话等到 promise 函数完成。
那么如何在这个用例中进行测试呢?
更新我尝试了 nextTick 但没有成功。
PASS src/Sample.spec.js
Sample.vue
✓ should work (31ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.46s
Ran all test suites.
console.error node_modules/vue/dist/vue.runtime.common.js:477
[Vue warn]: Error in nextTick: "Error: expect(received).toBe(expected)
Expected value to be (using ===):
2
Received:
1"
console.error node_modules/vue/dist/vue.runtime.common.js:564
Error: expect(received).toBe(expected)
Expected value to be (using ===):
2
Received:
1
at /path/to/sample-project/src/Sample.spec.js:16:30
at Array.<anonymous> (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:699:14)
at nextTickHandler (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:646:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
matcherResult:
actual: 1,
expected: 2,
message: [Function],
name: 'toBe',
pass: false
这是完整的测试代码。
import mount from 'avoriaz';
import Sample from './Sample.vue';
import Vue from 'vue';
/* eslint-disable */
describe('Sample.vue', () =>
test('should work', () =>
const wrapper = mount(Sample);
// console.log(wrapper.data().val);
expect(wrapper.data().val).toBe(1);
wrapper.find('.my-btn')[0].trigger('click');
Vue.nextTick(() =>
// console.log(wrapper.data().val);
expect(wrapper.vm.val).toBe(2);
done();
)
);
)
更新 2 我添加了done
,但它仍然不起作用。这是错误消息。
console.error node_modules/vue/dist/vue.runtime.common.js:477
[Vue warn]: Error in nextTick: "Error: expect(received).toBe(expected)
Expected value to be (using ===):
2
Received:
1"
console.error node_modules/vue/dist/vue.runtime.common.js:564
Error: expect(received).toBe(expected)
Expected value to be (using ===):
2
Received:
1
at /path/to/sample-project/src/Sample.spec.js:16:30
at Array.<anonymous> (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:699:14)
at nextTickHandler (/path/to/sample-project/node_modules/vue/dist/vue.runtime.common.js:646:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
matcherResult:
actual: 1,
expected: 2,
message: [Function],
name: 'toBe',
pass: false
FAIL src/Sample.spec.js (7.262s)
● Sample.vue › should work
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
at pTimeout (node_modules/jest-jasmine2/build/queueRunner.js:53:21)
at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:523:19)
at ontimeout (timers.js:469:11)
at tryOnTimeout (timers.js:304:5)
at Timer.listOnTimeout (timers.js:264:5)
Sample.vue
✕ should work (5032ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 8.416s
Ran all test suites.
【问题讨论】:
【参考方案1】:小故事:从flush-promises
(npm i -D flush-promises
) 获得帮助,并在您的Vue.nextTick
之前致电await flushPromises()
。
长话短说,我有一个 EmailVerification.vue
组件和一个 submit
方法,如下所示:
submit ()
this.successMessage = ''
this.verifyError = null
this.isVerifying = true
this.verifyEmail( 'key': this.key )
.then(() =>
this.isVerifying = false
this.successMessage = 'Email verified, great! Thanks a lot. <i class="fa fa-home"></i><a href="/">Home</a>'
)
.catch((error) =>
this.isVerifying = false
this.verifyError = error
)
这是我通过的完整测试:
const localVue = createLocalVue()
localVue.use(Vuex)
const $route =
path: '/verify-email/:key',
params: key: 'dummy_key' ,
query: email: 'dummy@test.com'
describe('EmailVerification.vue', () =>
describe('Methods', () =>
let localAuth = namespaced: true
let store
let wrapper
beforeEach(() =>
localAuth.actions =
verifyEmail: jest.fn().mockReturnValueOnce()
store = new Vuex.Store(
namespaced: true,
modules: auth: localAuth ,
strict: true
)
wrapper = shallowMount(EmailVerification,
localVue,
store,
stubs:
RouterLink: RouterLinkStub
,
mocks:
$route
)
)
it('should trigger verifyEmail when button is clicked', async (done) =>
const data = key: 'another_dummy_key'
wrapper.setData(data)
const button = wrapper.find('button')
expect(wrapper.vm.isVerifying).toBeFalsy()
expect(wrapper.vm.verifyError).toBeNull()
expect(button.attributes().disabled).toBeUndefined()
button.trigger('click')
expect(localAuth.actions.verifyEmail).toHaveBeenCalled()
expect(localAuth.actions.verifyEmail.mock.calls[0][1]).toEqual(data)
expect(button.attributes().disabled).toBeDefined()
expect(wrapper.vm.isVerifying).toBeTruthy()
expect(wrapper.vm.verifyError).toBeNull()
const inputArray = wrapper.findAll('input')
expect(inputArray.at(0).attributes().disabled).toBeDefined()
expect(inputArray.at(1).attributes().disabled).toBeDefined()
await flushPromises()
wrapper.vm.$nextTick(() =>
expect(wrapper.vm.isVerifying).toBeFalsy()
expect(wrapper.vm.verifyError).toBeNull()
done()
)
)
)
)
然后使用jest.fn()
模拟函数的返回值返回并测试错误。
注意:我使用的是 jest 和 mocha,而不是 avoriaz。
【讨论】:
nextTick
甚至没有必要。【参考方案2】:
您需要在测试中使用Vue.nextTick
和done
:
test('should work', (done) =>
expect(wrapper.data().val).toBe(1);
wrapper.find('.my-btn')[0].trigger('click');
Vue.nextTick(() =>
expect(wrapper.vm.val).toBe(3);
done()
)
);
【讨论】:
嗨,艾德!非常感谢您回答我。但我仍然没有运气。我更新了我的问题,看来val
仍然是 1...
我忘记在回调中添加 done,我已经编辑了我的答案。你能再试一次吗?
嗨,Edd,我又试了一次,但仍然出错。请检查我的新更新。
这个错误看起来你没有在下一个滴答回调中调用完成?由于我现在正在休假八,我无法正确查看,但解决方案应该使用 done 和 nextTick以上是关于使用 jest 和 avoriaz 时如何在 Vuejs 的组件中测试异步方法的主要内容,如果未能解决你的问题,请参考以下文章
使用带有 Avoriaz 的 AVA 在 Vue.js 中测试计算属性
Vue Typescript 组件 Jest 测试不会在 html 中呈现值