This setup is extremely specific but I couldn't find any similar resources online so I'm posting here in case it helps anyone.
There are many questions about Jest and Async callback was not invoked
, but I haven't found any questions whose root issue revolves around the use of jest.useFakeTimers()
. My function should take no time to execute when using fake timers, but for some reason Jest is hanging.
I'm using Jest 26 so I'm manually specifying to use modern
timers.
This is a complete code snippet that demonstrates the issue.
jest.useFakeTimers('modern')
let setTimeoutSpy = jest.spyOn(global, 'setTimeout')
async function retryThrowable(
fn,
maxRetries = 5,
currentAttempt = 0
) {
try {
return await fn()
} catch (e) {
if (currentAttempt < maxRetries) {
setTimeout(
() => retryThrowable(fn, maxRetries, currentAttempt + 1),
1 * Math.pow(1, currentAttempt)
)
}
throw e
}
}
describe('retryThrowable', () => {
const fnErr = jest.fn(async () => { throw new Error('err') })
it('retries `maxRetries` times if result is Err', async () => {
jest.clearAllMocks()
const maxRetries = 5
await expect(retryThrowable(() => fnErr(), maxRetries)).rejects.toThrow('err')
for (let _ in Array(maxRetries).fill(0)) {
jest.runAllTimers()
await Promise.resolve() // https://stackoverflow.com/a/52196951/3991555
}
expect(setTimeoutSpy).toHaveBeenCalledTimes(maxRetries)
})
})
The full error message is
Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.
at mapper (../../node_modules/jest-jasmine2/build/queueRunner.js:27:45)
Any ideas would be very appreciated
edit 1: I have tried --detectOpenHandles
but no new information is provided
edit 2: I just tried my above code snippet in a fresh project and realized that it passes just fine. So the issue must somewhere else in my Jest config. I'll answer my own question when I determine the root cause