Files
Colby McHenry 207621e60e test: eliminate chokidar/FSEvents race in watcher + staleness-banner tests
The watcher.test.ts pending-file-tracking tests and the mcp-staleness-banner.test.ts
suite drove the watcher with real `fs.writeFileSync` and waited on real chokidar
event delivery. Under parallel vitest execution, OS-level event subsystems
(FSEvents on macOS, inotify on Linux) serve many test files simultaneously and
event-delivery latency grows non-deterministically — measured **3/10 failure
rate** on full-suite runs (different test fails each run, all pass in isolation,
present on both pre-bridging `1821038` and current main `4d1a2b3`).

Fix: replace chokidar with a controllable EventEmitter for these tests.

- `__tests__/__helpers__/chokidar-mock.ts` — module-scoped fake that
  exposes `chokidarMockModule` (for `vi.mock('chokidar', ...)`) and
  `triggerFileEvent(root, event, relPath)` (for tests to synthesize
  chokidar events deterministically). `watch(root)` returns an
  EventEmitter that fires `ready` on the next microtask; tests' existing
  `watcher.waitUntilReady()` resolves immediately.

- `__tests__/watcher.test.ts` — hoists `vi.mock('chokidar', ...)` and
  refactors every event-driving test to call `triggerFileEvent(...)`
  instead of `fs.writeFileSync(...)` for the trigger. The pending-file
  tests now assert pendingFiles state synchronously (no more 8000ms
  waitFor for chokidar delivery). Filtering tests still verify
  FileWatcher's own filter chain (`isAlwaysIgnored` + `isSourceFile`)
  — what they always actually tested. One nuance: the node_modules
  filtering test previously also exercised chokidar's `ignored` callback
  (so node_modules dirs are never registered as watches); with chokidar
  mocked that OS-level behaviour isn't covered here. Commented inline;
  chokidar's `ignored` exclusion is a chokidar property, not a
  FileWatcher invariant.

- `__tests__/mcp-staleness-banner.test.ts` — same vi.mock at top, same
  `triggerFileEvent` pattern. Each test still does `fs.writeFileSync`
  for the on-disk content (so `cg.sync()` reads the new bytes) AND a
  `triggerFileEvent` to wake the watcher.

The watcher's actual debounce timer (real `setTimeout`) is left
untouched — that's the unit under test; deterministic timing would
change what the tests assert.

Measured before/after on the full suite (`npx vitest run`):

- Before fix: **3/10 failures** — different test fails each run, always
  from the pending-file-tracking or staleness-banner files.
- After fix: **0/10 failures** across the same 10-run sample.
- Bonus: test wall-clock dropped because the slow waitFor polls
  (8000ms+ on the pending-file tests) are gone — those waited on real
  chokidar delivery that was usually under 100ms but variable to seconds.

Total test count unchanged (928 passing + 2 pre-existing skips).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 02:36:38 -05:00
..
2026-01-18 16:25:00 -06:00