vue.js - jest.fn() 声称没有被调用,但有
问题描述
我正在测试一个 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()
失败了。
这怎么可能?它适用于我模拟的另一个功能。替换我模拟函数的顺序并不重要。消除调用另一个函数的期望也没关系,所以它看起来不像是冲突。
解决方案
这怎么可能?
之前的expect
运行和失败selectElement
都有机会运行。
细节
消息队列
JavaScript 使用消息队列。当前消息在下一条消息开始之前运行完成。
PromiseJobs 队列
ES6 引入了PromiseJobs 队列,它处理“对 Promise 的解决作出响应”的作业。PromiseJobs 队列中的任何作业都在当前消息完成之后和下一条消息开始之前运行。
异步/等待
async
并且await
只是promises 和 generators 的语法糖。调用await
aPromise
基本上将函数的其余部分包装在回调中,以便在解析时在 PromiseJobs 中安排Promise
。
怎么了
您的测试作为当前正在运行的消息开始运行。调用shallowMount
会加载您的组件,该组件会运行直到await this.$store.dispatch('someOtherAction');
调用someOtherFunction
,然后实质上将函数的其余部分作为Promise
回调排队,以便在解决时安排在 PromiseJobs 队列中Promise
。
然后执行返回到运行这两个expect
语句的测试。第一个通过,因为someOtherFunction
已被调用,但第二个失败,因为selectElement
尚未运行。
当前正在运行的消息然后完成,然后运行 PromiseJobs 队列中的待处理作业。调用的回调selectElement
在队列中,因此它运行并调用selectElement
记录到控制台的日志。
解决方案
确保Promise
调用的回调selectElement
在运行expect
.
只要有可能,最好将其返回,Promise
以便测试可以await
直接使用它。
如果这是不可能的,那么一种解决方法是在测试期间调用await
resolve Promise
,它基本上将其余的测试排在 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
});
推荐阅读
- javascript - 如何在反应组件内消除redux动作
- javascript - 有没有办法计算你在溢出设置为自动的 div 内滚动了多远?
- vba - 如何使用 VBA 获取单词表中的行值
- ubuntu - 让 odbc 驱动程序与适用于 linux 的 windows 子系统一起工作
- c# - C# 自定义封送处理 - 未提供零 IntPtr 值的 ICustomMarshaler 实现
- java - 如何读取多个大文件(400~mb)更改为自定义格式并写入单个文件
- c# - 如何更改 IIS Express 的默认路径?
- javascript - 在 PDF 中,我想使用 javascript 从浏览器 URL 中获取主机名
- python - 计算 Tensorflow 2 中每个 epoch 后每个类的召回率
- java - 如何在 spring 项目中使用 Deployed Resources/web-resources/ 中的属性文件