$npx -y skills add girijashankarj/cursor-handbook --skill flaky-testDiagnose and fix flaky tests. Use when a test passes sometimes and fails other times.
| 1 | # Skill: Fix Flaky Tests |
| 2 | |
| 3 | ## Trigger |
| 4 | When a test is flaky — passes intermittently, fails on CI but not locally, or depends on timing/order. |
| 5 | |
| 6 | ## Steps |
| 7 | |
| 8 | ### Step 1: Reproduce |
| 9 | - [ ] Run the test 10+ times: `{{CONFIG.testing.testCommand}} -- --testPathPattern={file} --runInBand` |
| 10 | - [ ] Note failure rate and any pattern (e.g., fails when run with others) |
| 11 | - [ ] Run in isolation vs with full suite to check order dependency |
| 12 | |
| 13 | ### Step 2: Categorize |
| 14 | Common causes: |
| 15 | - **Timing** — Async not awaited; `setTimeout`/`setInterval`; race conditions |
| 16 | - **Shared state** — Mocks, globals, or DB state leaking between tests |
| 17 | - **Randomness** — `Date.now()`, `Math.random()`, `uuid` without seed |
| 18 | - **Order dependency** — Tests assume execution order; shared fixtures |
| 19 | - **Environment** — CI vs local (timezone, env vars, network) |
| 20 | |
| 21 | ### Step 3: Fix |
| 22 | |
| 23 | #### Timing |
| 24 | - Add `await` for all async operations |
| 25 | - Use `waitFor` or `act` for React updates |
| 26 | - Replace `setTimeout` with fake timers: `jest.useFakeTimers()` |
| 27 | - Increase timeout only as last resort; prefer fixing the race |
| 28 | |
| 29 | #### Shared State |
| 30 | - Reset mocks in `beforeEach`: `jest.clearAllMocks()` or `mockReset()` |
| 31 | - Use `beforeEach` to create fresh fixtures; avoid module-level state |
| 32 | - Run tests with `--runInBand` to isolate; fix root cause rather than rely on it |
| 33 | |
| 34 | #### Randomness |
| 35 | - Mock `Date.now()`, `Math.random()`, or ID generators |
| 36 | - Use `jest.setSystemTime()` for date-dependent tests |
| 37 | - Seed random if deterministic output is needed |
| 38 | |
| 39 | #### Order Dependency |
| 40 | - Make each test self-contained; no assumptions about other tests |
| 41 | - Use `beforeEach` for setup; avoid `afterAll` that affects later tests |
| 42 | |
| 43 | ### Step 4: Verify |
| 44 | - [ ] Run test 20+ times: `for i in {1..20}; do {{CONFIG.testing.testCommand}} -- --testPathPattern={file}; done` |
| 45 | - [ ] Run with full suite to ensure no regression |
| 46 | - [ ] Check CI passes on multiple runs |
| 47 | |
| 48 | ## Completion |
| 49 | - [ ] Test passes consistently (20/20 runs) |
| 50 | - [ ] No new flakiness introduced |
| 51 | - [ ] Root cause fixed, not masked (e.g., no arbitrary `sleep`) |