我正在尝试用Jest模拟setInterval中的setTimeout,但是看到令人困惑的行为,并且我不知道它是否是错误,或者我做错了什么。
在传递给setInterval的异步函数内部等待将导致setTimeout永远不会运行。如果我在下面的函数中删除了await,则setTimeout成功设置。
jest.setTimeout(10000);
let interval;
/**
* Check for a promise to return true before clearing an interval and setting a timeout
* @param {boolean} shouldAwaitRes - toggle whether to await inside the async callback
* @param {function} callback - mock function to call inside timeout
*/
const check = async (shouldAwaitRes, callback) => {
const res = shouldAwaitRes ? await Promise.resolve(true) : Promise.resolve(true);
if (res) {
clearInterval(interval);
setTimeout(() => {
callback();
}, 2000);
}
};
/**
* Set an interval with an async function that awaits a response
* @param {boolean} shouldAwaitRes - toggle whether to await inside the async callback
* @param {function} callback - mock function to pass into set timeout
*/
const setAsyncInterval = async (shouldAwaitRes, callback) => {
interval = setInterval(check, 1000, shouldAwaitRes, callback);
};
/**
* Wait 6 seconds for real timers to run
*/
const pause = async () => {
return new Promise(resolve => {
setTimeout(resolve, 6000);
});
};
// ----------------------------------
// Tests
describe('Timers', () => {
let callback;
beforeEach(() => {
callback = jest.fn();
});
afterEach(() => {
jest.resetAllMocks();
});
describe('No Fake Timers Used', () => {
it('should call the callback inside the async setInterval callback when awaiting', async done => {
await setAsyncInterval(true, callback); // setting to true to await inside async callback
// Pause 6 seconds to let the timers runs
await pause();
expect(callback).toBeCalled(); // callback is called
done();
});
});
describe('Fake Timers', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
});
it('should call the callback inside the async setInterval callback when NOT awaiting', async done => {
await setAsyncInterval(false, callback); // setting to false to disable awaiting inside async callback
// Advance Time 6 seconds
jest.advanceTimersByTime(6000);
expect(callback).toBeCalled(); // callback is called
done();
});
// The below test fails
it('should call the callback inside the async setInterval callback when awaiting', async done => {
await setAsyncInterval(true, callback); // setting to true to enable awaiting inside async callback
// Advance Time 6 seconds
jest.advanceTimersByTime(6000);
expect(callback).toBeCalled(); // callback is NOT called
done();
});
});
});
还向Jest报告,看是否可能是错误:https://github.com/facebook/jest/issues/9181
编辑:更新了样本复制案例并添加了开玩笑