ARTICLE AD BOX
In my application I need to ensure that an array of Promises will be executed in the order as given in the array. Addtionally, the application shall "wait" a certain time after each Promise execution.
I'm using a for..of loop over a forEach(). forEach() would not await each Promise separately:
// timerDemo.ts export async function executeInOrderWithDelay( fns: (() => Promise<void>)[], delayMs = 1000, ): Promise<void> { for (const fn of fns) { await fn() await new Promise<void>((r) => setTimeout(r, delayMs)) } }Using this code in my application and testing it in a browser works as expected.
I'm having issues in my Jest-UnitTests mocking setTimeout():
import { executeInOrderWithDelay } from './TimerDemo' describe('executeInOrderWithDelay', () => { afterEach(() => { jest.useRealTimers() }) test('executes functions in order with specified delay', async () => { jest.useFakeTimers() const calls: number[] = [] const fns = [ jest.fn(() => { calls.push(1) return Promise.resolve() }), jest.fn(() => { calls.push(2) return Promise.resolve() }), jest.fn(() => { calls.push(3) return Promise.resolve() }), ] executeInOrderWithDelay(fns, 1000) // first should be invoked immediately expect(fns[0]).toHaveBeenCalledTimes(1) expect(fns[1]).not.toHaveBeenCalled() // advance to allow loop to proceed to second jest.advanceTimersByTime(1000) expect(fns[1]).toHaveBeenCalledTimes(1) expect(fns[2]).not.toHaveBeenCalled() // advance to allow loop to proceed to third jest.advanceTimersByTime(1000) expect(fns[2]).toHaveBeenCalledTimes(1) expect(calls).toEqual([1, 2, 3]) }) })The UT fails with the first setTimeout():
FAIL test/TimerDemo.spec.ts executeInOrderWithDelay ✕ executes functions in order with specified delay (7 ms) ● executeInOrderWithDelay › executes functions in order with specified delay expect(jest.fn()).toHaveBeenCalledTimes(expected) Expected number of calls: 1 Received number of calls: 0 32 | // advance to allow loop to proceed to second 33 | jest.advanceTimersByTime(1000) > 34 | expect(fns[1]).toHaveBeenCalledTimes(1) | ^ 35 | expect(fns[2]).not.toHaveBeenCalled() 36 | 37 | // advance to allow loop to proceed to thirdHow is the right way to mock setTimeout() to pass the UT?
