jest.fn()声称没有被调用,但是有

时间:2019-02-26 17:20:36

标签: vue.js vuejs2 jestjs vuex

我正在测试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()失败了。

这怎么可能?它与我嘲笑的另一个功能配合正常。替换我模拟函数的顺序并不重要。删除其他函数被调用的期望也没有关系,因此它看起来不像是冲突。

1 个答案:

答案 0 :(得分:2)

  

这怎么可能?

expect运行并失败,而selectElement才有机会运行。


详细信息

消息队列

JavaScript使用message queue。下一条开始之前的当前消息runs to completion

PromiseJobs队列

ES6引入了PromiseJobs queue来处理“响应承诺的解决”的工作。 PromiseJobs队列中的所有作业都在当前消息完成之后且下一条消息开始之前运行

异步/等待

asyncawait只是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