0
# Test Runner Implementation
1
2
The main `TestRunner` class providing both serial and parallel test execution with event-driven progress reporting, worker process coordination, and real-time test status events.
3
4
## Capabilities
5
6
### TestRunner Class
7
8
The default export implementing `EmittingTestRunner` for comprehensive test execution management.
9
10
```typescript { .api }
11
/**
12
* Main test runner class implementing event-driven test execution
13
* Supports both serial and parallel execution modes with worker management
14
*/
15
export default class TestRunner extends EmittingTestRunner {
16
constructor(globalConfig: Config.GlobalConfig, context: TestRunnerContext);
17
18
/**
19
* Execute a collection of tests with the specified options
20
* @param tests - Array of test objects containing path and context
21
* @param watcher - Test watcher for interrupt handling
22
* @param options - Execution options including serial mode flag
23
* @returns Promise that resolves when all tests complete
24
*/
25
runTests(
26
tests: Array<Test>,
27
watcher: TestWatcher,
28
options: TestRunnerOptions
29
): Promise<void>;
30
31
/**
32
* Register event listener for test execution events
33
* @param eventName - Name of the event to listen for
34
* @param listener - Function to call when event is emitted
35
* @returns Unsubscribe function to remove the listener
36
*/
37
on<Name extends keyof TestEvents>(
38
eventName: Name,
39
listener: (eventData: TestEvents[Name]) => void | Promise<void>
40
): UnsubscribeFn;
41
}
42
```
43
44
**Usage Examples:**
45
46
```typescript
47
import TestRunner from "jest-runner";
48
import { TestWatcher } from "jest-watcher";
49
import type { Test } from "@jest/test-result";
50
51
// Create runner with configuration
52
const runner = new TestRunner(globalConfig, {
53
changedFiles: new Set(["/changed/file.js"]),
54
sourcesRelatedToTestsInChangedFiles: new Set(["/source/file.js"])
55
});
56
57
// Set up event listeners
58
runner.on('test-file-start', ([test]) => {
59
console.log(`Starting: ${test.path}`);
60
});
61
62
runner.on('test-file-success', ([test, result]) => {
63
console.log(`✓ ${test.path} - ${result.numPassingTests} tests passed`);
64
});
65
66
runner.on('test-file-failure', ([test, error]) => {
67
console.error(`✗ ${test.path} failed:`, error.message);
68
});
69
70
// Execute tests in parallel
71
await runner.runTests(tests, watcher, { serial: false });
72
73
// Execute tests serially (useful for debugging)
74
await runner.runTests(tests, watcher, { serial: true });
75
```
76
77
### Test Execution Modes
78
79
The runner supports two execution modes with different characteristics and use cases.
80
81
#### Parallel Execution
82
83
Default mode that executes tests across multiple worker processes for optimal performance.
84
85
```typescript
86
// Parallel execution (default)
87
await runner.runTests(tests, watcher, { serial: false });
88
```
89
90
**Features:**
91
- Uses `jest-worker` to spawn worker processes
92
- Configurable worker count via `globalConfig.maxWorkers`
93
- Memory limit enforcement with `workerIdleMemoryLimit`
94
- Automatic worker cleanup and graceful shutdown
95
- Real-time progress reporting through worker communication
96
97
#### Serial Execution
98
99
Single-threaded execution mode that runs tests one by one in the main process.
100
101
```typescript
102
// Serial execution
103
await runner.runTests(tests, watcher, { serial: true });
104
// Sets process.env.JEST_WORKER_ID = '1'
105
```
106
107
**Features:**
108
- Runs in main process with `JEST_WORKER_ID = '1'`
109
- Simplified debugging and error reporting
110
- No worker process overhead
111
- Sequential test execution with rate limiting
112
113
### Event System
114
115
The runner emits typed events throughout test execution for real-time monitoring and integration.
116
117
```typescript { .api }
118
// Available events from TestEvents interface
119
type TestEvents = {
120
'test-file-start': [Test];
121
'test-file-success': [Test, TestResult];
122
'test-file-failure': [Test, SerializableError];
123
// Additional events may be forwarded from test frameworks
124
};
125
```
126
127
**Event Flow:**
128
1. `test-file-start` - Emitted when a test file begins execution
129
2. `test-file-success` - Emitted when a test file completes successfully
130
3. `test-file-failure` - Emitted when a test file fails or throws an error
131
132
### Worker Process Management
133
134
The parallel execution mode uses sophisticated worker management for optimal performance.
135
136
**Worker Configuration:**
137
- Worker count controlled by `globalConfig.maxWorkers`
138
- Memory limits enforced via `workerIdleMemoryLimit`
139
- Worker threads support via `globalConfig.workerThreads`
140
- Retry logic with up to 3 attempts per test
141
- Graceful shutdown with force-exit detection
142
143
**Worker Communication:**
144
- Bidirectional communication between main process and workers
145
- Real-time event forwarding from workers to main process
146
- Serialized context and configuration data transmission
147
- Custom message handling via `UNSTABLE_onCustomMessage`
148
149
### Error Handling and Interruption
150
151
The runner provides robust error handling and graceful interruption support.
152
153
**Interruption Handling:**
154
```typescript
155
// Watcher-based interruption
156
const watcher = new TestWatcher({ isWatchMode: true });
157
watcher.on('change', (state) => {
158
if (state.interrupted) {
159
// Tests will be cancelled gracefully
160
}
161
});
162
```
163
164
**Error Management:**
165
- Individual test failures don't stop the entire run
166
- Worker process crashes are handled with retries
167
- Memory leaks are detected and reported
168
- Graceful cleanup on interruption or completion
169
170
## Types
171
172
```typescript { .api }
173
interface Test {
174
path: string;
175
context: TestContext;
176
}
177
178
interface TestContext {
179
config: Config.ProjectConfig;
180
moduleMap: ModuleMap;
181
resolver: Resolver;
182
}
183
184
interface TestResult {
185
numFailingTests: number;
186
numPassingTests: number;
187
numPendingTests: number;
188
numTodoTests: number;
189
perfStats: TestPerformanceStats;
190
testFilePath: string;
191
console: ConsoleBuffer;
192
leaks: boolean;
193
// Additional properties for coverage, memory usage, etc.
194
}
195
196
interface SerializableError {
197
message: string;
198
stack?: string;
199
type: string;
200
code?: string;
201
}
202
```