Guide

A flaky test is one that fails without a code change. Flakes train the team to ignore red CI — the most expensive cultural failure a suite can cause. Treat them as P0.

Policy that works: quarantine a flake immediately, fix or delete within days, never "retry until green" as the permanent solution. A quarantined job is a temporary hospital with owners and tickets, not a permanent junk drawer.

Concept

Shared mutable fixtures and sleeps are common flake factories. Prefer the isolation habits in testing behavior and the cost model in test levels.

Causes and fixes

CauseFix
Time / clocksInject Clock; freeze time in tests
OrderingNo shared mutable globals; isolate DB per test
ConcurrencyDeterministic locks or single-thread test runs for that case
NetworkFake or record/replay; never hit live APIs in unit CI
Sleeps / waitsWait on conditions, not sleep(500)
Random ports / filesTemp dirs; allocate ports dynamically

When you inherit a bad suite, do not rewrite it wholesale. Apply the same strangler mindset as legacy refactors: add good tests on the path of current features, quarantine flakes, delete worthless tests when you touch their code.

A healthy CI pipeline usually stages a fast gate (unit + lint + types in under a few minutes on every push), then integration with shards (tens of minutes max for the default PR check), then nightly or pre-release E2E and mutation on hot packages. Fail the build on new flakes in the default gate.

Document how to run the smallest relevant subset locally (pnpm test path/to/file) so people actually run tests before push. A suite that only runs in CI will be developed blind and stay brittle.

When talking to PMs and managers, translate: "This flake burns ~Z engineer-hours/week in retriggers; fixing it is capacity, not polish." Same facts, outcome language.

Common mistakes

  • Retry until green as the permanent fix. You trained the team to ignore red.
  • Leaving flakes red for weeks. Nobody trusts CI.
  • A quarantine lane with no owner. It becomes a junk drawer.
  • sleep(500) to "stabilize" a test. Wait on the condition.

Check yourself

  1. A test failed on main with no diff. What do you do today? Quarantine it with an owner. Fix or delete within days. Do not merge retries as the policy.

  2. Why is sleep(500) a flake factory? You guessed a duration. Slow CI loses the race. Wait until the condition is true.

Key takeaways

  • Flakes are cultural debt. Quarantine and fix; do not normalize retries.
  • Isolate time, data, network, and files.
  • Fail the default gate on new flakes.
  • Keep local commands short so people run tests before they push.

Further learning

Software Engineering at GoogleAn open-source collection of core C++ library codeabseil.io

Next, extend confidence past CI with testing in production.