Motivation

Reliable tests are essential for maintaining confidence in your code. But in Jest, a test can pass while still leaking async work.

The problem

Jest does not fully enforce async test isolation. Even with --detectOpenHandles, it does not fail when some async work continues after a test ends.

Nothing in Jest guarantees that:

This leads to tests that appear to pass but are incorrect.

Example:

it('fetches data', async () => {
  // returns a promise, but we forget to await it
  fetchData().then((data) => {
    putItInGlobalStore(data);
  });
});

This test: Passes, but leaves async work running. This can mutate global state later. To address these issues, jest-doctor ensures tests fail if any async operations remain unresolved.

Why this matters

A failing test is noisy and clear. A leaking test is silent and can corrupt other tests.

Leaks often show up as:

By the time you see the failure, the leaking test may be far earlier in the run.

Async leaks break determinism

A fundamental invariant of testing is:

Running tests in a different order should not change results.

Async leaks violate this rule.

Promises are especially dangerous leak sources.

Promises are:

A Promise can:

jest-doctor enforces a simple rule:

when a test ends, all async work must be done.