Skip to content

Jest Async Test Timeout Exceeded Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about Jest Async Test Timeout Exceeded Fix. We cover key concepts, practical examples, and best practices.

Jest throws Timeout - Async callback was not invoked within the 5000 ms timeout — your async test never resolved and Jest timed out waiting.

The Problem

// WRONG — async test with missing await
test('fetches user data', () => {
  return fetchUser().then(data => {
    expect(data.name).toBe('Alice');
  });
  // Missing return statement:
  fetchUser().then(data => {
    expect(data.name).toBe('Alice');
  });
});
Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.

The second call to fetchUser() creates a promise that Jest doesn't wait for — the test passes an empty synchronous function, Jest marks it as done, and the assertion never runs.

Step-by-Step Fix

1. Return the promise or use async/await

// RIGHT — return the promise
test('fetches user data', () => {
  return fetchUser().then(data => {
    expect(data.name).toBe('Alice');
  });
});

// RIGHT — use async/await
test('fetches user data', async () => {
  const data = await fetchUser();
  expect(data.name).toBe('Alice');
});

2. Increase the timeout for slow operations

// RIGHT — increase timeout for slow async operations
test('processes large dataset', async () => {
  const result = await processLargeDataset();
  expect(result.length).toBe(10000);
}, 30000); // 30 seconds

Or set it globally:

// In setupFiles or test file
jest.setTimeout(30000);

3. Handle the done callback properly

// WRONG — done is never called on error
test('reads file', (done) => {
  fs.readFile('/tmp/data.txt', 'utf8', (err, data) => {
    if (err) throw err;
    expect(data).toContain('test');
    done();
  });
});

// RIGHT — catch errors and pass them to done
test('reads file', (done) => {
  fs.readFile('/tmp/data.txt', 'utf8', (err, data) => {
    if (err) return done(err);
    expect(data).toContain('test');
    done();
  });
});

4. Use Jest's timer mocks for flaky timeouts

jest.useFakeTimers();

test('debounced search', async () => {
  const search = jest.fn();
  debouncedSearch('hello', search);

  jest.advanceTimersByTime(300);

  expect(search).toHaveBeenCalledWith('hello');
});

Expected output:

PASS  tests/async.test.js
  ✓ fetches user data (45 ms)
  ✓ processes large dataset (12034 ms)
  ✓ reads file (8 ms)

Prevention Tips

  • Always return promises from non-async tests
  • Use async/await instead of raw .then() chains
  • Set jest.setTimeout() in jest.setup.js for slow CI environments
  • Use fake timers for setTimeout/setInterval-heavy code
  • Add --detectOpenHandles to find unresolved promises

Common Mistakes with async test timeout

  1. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  2. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  3. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks

These mistakes appear frequently in real-world JEST code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What does "Async callback was not invoked" mean?

It means your test function accepted a done callback parameter but never called it, or an async test never resolved its promise. Jest waits until the timeout expires then fails the test. The fix is to always call done() or return/await your promise.

How long should I set the timeout for CI tests?

Start with 30 seconds for individual slow tests and 10 seconds for most tests. CI runners are slower than local machines. Use jest.setTimeout(30000) in a setup file. Watch CI logs for tests that consistently take long — optimize those instead of increasing timeout globally.

Does fake timers affect all async operations?

No. jest.useFakeTimers() replaces setTimeout, setInterval, setImmediate, and process.nextTick. Promises, fetch, and actual I/O operations still run in real time. For full async control, use jest.useFakeTimers({ advanceTimers: true }) or a time mocking library.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro