我正在测试Vue组件,当路由中存在某个参数时,该组件会在我的Vuex存储中调用某个动作。我正在用jest.fn()
来模仿动作。
这是组件中的相关代码:
await this.$store.dispatch('someOtherAction');
if (this.$route.params && this.$route.params.id) {
this.$store.dispatch('selection/selectElement', parseInt(this.$route.params.id, 10));
}
这是模拟功能:
someOtherAction = jest.fn();
selectElement = jest.fn(() => console.log("selectElement has been called"));
我的测试:
it('selects element if passed in route', async () => {
const $route = {params: {id: '256'}};
const wrapper = shallowMount(AbcModel, {
mocks: {$route},
store, localVue
});
expect(someOtherAction).toHaveBeenCalled();
expect(selectElement).toHaveBeenCalled();
});
在输出中,我可以看到“ selectElement已被调用”。显然,它已被调用。然而,expect(selectElement).toHaveBeenCalled()
失败了。
这怎么可能?它与我嘲笑的另一个功能配合正常。替换我模拟函数的顺序并不重要。删除其他函数被调用的期望也没有关系,因此它看起来不像是冲突。
答案 0 :(得分:2)
这怎么可能?
expect
运行并失败,而selectElement
才有机会运行。
消息队列
JavaScript使用message queue。下一条开始之前的当前消息runs to completion。
PromiseJobs队列
ES6引入了PromiseJobs queue来处理“响应承诺的解决”的工作。 PromiseJobs队列中的所有作业都在当前消息完成之后且下一条消息开始之前运行。
异步/等待
async
和await
只是syntactic sugar over promises and generators。实际上,在await
上调用Promise
会在Promise
解析时将其余函数包装在PromiseJobs中计划的回调中。
会发生什么
您的测试开始作为当前运行消息运行。调用shallowMount
会加载您的组件,直到运行await this.$store.dispatch('someOtherAction');
并调用someOtherFunction
为止,然后基本上将其余函数作为Promise
回调队列,并在PromiseJobs队列中安排Promise
解决。
然后执行返回到运行两个expect
语句的测试。自someOtherFunction
被调用以来,第一个失败了,但是由于selectElement
尚未运行,第二个失败了。
然后,当前正在运行的消息完成,然后PromiseJobs队列中的挂起作业将运行。调用selectElement
的回调位于队列中,因此它可以运行并调用selectElement
,该日志将记录到控制台。
解决方案
在运行Promise
之前,请确保已运行调用selectElement
的{{1}}回调。
只要有可能,最好返回expect
,以便测试可以直接Promise
。
如果这不可能,那么一种解决方法是在测试期间在已解决的await
上调用await
,这实际上将其余测试排在PromiseJobs队列的后面,并允许任何待处理的{先运行{1}}个回调:
Promise