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

标签 vue.js vuejs2 jestjs vuex

我正在测试一个 Vue 组件,当某个参数出现在路由中时,它会调用我的 Vuex 存储中的某个操作。我正在使用 jest.fn() 来模拟这个 Action 。

这里是组件的相关代码:

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() 失败了。

这怎么可能?它适用于我模拟的另一个功能。替换我模拟函数的顺序并不重要。删除另一个函数被调用的期望也无关紧要,因此它看起来不像是冲突。

最佳答案

How is this possible?

expectselectElement 有机会运行之前运行并失败。


详情

消息队列

JavaScript 使用 message queue .当前留言runs to completion在下一个开始之前。

PromiseJobs 队列

ES6 引入了 PromiseJobs queue它处理“对 promise 的解决作出回应”的工作。 PromiseJobs 队列中的任何作业都在当前消息完成后和下一条消息开始之前运行。

异步/等待

asyncawait 只是 syntactic sugar over promises and generators .在 Promise 上调用 await 实质上将函数的其余部分包装在回调中,以便在 Promise 解析时在 PromiseJobs 中安排。

会发生什么

您的测试作为当前正在运行的消息开始运行。调用 shallowMount 加载您的组件,该组件一直运行到 await this.$store.dispatch('someOtherAction'); 调用 someOtherFunction 然后基本上将函数的其余部分作为 Promise 回调在 Promise 解析时安排在 PromiseJobs 队列中。

然后执行返回到运行两个 expect 语句的测试。第一个通过,因为 someOtherFunction 已被调用,但第二个失败,因为 selectElement 尚未运行。

然后当前正在运行的消息完成,然后运行 ​​PromiseJobs 队列中的待处理作业。调用 selectElement 的回调在队列中,因此它运行并调用记录到控制台的 selectElement


解决方案

确保调用 selectElementPromise 回调在运行 expect 之前已经运行。

只要有可能,最好返回 Promise,这样测试就可以直接await

如果那是不可能的,那么解决方法是在测试期间对已解决的 Promise 调用 await,这实际上将其余测试排在 PromiseJobs 的后面排队并允许任何未决的 Promise 回调首先运行:

it('selects element if passed in route', async () => {
  const $route = {params: {id: '256'}};
  const wrapper = shallowMount(AbcModel, {
    mocks: {$route},
    store, localVue
  });
  expect(someOtherFunction).toHaveBeenCalled();
  // Ideally await the Promise directly...
  // but if that isn't possible then calling await Promise.resolve()
  // queues the rest of the test at the back of PromiseJobs
  // allowing any pending callbacks to run first
  await Promise.resolve();
  expect(selectElement).toHaveBeenCalled();  // SUCCESS
});

关于vue.js - jest.fn() 声称没有被调用,但是,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54890916/

相关文章:

vue.js - 使用组件通过CDN读取条形码

javascript - 在后端生成由 Javascript (VueJS) 生成的等效 HTML

javascript - 如何隐藏主页上的一组按钮? vue.js

reactjs - 无法在 React 应用程序中测试轻量级图表

node.js - 无法在 Windows 10 上安装@vue/cli 3

c# - .NET Core 3.1、Vue、Axios 和 [ValidateAntiForgeryToken]

javascript - 为什么配合插件调用vue组件方法失败?

javascript - 如何将输入的值添加到 li 列表?

jestjs - 如何测试应该抛出错误的组件?

node.js - Jest如何测试express API POST请求?