## TL;DR
After the Jest 27 upgrade, fake timers default to the modern implementation, whose API differs from the legacy one. Pass explicit options to jest.useFakeTimers, for example a doNotFake list for the pieces you need real, and set the system time with jest.setSystemTime. Most breakage is tests that relied on legacy quirks.

## Problem
Tests that passed on legacy fake timers now fail or hang after upgrading to Jest 27 or later.

## Steps
1. Find every jest.useFakeTimers() call with no arguments. Expected: you have the full list of affected tests.
2. Replace bare calls with explicit config, for example jest.useFakeTimers({ advanceTimers: true }) or a doNotFake list for timers you want real. Expected: timer behavior is explicit in each test.
3. Replace Date-mocking hacks with jest.setSystemTime inside the fake-timer block. Expected: Date.now() returns the mocked time.
4. Run the suite. Expected: previously hanging tests complete and time-based assertions pass.
5. If a legacy-only library truly cannot work with modern timers, set timers to 'legacy' in Jest config as a last resort. Expected: old behavior returns; plan the migration anyway.

## When to use
- Upgrading Jest 26 to 27+ broke timer-dependent tests.
- jest.advanceTimersByTime seems to do nothing, or promises never resolve.
- Date.now() is not mocked the way the old tests assumed.

## When not to use
- You are still on Jest 26 or below; legacy is the default there.
- The failure is a real timeout, not a timer-mock issue.
- You use Vitest; its vi.useFakeTimers has its own API.

## Tool compatibility
- Jest 27, 28, 29, 30: modern timers are the default; config key timers accepts 'modern' or 'legacy'.
- jest.useFakeTimers(options) supports advanceTimers, doNotFake, now, and timerLimit.

## Variant phrasings
### jest modern fake timers not advancing
Usually a missing advanceTimers option, or awaiting a real promise inside fake time; make the config explicit.
### jest.useFakeTimers broke Date mocking
Use jest.setSystemTime; modern timers fake Date by default, so manual Date stubs now conflict.

## Why it happens
Legacy timers replaced timer functions with simple mocks that had loose semantics. Modern timers use a fuller fake-clock implementation with stricter, more correct behavior, so tests written against legacy quirks break.

## Edge cases
- doNotFake with nextTick and setImmediate keeps promise-heavy code moving while timers stay fake.
- performance.now() is faked too; animation-frame style tests need it unfaked or advanced manually.
- Mixing real network calls with fake timers hangs; unfake or mock the network layer.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_BSYqkmxKYL0q9tbbmVMMGQ
