更新:可以肯定地说,这基本上是Jest: Timer and Promise don't work well. (setTimeout and async function)的重复
我有一个函数,在执行异步功能后会自我重复。我想验证jest.advanceTimersOnTime(5000)
继续产生expect(doAsyncStuff).toHaveBeenCalledTimes(X);
。
我观察到我们可以到达调用以重复该功能,但是当要求开玩笑地提前计时器时,它不会“通过”。当您删除其前面的异步功能时,它确实起作用。因此,听起来我必须获得doAsyncStuff才能“致电给我”或在此处解决一些未完成的承诺?
function repeatMe() {
setTimeout(() => {
doAsyncStuff.then((response) => {
if (response) {
console.log("I get here!");
repeatMe();
}
})
}, 5000);
}
jest.useFakeTimers();
let doAsyncStuff = jest.spyOn(updater, 'doAsyncStuff');
doAsyncStuff.mockResolvedValue(true);
repeatMe();
jest.advanceTimersByTime(5000);
expect(doAsyncStuff).toHaveBeenCalledTimes(1);
jest.advanceTimersByTime(5000);
expect(doAsyncStuff).toHaveBeenCalledTimes(2); // Failed?
答案 0 :(得分:1)
所以听起来我必须...在这里解决一些未完成的承诺?
是的。
简短的答案是,Promise
链接到then
返回的Promise
的{{1}}和{编写测试,在测试结束之前,回调永远没有机会运行。
要解决此问题,请为doAsyncStuff
回调提供在测试过程中运行的机会:
updater.js
Promise
code.js
export const doAsyncStuff = async () => { };
code.test.js
import { doAsyncStuff } from './updater';
export function repeatMe() {
setTimeout(() => {
doAsyncStuff().then((response) => {
if (response) {
console.log("I get here!");
repeatMe();
}
})
}, 5000);
}
答案 1 :(得分:0)
很明显,Jest故障排除解决了此问题:we have set the definition to happen asynchronously on the next tick of the event loop
。我想这也适用于实时代码中的事件,而不仅仅是书面测试。
做jest.runAllTimers()
会使事情陷入无休止的循环。
添加jest.runAllTicks()
将使刻度线前进,因此上述测试现在可以进行。
我仍然很困惑,但是我想这就是答案。
jest.advanceTimersByTime(5000);
jest.runAllTicks();
expect(doAsyncStuff).toHaveBeenCalledTimes(1);
jest.advanceTimersByTime(5000);
jest.runAllTicks();
expect(doAsyncStuff).toHaveBeenCalledTimes(2);
https://jestjs.io/docs/en/troubleshooting#defining-tests
要实现此目的,还需要模拟doAsyncStuff的实现,因为我也认为doAsyncStuff中的任何异步内容都会排队到tick事件中。
doAsyncStuff.mockImplementation(() => {
return new Promise.resolve();
});