Skip to content

[Feature]: Advanced leak detection and prevention #15953

@stephan-dum

Description

@stephan-dum

🚀 Feature Proposal

disclaimer: most of this proposal is copied from my project jest-doctor. The goal is to share learnings and explore whether some of these capabilities could be integrated into Jest itself.

The proposal aims to help detect common causes of flaky tests by ensuring each test properly cleans up asynchronous work and side effects before the next test runs.

The feature would detect and report tests that:

  • Leave unresolved promises
  • Leave open real or fake timers
  • Leave DOM listeners attached
  • Rely on excessive real-time delays
  • Produce unexpected console or process output

Some resources could potentially be auto-cleaned safely (e.g., timers), while others would act as signals that something unexpected happened during the test.

The intent is not to change default Jest behavior but to offer optional and configurable hygiene checks.

Motivation

Reliable tests are essential for developer confidence. However, tests can currently pass while still leaking asynchronous work that later affects unrelated tests.

The problem

Jest already provides tools such as --detectOpenHandles, but async work may still continue after a test completes without causing a failure.

As a result, tests may pass even when:

  • All async work triggered by the test has completed
  • All timers have been cleared
  • All async side effects have stopped

This can lead to tests that appear correct but create nondeterministic failures later.

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, which may later mutate global state and affect unrelated tests.
Tools like jest-doctor demonstrate that detecting unresolved async work at test boundaries helps surface these problems early.

Why this matters

A failing test is visible and actionable. A leaking test silently corrupts later tests.

Leaks often manifest as:

  • Random failures in unrelated files
  • Snapshot mismatches
  • Timeouts in later tests
  • CI failures that cannot be reproduced locally

By the time failures appear, the leaking test may have run much earlier, making the root cause difficult to find.

Example

Timers

Timers frequently cause flaky or hanging tests in large codebases.

In this example, a setInterval remains active after the test completes because fake timers are not used, preventing the process from exiting naturally. Jest will automatically force termination, but the root cause remains hidden.

const preventProcessExit = () => {
  setInterval(() =>{ doSomething() } , 100);
}

it('will run but never stop', async () => {
  preventProcessExit();
  await waitFor(() => expect(doSomething).toHaveBeenCalled());
});

Unexpected console output

Unexpected console output can indicate hidden problems.

it('leaks console.error', () => {
  const MyComponent = () => <div wrongProp={'hello'}>hello</div>;
  render(<MyComponent />);
  expect(screen.getByText('hello')).toBeInTheDocument();
});

React logs an error due to an invalid prop, but the test still passes, hiding the issue.

Pitch

Introduce optional test hygiene checks that help developers detect and prevent common sources of flaky tests and async leaks.

The proposal builds on ideas validated in the jest-doctor and aims to integrate them into Jest in a lightweight, incremental, and configurable manner.

Key goals:

  • Provide reliable detection of async leaks and side effects per test
  • Reduce flaky tests and non-deterministic CI failures
  • Improve developer feedback loops by failing tests at the moment leaks occur
  • Offer opt-in or configurable strictness levels to maintain backwards compatibility
  • Potentially auto-cleanup safe resources (e.g., timers) while clearly reporting risky behavior

This feature would help teams maintain test isolation at scale while preserving Jest’s fast and ergonomic developer experience.

Possible design considerations

To keep adoption practical:

  • Feature could be opt-in via config or CLI flag
  • Strictness levels could allow gradual rollout
  • Checks should minimize runtime overhead
  • Reporting should point clearly to the leaking test

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions