A flaky test passes and fails without any code change. Find the cause, then fix the cause.
Common causes:
- Timing: fixed sleeps, asserting before async work finishes, animations.
- Shared state: a module-level variable, an MSW handler or mock that wasn't reset, data left in a database.
- Order dependence: a test only passes after another test runs.
- Real network or third-party services.
- Environment differences: time zones, the current date, random values, or a slower CI machine.
To find the cause:
- Run the test alone, and run it in a loop.
- Run the suite in random or different order.
- Compare with CI.
- In Playwright, use the trace viewer.
Fixes:
- Wait for conditions with
findBy,waitForor web-first assertions instead of sleeping. - Reset state in
afterEach: mocks, handlers and timers. - Mock the network, and freeze time with fake timers.
- Make each test create its own data.
Retries can buy you time, but they shouldn't replace a real fix.
- Timing causes flakiness: sleeps, async work that isn't awaited, and animations.
- Shared state and test order dependence cause flakiness.
- Real network calls, dates, time zones and randomness cause flakiness.
- Reproduce it: run alone, in a loop and in another order, and use traces.
- Fix the cause. Retries are not a fix.
Read more