## TL;DR
The timed-out test is usually innocent: a `before` or `beforeEach` hook (or an earlier test in the same file) eats most of the 2-second budget, and the named test just happens to be holding the bag when the timer fires. Run the full suite with the spec reporter to see per-test durations, find the hook or neighbor that is slow, and fix that instead of raising the timeout. The timeout is a messenger, not the problem.

```text
mocha "Error: Timeout of 2000ms exceeded" only when the full suite runs in CI: how to find the slow hook
```

## Steps
1. Run the full suite the way CI does, with the spec reporter: `npx mocha --reporter spec`. The reporter prints each test's duration in milliseconds. Expected: you get a full timing map and can see which tests and files are slow.
2. Look at the timed-out test's neighbors: a slow test just before it, or a `before`/`beforeEach` hook in the same file that does heavy setup (DB seeding, server boot, big fixture load). Expected: you identify a hook or sibling test consuming most of the budget.
3. Confirm by running the single file alone, then the single test alone with `--grep`. Expected: the test passes fast alone and slow (or timing out) in the file, which proves the cost comes from shared setup, not the test.
4. Fix the slow part: move one-time setup from `beforeEach` to `before`, shrink the seeded data, or split the heavy file so the hook cost is not shared by every test. Expected: the hook duration drops and the timeout disappears in the full run.
5. Rerun the full suite in CI. Expected: no timeout errors and the total suite time is lower.

## Use this when
- Mocha reports "Timeout of 2000ms exceeded" only in the full CI run
- The same test passes quickly when run alone with --grep
- You suspect hooks or neighboring tests, not the failing test itself

## Not for this skill when
- The test hangs forever even alone (that is an unresolved promise or missing done, not a slow hook)
- The test is genuinely slow and needs a longer timeout on its own merits
- The runner is jest or vitest, which attribute timeouts differently

## Variant phrasings
- mocha timeout only when running full suite
- mocha 2000ms exceeded in CI but passes locally alone
- find slow mocha hook causing timeout

## Why it happens
Mocha's timeout covers the test plus its hooks: a `beforeEach` that takes 1.9 seconds leaves 100ms for the test itself. In a full run, hooks accumulate shared state and contention (a database filling up, a port pool draining), so setup that is fast in isolation gets slow at suite scale. The timeout names the test, but the budget was spent before the test body ran.

## Edge cases
- Root-level hooks (in a root hook plugin or a top-level beforeEach) affect every file; check those when many files time out at once.
- `--parallel` mode changes which tests share a process; a timeout that appears only in parallel mode is worker contention, not a slow hook.
- Do not raise the timeout globally to silence this. It hides the slow setup and makes the whole suite slower for everyone.

## Provenance

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