如何在 Jest 中正确使用 Promises 和 Timer [英] How to properly use Promises and Timers with Jest
问题描述
我搜索了 SO 和 Google,发现了很多类似的问题和答案,但似乎没有一个能帮助我解决我的问题.
I have searched both SO and Google and found a lot of similar questions and answers, but none of them seems to have helped me solve my issue.
我正在尝试编写一些需要模拟异步轮询函数的测试用例.但无论我做什么,我都会得到:
I am attempting to write some test cases where I need to mock an async polling function. But no matter what I do I get:
在 jest.setTimeout.Timeout 指定的 5000 毫秒超时内未调用异步回调
我设置了一些最小的测试用例来重现问题:
I set up some minimal test cases the reproduce the problem:
jest.useFakeTimers();
describe('timers test', () => {
it('plain timer works as expected', () => {
const mock = jest.fn();
setTimeout(mock, 5000);
jest.runAllTimers();
expect(mock).toHaveBeenCalled();
});
it('Using a timer to mock a promise resolution results in a jest timeout error', async () => {
const mock = jest.fn(() => {
return new Promise((resolve) => setTimeout(resolve, 500));
});
const handler = jest.fn();
await mock().then(handler);
jest.runAllTimers();
expect(handler).toHaveBeenCalled();
});
it('Using a timer to mock a promise rejection results in a jest timeout error', async () => {
const mock = jest.fn(() => {
return new Promise((resolve, reject) => setTimeout(reject, 500));
});
const handler = jest.fn();
await mock().catch(handler);
jest.runAllTimers();
expect(handler).toHaveBeenCalled();
});
});
有人可以解释我做错了什么以及为什么吗?
Can someone explain what I am doing wrong and why?
推荐答案
因此,在@Bergi 的后续评论中,我认为 done
实际上也不是必需的.我只需要重新订购一些东西.然后,我在测试进一步强调这一点的承诺链时遇到了类似的问题,因此我为此添加了一些案例.
So with a follow up comment from @Bergi, I relaized the done
wasn't actually necessary either. I just needed to re-order some things. I then ran into a similar issue when testing chains of promises that further highlighted this so I added some cases for that.
jest.useFakeTimers();
describe('timers test', () => {
it('Using a plain timer works as expected', () => {
const mock = jest.fn();
setTimeout(mock, 5000);
jest.runAllTimers();
expect(mock).toHaveBeenCalled();
});
it('Using a timer to mock a promise resolution', async () => {
const mock = jest.fn(() => {
return new Promise((resolve) => setTimeout(resolve, 500));
});
const handler = jest.fn();
const actual = mock().then(handler);
jest.runAllTimers();
await actual;
expect(handler).toHaveBeenCalled();
});
it('Using a timer to mock a promise rejection', async () => {
const mock = jest.fn(() => {
return new Promise((resolve, reject) => setTimeout(reject, 500));
});
const handler = jest.fn();
const actual = mock().catch(handler);
jest.runAllTimers();
await actual;
expect(handler).toHaveBeenCalled();
});
it('Using a timer to mock a promise resolve -> delay -> resolve chain', async () => {
const mockA = jest.fn(() => {
return Promise.resolve();
});
const mockB = jest.fn(() => {
return new Promise((resolve, reject) => {
setTimeout(resolve, 500);
});
});
const handler = jest.fn();
const actual = mockA()
.then(() => {
const mockProm = mockB();
jest.runAllTimers();
return mockProm;
})
.then(handler);
jest.runAllTimers();
await actual;
expect(mockA).toHaveBeenCalled();
expect(mockB).toHaveBeenCalled();
expect(handler).toHaveBeenCalled();
});
it('Using a timer to mock a promise resolve -> delay -> reject chain', async () => {
const mockA = jest.fn(() => {
return Promise.resolve();
});
const mockB = jest.fn(() => {
return new Promise((resolve, reject) => {
setTimeout(reject, 500);
});
});
const handler = jest.fn();
const actual = mockA()
.then(() => {
const mockProm = mockB();
jest.runAllTimers();
return mockProm;
})
.catch(handler);
await actual;
expect(mockA).toHaveBeenCalled();
expect(mockB).toHaveBeenCalled();
expect(handler).toHaveBeenCalled();
});
});
<小时>
@Bergi' 评论引导我找到解决方案.我最终使用了 done
函数,并删除了 await
.这似乎至少在这个最小的测试用例中有效.
@Bergi' comment led me to the solution. I ended up making use of the done
function, and removing the await
. This seems to work at least in this minimal test case.
jest.useFakeTimers();
describe('timers test', () => {
it('plain timer works as expected', () => {
const mock = jest.fn();
setTimeout(mock, 5000);
jest.runAllTimers();
expect(mock).toHaveBeenCalled();
});
it('Using a timer to mock a promise resolution results in a jest timeout error', async (done) => {
const mock = jest.fn().mockImplementation(() => {
return new Promise((resolve) => setTimeout(resolve, 500));
});
// make the handler invoke done to replace the await
const handler = jest.fn(done);
mock().then(handler);
jest.runAllTimers();
expect(handler).toHaveBeenCalled();
});
it('Using a timer to mock a promise rejection results in a jest timeout error', async (done) => {
const mock = jest.fn().mockImplementation(() => {
return new Promise((resolve, reject) => setTimeout(reject, 500));
});
// make the handler invoke done to replace the await
const handler = jest.fn(done);
mock().catch(handler);
jest.runAllTimers();
expect(handler).toHaveBeenCalled();
});
});
这篇关于如何在 Jest 中正确使用 Promises 和 Timer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!