Search code examples
javascripttypescriptjestjssettimeoutusefaketimers

Using Jest with setTimeout and useFakeTimers


I have a TypeScript async function which must perform a sleep of 1 second between two statements. It is implemented by this code.

async function systemUnderTest(): Promise<void> {
    console.log("One");
    await new Promise(r => { setTimeout(r, 1000); });
    console.log("Two");
}

I want to test it using the Jest framework. I can run this test:

test('myTest', async () => {
    await systemUnderTest();
});

It works, but it uses real time. How can I test that function in fake time?

I tried to write this test:

test('myTest', async () => {
    jest.useFakeTimers();
    await systemUnderTest();
    jest.runAllTimers();
    jest.useRealTimers();
});

For it, the timeout of 5 seconds is exceeded, and it never prints "Two".


Solution

  • Can you try to:

    1. Start the async function without waiting for it.
    2. Run all timers.
    3. Then wait for the async function.
    test('myTest', async () => {
        jest.useFakeTimers();
    
        const promise = systemUnderTest(); // start the function without awaiting it
    
        jest.runAllTimers(); // this will run the setTimeout in systemUnderTest
    
        await promise; // now we can wait for the function to finish
    
        jest.useRealTimers();
    });
    

    Note that when using fake timers, the setTimeout callback will be executed synchronously when you run jest.runAllTimers(), so there's no need to await it beforehand.