A test suite from minutes to seconds
In short: tests took minutes, so nobody ran them. Now the suite runs in seconds and covers the code that actually matters — regressions get caught while developing, not after release.
Context
The same Nx monorepo as the other case studies — 10+ libraries, Jest, shared CI. The suite was slow enough that nobody ran it locally; tests had become something CI complains about after you push, not something that guides you while you work.
Problem
Four problems stacked on top of each other. Every test run type-checked every file it touched, from scratch. Every run executed everything, whether you changed one library or none. A big slice of the suite was noise — ~70 auto-generated "should create" specs compiling full components to assert nothing. And the code that most deserved tests — the spatial index and registry powering the rendering and event-delegation work — had none at all. Underneath it, the toolchain sat on an EOL Node with lint crashing outright.
What changed
| Change | Before | After | Gain |
|---|---|---|---|
| Transpile-only test transforms | ts-jest ran a full type-check on every file it transformed | isolatedModules — transpilation only; types are already caught by build and lint | cold run 6.9s → 2.2s per lib (~3×) |
| Run only what changed | one command, always the whole suite (~18s) | nx affected with 6 parallel workers and caching | ~3.5s cached |
| Deleted ~70 empty specs | "should create" boilerplate — TestBed + compileComponents for one trivial assertion each | gone (−3,142 lines) — no more paying compile time for fake coverage | less work, honest coverage |
| Real tests for the core domain | the spatial index, registry and conflict logic — the heart of the app — had zero tests | +1,167 lines of meaningful tests over the critical paths | regressions caught, not shipped |
| jsdom polyfill for SVGPathElement | a vendored dependency crashed one library’s whole suite on load | a small stub installed in the shared test setup | suite runs at all |
| Toolchain pinned to Node 22 | Node 16 (EOL), no pin — lint crashed on structuredClone, environments drifted | .nvmrc + engines + engine-strict — install fails fast on the wrong Node | same behavior locally and in CI |
The counterintuitive part
Coverage went up while thousands of test lines were deleted. An empty "should create" spec is worse than no spec: it costs compile time on every run and reports coverage that isn't there. Swapping ~3,000 lines of boilerplate for ~1,200 lines of real tests over the core domain made the suite faster and more trustworthy at the same time.
Why speed is a coverage feature
A suite that takes minutes gets run at the end, if at all. A suite that takes seconds gets run on every save — and starts actually preventing regressions instead of documenting them. The same playbook later cut a second suite from minutes to seconds at a US fintech: the details differ, the pattern doesn't.
Slow tests don't just waste time — they change behavior. Once a suite runs in seconds, it stops being a CI gate and becomes part of the feedback loop; that's when tests start paying for themselves.