@matteo.collina/test-reporter
v1.0.0
Published
A custom test reporter for node:test designed for large-scale projects with stuck test detection
Maintainers
Readme
@matteo.collina/test-reporter
A custom test reporter for node:test designed specifically for large-scale projects with hundreds of test files and thousands of tests. Focuses on visibility, progress tracking, and especially diagnosing flaky/stuck tests.
Features
- 📄 File-level visibility: Pretty print each test file as it's processed with pass/total counters
- 🧪 Test-level visibility: Show each individual test with nesting support (describe → test)
- ⏳ Incomplete test detection (critical): When Ctrl-C is pressed, print exactly which tests never completed
- 💨 Real-time progress: Show what's currently running for large test suites
- ⚡ Slow test detection: Identify potential flaky tests by duration
- 🎨 Beautiful TTY output: Colors, unicode icons, and elegant formatting
- 📋 Clean CI output: Line-based, grep-friendly format when piped
Requirements
- Node.js 22+ (the reporter uses modern Node.js test runner APIs)
Installation
npm install --save-dev @matteo.collina/test-reporterUsage
Basic Usage
# After installing
node --test [email protected]/test-reporter
# Or download and use directly
node --test --test-reporter=./node_modules/@matteo.collina/test-reporter/reporter/reporter.jsWith Options
Options can be set via environment variables:
# Set options via environment
NODE_TEST_REPORTER_OPTIONS="timeout-warning=3000,stuck-threshold=10000,progress=off" \
node --test [email protected]/test-reporterWith Parallel Execution
The reporter supports parallel test execution:
node --test [email protected]/test-reporter --test-concurrency=4Programmatic Usage
const reporter = require('@matteo.collina/test-reporter');
// Use with node:test runnerOptions
| Option | Default | Description |
|--------|---------|-------------|
| timeout-warning | 5000 | Threshold (ms) for considering a test "slow" |
| stuck-threshold | 30000 | Threshold (ms) before warning about potentially stuck tests |
| show-passing | true | Show passing tests (set to false to see only failures) |
| show-skip | true | Show skipped tests |
| progress | auto | Progress mode: auto, on, or off |
Example Output
TTY Mode (Interactive Terminal)
📄 src/services/user.service.test.ts [3/4]
✓ UserService
✓ should create user ................................... 45ms
✓ should validate email ................................ 12ms
⏳ should handle edge cases ............................. ~5s •••
✗ should delete user ................................... 150ms
AssertionError: Expected user to be deleted
at src/services/user.service.test.ts:44:17
📄 src/api/routes.test.ts [2/2]
✓ GET /users
✓ returns 200 with user list ........................... 23ms
✓ POST /users
✓ creates new user ..................................... 67msIncomplete Tests Warning (Ctrl-C Pressed)
^C
⚠️ INCOMPLETE TESTS DETECTED
These tests started but never completed. The test at the bottom ran longest
and is most likely the one blocking:
⏳ src/db/connection.test.ts
└─ Database › should handle concurrent connections (45s ago)
⏳ src/cache/redis.test.ts
└─ RedisClient › should reconnect (12s ago)
⏳ src/queue/worker.test.ts
└─ Worker › should process jobs (8s ago)
💡 Tip: Check the last test for: infinite loops, blocking sync calls,
unawaited async, database deadlocks, or hanging network requestsFinal Summary
✓ TEST SUITE COMPLETE — 47 files | 312 passed | 3 failed | 5 skipped | 45.2s
❌ FAILURES (3):
1. src/services/user.service.test.ts:44 — should delete user
2. src/api/auth.test.ts:23 — should reject invalid token
3. src/db/connection.test.ts:87 — should rollback on error
⚡ SLOW TESTS (potential flaky tests):
1. 12.4s src/db/connection.test.ts — Database › should pool connections
2. 8.7s src/cache/redis.test.ts — RedisClient › should reconnect
3. 5.2s src/queue/worker.test.ts — Worker › should process jobsNon-TTY Mode (CI/Pipes)
FILE: src/services/user.service.test.ts [3/4]
PASS UserService > should create user [45ms]
PASS UserService > should validate email [12ms]
WARN UserService > should handle edge cases [~5s]
FAIL UserService > should delete user [150ms]
AssertionError: Expected user to be deleted
at src/services/user.service.test.ts:44:17
### PROCESS INTERRUPTED - INCOMPLETE TESTS
The following tests started but never completed:
(Ordered by start time - the last one likely caused the hang)
[45s] src/db/connection.test.ts::Database > should handle concurrent connections <-- LONGEST
[12s] src/cache/redis.test.ts::RedisClient > should reconnect
[ 8s] src/queue/worker.test.ts::Worker > should process jobsWhy This Reporter?
Problem: Stuck Tests in Large Codebases
In large projects with hundreds of test files, tests can hang due to:
- Infinite loops in async code
- Unawaited promises
- Database connection deadlocks
- Network request timeouts
- Blocking synchronous calls
Without visibility, you just see a hung test runner with no idea which test is stuck.
Solution: Incomplete Test Detection
This reporter tracks every test that receives test:start and compares it to test:complete. If a test never completes (common on SIGINT), it reports exactly which tests were stuck.
The longest-running incomplete test is shown last — that's most likely your culprit.
Architecture
reporter/
├── index.js # Entry point
├── reporter.js # Main async generator - handles node:test events
├── state-tracker.js # Tracks running/finished test state
└── printer.js # Formatting utilitiesEvent Flow
node:testsends events through the async generatorreporter.jsreceives events (test:start,test:pass,test:fail, etc.)state-tracker.jsmaintains a map of tests by file and completion statusprinter.jsformats output for TTY or non-TTY environments- On
SIGINT/SIGTERM/exit, incomplete tests are reported
Contributing
Please see the GitHub repository for source code and issues.
License
MIT
