0
# Test Runner
1
2
Main test runner implementation that executes Jest tests within Stryker's mutation testing workflow. Handles dry runs for coverage analysis and mutant runs for testing specific mutations.
3
4
## Capabilities
5
6
### Jest Test Runner Class
7
8
The primary test runner implementation that manages Jest test execution for mutation testing.
9
10
```typescript { .api }
11
/**
12
* Main Jest test runner implementation for Stryker
13
* Manages Jest configuration, test execution, and result processing
14
*/
15
export class JestTestRunner implements TestRunner {
16
/**
17
* Initialize the test runner with Jest configuration
18
* Loads and merges Jest config from various sources
19
*/
20
init(): Promise<void>;
21
22
/**
23
* Get test runner capabilities
24
* @returns Capabilities indicating reloadEnvironment support
25
*/
26
capabilities(): TestRunnerCapabilities;
27
28
/**
29
* Execute dry run for initial test execution and coverage analysis
30
* @param options - Options including coverage analysis mode and files to test
31
* @returns Results of test execution with optional coverage data
32
*/
33
dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
34
35
/**
36
* Execute tests with an active mutant for mutation testing
37
* @param options - Options including active mutant, test filters, and limits
38
* @returns Results of mutant testing execution
39
*/
40
mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
41
}
42
```
43
44
**Usage Example:**
45
46
```typescript
47
import { JestTestRunner } from "@stryker-mutator/jest-runner";
48
// Note: Typically instantiated through Stryker's dependency injection
49
50
// Test runner is created and managed by Stryker internally
51
// Configuration is passed through Stryker options
52
const runner = new JestTestRunner(logger, options, adapter, configLoader, jestWrapper, namespace);
53
54
// Initialize with Jest configuration
55
await runner.init();
56
57
// Check capabilities
58
const caps = runner.capabilities(); // { reloadEnvironment: true }
59
60
// Execute dry run for coverage analysis
61
const dryResult = await runner.dryRun({
62
coverageAnalysis: 'perTest',
63
files: ['src/example.js']
64
});
65
66
// Execute mutant run
67
const mutantResult = await runner.mutantRun({
68
activeMutant: { id: '1', replacement: '>' },
69
sandboxFileName: 'src/example.js',
70
testFilter: ['should pass basic test'],
71
disableBail: false,
72
hitLimit: 10
73
});
74
```
75
76
### Test Runner Factory
77
78
Factory functions for creating Jest test runner instances with dependency injection.
79
80
```typescript { .api }
81
/**
82
* Create a Jest test runner factory with optional custom namespace
83
* @param namespace - Global namespace for instrumenter (defaults to Stryker namespace)
84
* @returns Factory function with dependency injection configuration
85
*/
86
export function createJestTestRunnerFactory(
87
namespace?: typeof INSTRUMENTER_CONSTANTS.NAMESPACE | '__stryker2__'
88
): {
89
(injector: Injector<PluginContext>): JestTestRunner;
90
inject: ['$injector'];
91
};
92
93
/**
94
* Default Jest test runner factory instance
95
* Pre-configured with standard Stryker namespace
96
*/
97
export const jestTestRunnerFactory: ReturnType<typeof createJestTestRunnerFactory>;
98
```
99
100
**Usage Example:**
101
102
```typescript
103
import { createJestTestRunnerFactory, jestTestRunnerFactory } from "@stryker-mutator/jest-runner";
104
105
// Create custom factory with different namespace
106
const customFactory = createJestTestRunnerFactory('__customStryker__');
107
108
// Use default factory (typical usage)
109
const defaultFactory = jestTestRunnerFactory;
110
111
// Factories are used by Stryker's dependency injection system
112
// to create test runner instances with proper dependencies
113
```
114
115
### Jest Test Adapters
116
117
Adapter pattern implementation that abstracts differences between Jest versions.
118
119
```typescript { .api }
120
/**
121
* Factory function that creates version-appropriate Jest test adapter
122
* Automatically selects adapter based on detected Jest version
123
* @returns Jest test adapter instance compatible with current Jest version
124
*/
125
export function jestTestAdapterFactory(): JestTestAdapter;
126
127
/**
128
* Abstract interface for Jest test execution adapters
129
* Provides version-agnostic interface for running Jest tests
130
*/
131
export interface JestTestAdapter {
132
run(settings: RunSettings): Promise<JestRunResult>;
133
}
134
135
/**
136
* Jest test adapter for versions prior to 25.x
137
* Handles legacy Jest API and configuration patterns
138
*/
139
export class JestLessThan25TestAdapter implements JestTestAdapter {
140
run(settings: RunSettings): Promise<JestRunResult>;
141
}
142
143
/**
144
* Jest test adapter for versions 25.x and later
145
* Uses modern Jest API with improved performance and features
146
*/
147
export class JestGreaterThan25TestAdapter implements JestTestAdapter {
148
run(settings: RunSettings): Promise<JestRunResult>;
149
}
150
```
151
152
**Usage Example:**
153
154
```typescript
155
import { jestTestAdapterFactory } from "@stryker-mutator/jest-runner";
156
157
// Factory automatically selects appropriate adapter
158
const adapter = jestTestAdapterFactory();
159
160
// Execute tests with version-appropriate adapter
161
const result = await adapter.run({
162
jestConfig: myJestConfig,
163
fileNamesUnderTest: ['src/example.js'],
164
testLocationInResults: true
165
});
166
```
167
168
## Types
169
170
### Test Runner Interface
171
172
```typescript { .api }
173
interface TestRunner {
174
init(): Promise<void>;
175
capabilities(): TestRunnerCapabilities;
176
dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
177
mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
178
}
179
180
interface TestRunnerCapabilities {
181
reloadEnvironment: boolean;
182
}
183
```
184
185
### Options and Results
186
187
```typescript { .api }
188
interface DryRunOptions {
189
coverageAnalysis: CoverageAnalysis;
190
files: string[];
191
}
192
193
interface MutantRunOptions {
194
activeMutant: Mutant;
195
sandboxFileName: string;
196
testFilter?: string[];
197
disableBail: boolean;
198
hitLimit?: number;
199
}
200
201
interface DryRunResult {
202
status: DryRunStatus;
203
tests?: TestResult[];
204
errorMessage?: string;
205
mutantCoverage?: MutantCoverage;
206
}
207
208
interface MutantRunResult {
209
status: MutantRunStatus;
210
tests?: TestResult[];
211
errorMessage?: string;
212
killedBy?: string[];
213
survivalReason?: string;
214
}
215
216
type CoverageAnalysis = 'off' | 'all' | 'perTest';
217
218
enum DryRunStatus {
219
Complete = 'Complete',
220
Error = 'Error',
221
Timeout = 'Timeout'
222
}
223
224
enum MutantRunStatus {
225
Killed = 'Killed',
226
Survived = 'Survived',
227
Error = 'Error',
228
Timeout = 'Timeout'
229
}
230
```
231
232
### Mutant and Test Types
233
234
```typescript { .api }
235
interface Mutant {
236
id: string;
237
replacement: string;
238
fileName: string;
239
location: Location;
240
}
241
242
interface TestResult {
243
id: string;
244
name: string;
245
status: TestStatus;
246
timeSpentMs: number;
247
fileName?: string;
248
startPosition?: Position;
249
failureMessage?: string;
250
}
251
252
enum TestStatus {
253
Success = 'Success',
254
Failed = 'Failed',
255
Skipped = 'Skipped'
256
}
257
258
interface Position {
259
line: number;
260
column: number;
261
}
262
```
263
264
## Implementation Details
265
266
### Configuration Merging
267
268
The test runner merges Jest configuration from multiple sources:
269
270
1. **File-based config**: Loaded from Jest config files or package.json
271
2. **User config**: Custom configuration from Stryker jest options
272
3. **Override config**: Internal Stryker optimizations and requirements
273
274
### Coverage Analysis Modes
275
276
- **`off`**: No coverage analysis, fastest execution
277
- **`all`**: Global coverage analysis for all tests
278
- **`perTest`**: Individual test coverage tracking (recommended)
279
280
### Hit Limiting
281
282
Prevents infinite loops during mutation testing by limiting the number of times instrumented code can be executed:
283
284
- Configurable hit limit per mutant run
285
- Automatic timeout when limit is exceeded
286
- Helps identify problematic mutations
287
288
### Environment Variables
289
290
The test runner manages several environment variables:
291
292
- **`BABEL_ENV`**: Set to 'test' for proper Babel transformation
293
- **`NODE_ENV`**: Set to 'test' for consistent environment
294
- **`FORCE_COLOR`**: Set to '0' to disable colored output
295
- **Active mutant variable**: Set during mutant runs for instrumenter
296
297
### Performance Optimizations
298
299
- **Related tests**: Uses `--findRelatedTests` to run only relevant tests
300
- **Disabled features**: Turns off Jest features that slow down mutation testing
301
- **Lazy execution**: Defers expensive operations until needed
302
- **Result caching**: Optimizes repeated test executions