@matteo.collina/test-reporter

A custom test reporter for node:test designed for large-scale projects with stuck test detection


Keywords
nodejs, test, reporter, testing, node:test, test-runner, large-scale, flaky-tests, stuck-tests, cli
License
MIT
Install
npm install @matteo.collina/test-reporter@1.0.0

Documentation

@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-reporter

Usage

Basic Usage

# After installing
node --test --test-reporter=@matteo.collina/test-reporter

# Or download and use directly
node --test --test-reporter=./node_modules/@matteo.collina/test-reporter/reporter/reporter.js

With 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 --test-reporter=@matteo.collina/test-reporter

With Parallel Execution

The reporter supports parallel test execution:

node --test --test-reporter=@matteo.collina/test-reporter --test-concurrency=4

Programmatic Usage

const reporter = require('@matteo.collina/test-reporter');

// Use with node:test runner

Options

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 ..................................... 67ms

Incomplete 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 requests

Final 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 jobs

Non-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 jobs

Why 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 utilities

Event Flow

  1. node:test sends events through the async generator
  2. reporter.js receives events (test:start, test:pass, test:fail, etc.)
  3. state-tracker.js maintains a map of tests by file and completion status
  4. printer.js formats output for TTY or non-TTY environments
  5. On SIGINT/SIGTERM/exit, incomplete tests are reported

Contributing

Please see the GitHub repository for source code and issues.

License

MIT