我有一个等待多个诺言的功能
const function = async () => {
await function1()
await function2()
await function3()
}
我要测试是否调用了function3:
it(('calls function3', async () => {
jest.spyOn(api, 'function1').mockResolvedValue({})
jest.spyOn(api, 'function2').mockResolvedValue({})
spy = jest.spyOn(api, 'function3')
await function()
expect(spy).toBeCalledTimes(1)
})
此测试失败,但是当我打电话等待很多次时:
it(('calls function3', async () => {
jest.spyOn(api, 'function1').mockResolvedValue({})
jest.spyOn(api, 'function2').mockResolvedValue({})
spy = jest.spyOn(api, 'function3')
await await await await await function()
expect(spy).toBeCalledTimes(1)
})
测试将通过。为什么是这样?在进入下一个期望行之前,await function()
是否应该解决所有的诺言?
edit:等待的函数越深,即function4,我需要的等待语句越多,但不是1到1。
答案 0 :(得分:1)
将承诺排入微任务队列是一个顺序问题,我正在使用flush-promises
解决同一问题。
它使用节点setImmediate
将微任务队列为空时将调用的回调推送到队列。
const flushPromises = require('flush-promises');
test('flushPromises', async () => {
let a;
let b;
Promise.resolve().then(() => {
a = 1;
}).then(() => {
b = 2;
})
await flushPromises();
expect(a).toBe(1);
expect(b).toBe(2);
});
答案 1 :(得分:1)
现在有一个proposal in Jest具有类似runAllTimers
的东西,只是为了保证。
因此,如果您想避免集成flush-promises
,则可以只使用setTimeout(() => {...rest code...}, 0)
。由于timeout
是宏任务,因此可以确保在运行之前解决所有待处理的微任务(如promises)。
有关微任务和宏任务的更多信息:https://abc.danch.me/microtasks-macrotasks-more-on-the-event-loop-881557d7af6f
答案 2 :(得分:0)
await function()
在进入下一个期望行之前难道没有解决所有的诺言吗?
是的,await
将等待返回的Promise
后再继续。
这是一个简单的工作示例:
const function1 = jest.fn().mockResolvedValue();
const function2 = jest.fn().mockResolvedValue();
const function3 = jest.fn().mockResolvedValue();
const func = async () => {
await function1();
await function2();
await function3();
}
it('calls function3', async () => {
await func();
expect(function3).toHaveBeenCalled(); // Success!
})
如果await
的等待时间没有达到预期的时间,则Promise
链可能会在某个时刻断开。
以下是Promise
链断裂的示例:
const function1 = jest.fn().mockResolvedValue();
const function2 = jest.fn().mockResolvedValue();
const function3 = jest.fn().mockResolvedValue();
const func = async () => {
await function1();
await function2();
await function3();
}
const func2 = async () => {
func(); // <= breaks the Promise chain
}
it('calls function3', async () => {
await func2();
expect(function3).toHaveBeenCalled(); // <= FAILS
})
多次调用await
会将其余测试功能排入PromiseJobs
队列的后面,这可以使待处理的Promise
回调有机会运行... < / p>
...因此,如果将上面的破损测试更改为此,它将通过:
it('calls function3', async () => {
await await await await func2(); // <= multiple await calls
expect(function3).toHaveBeenCalled(); // Success...only because of multiple await calls
})
...但是真正的解决方案是找到并修复Promise
链断开的位置:
const func2 = async () => {
await func(); // <= calling await on func fixes the Promise chain
}
it('calls function3', async () => {
await func2();
expect(function3).toHaveBeenCalled(); // Success!
})