A plugin to use the jest test runner and framework in Stryker, the JavaScript mutation testing framework
npx @tessl/cli install tessl/npm-stryker-mutator--jest-runner@9.1.00
# StrykerJS Jest Runner
1
2
StrykerJS Jest Runner is a plugin that enables the use of Jest as a test runner and framework within Stryker, the JavaScript mutation testing framework. It provides seamless integration between Jest and Stryker, supporting advanced features like per-test coverage analysis, multiple Jest environments, and optimized test execution for mutation testing workflows.
3
4
## Package Information
5
6
- **Package Name**: @stryker-mutator/jest-runner
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @stryker-mutator/jest-runner`
10
- **Peer Dependency**: `@stryker-mutator/core ~9.1.0`
11
12
## Core Imports
13
14
```typescript
15
import { strykerPlugins, strykerValidationSchema, mixinJestEnvironment } from "@stryker-mutator/jest-runner";
16
```
17
18
For Jest environment integration:
19
20
```javascript
21
// These are pre-enhanced Jest environments (CommonJS exports)
22
// Node.js environment with Stryker integration
23
const JestEnvironmentNode = require("@stryker-mutator/jest-runner/jest-env/node");
24
25
// JSDOM environment with Stryker integration
26
const JestEnvironmentJsdom = require("@stryker-mutator/jest-runner/jest-env/jsdom");
27
28
// JSDOM v16 environment with Stryker integration
29
const JestEnvironmentJsdomSixteen = require("@stryker-mutator/jest-runner/jest-env/jsdom-sixteen");
30
```
31
32
## Basic Usage
33
34
### Stryker Configuration
35
36
```javascript
37
// stryker.conf.js
38
module.exports = {
39
testRunner: "jest",
40
coverageAnalysis: "perTest", // or "all" or "off"
41
jest: {
42
projectType: "custom", // or "create-react-app"
43
enableFindRelatedTests: true,
44
config: {
45
// Custom Jest configuration
46
testEnvironment: "node"
47
}
48
}
49
};
50
```
51
52
### Jest Environment Integration
53
54
```typescript
55
import { mixinJestEnvironment } from "@stryker-mutator/jest-runner";
56
import { TestEnvironment } from "@jest/environment";
57
58
// Enhance Jest environment with Stryker integration
59
const StrykerJestEnvironment = mixinJestEnvironment(TestEnvironment);
60
```
61
62
## Architecture
63
64
The Jest Runner is built around several key components:
65
66
- **Plugin System**: Integrates with Stryker's plugin architecture using factory pattern
67
- **Test Adapter Pattern**: Abstracts Jest version differences through adapters
68
- **Configuration Management**: Handles Jest config loading for different project types
69
- **Environment Enhancement**: Provides Jest environment mixins for mutation testing
70
- **Coverage Analysis**: Implements per-test and global coverage tracking
71
- **Hit Limiting**: Prevents infinite loops during mutation testing
72
73
## Capabilities
74
75
### Stryker Plugin Integration
76
77
Core plugin registration and validation schema for Stryker integration. Provides the main entry point for using Jest as a test runner in Stryker mutation testing.
78
79
```typescript { .api }
80
export const strykerPlugins: Array<PluginDeclaration>;
81
82
export const strykerValidationSchema: JestRunnerOptionsSchema;
83
```
84
85
[Plugin Integration](./plugin-integration.md)
86
87
### Jest Test Runner
88
89
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.
90
91
```typescript { .api }
92
export class JestTestRunner implements TestRunner {
93
init(): Promise<void>;
94
capabilities(): TestRunnerCapabilities;
95
dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
96
mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
97
}
98
99
export function createJestTestRunnerFactory(
100
namespace?: typeof INSTRUMENTER_CONSTANTS.NAMESPACE | '__stryker2__'
101
): {
102
(injector: Injector<PluginContext>): JestTestRunner;
103
inject: ['$injector'];
104
};
105
106
export const jestTestRunnerFactory: ReturnType<typeof createJestTestRunnerFactory>;
107
```
108
109
[Test Runner](./test-runner.md)
110
111
### Jest Environment Integration
112
113
Jest environment enhancement utilities that provide Stryker-specific functionality including instrumenter context sharing and test event handling for coverage analysis.
114
115
```typescript { .api }
116
export function mixinJestEnvironment<T extends typeof JestEnvironment>(
117
JestEnvironmentClass: T & { [STRYKER_JEST_ENV]?: true }
118
): T;
119
```
120
121
[Environment Integration](./environment-integration.md)
122
123
### Configuration Management
124
125
Configuration loading and validation for different Jest project types including custom projects and Create React App setups. Handles Jest config merging and validation.
126
127
```typescript { .api }
128
export interface JestOptions {
129
projectType: JestProjectType;
130
configFile?: string;
131
config?: { [k: string]: unknown };
132
enableFindRelatedTests: boolean;
133
}
134
135
export type JestProjectType = 'create-react-app' | 'custom';
136
137
export interface JestRunnerOptions {
138
jest: JestOptions;
139
[k: string]: unknown;
140
}
141
142
export interface JestRunnerOptionsWithStrykerOptions extends StrykerOptions, JestRunnerOptions {}
143
```
144
145
[Configuration Management](./configuration.md)
146
147
### Utility Functions and Classes
148
149
Core utility functions and wrapper classes for Jest integration, version handling, and coverage validation.
150
151
```typescript { .api }
152
export class JestWrapper {
153
getVersion(): string;
154
}
155
156
export class JestConfigWrapper {
157
// Configuration loading and manipulation utilities
158
}
159
160
export function verifyAllTestFilesHaveCoverage(
161
jestResult: AggregatedResult,
162
testFilesWithStrykerEnvironment: Set<string>
163
): string | undefined;
164
165
export function withCoverageAnalysis(
166
jestConfig: Config.InitialOptions,
167
coverageAnalysis: CoverageAnalysis,
168
jestWrapper: JestWrapper
169
): Config.InitialOptions;
170
171
export function withHitLimit(
172
jestConfig: Config.InitialOptions,
173
hitLimit: number | undefined,
174
jestWrapper: JestWrapper
175
): Config.InitialOptions;
176
177
export const JEST_OVERRIDE_OPTIONS: Readonly<Config.InitialOptions>;
178
179
export const pluginTokens: {
180
readonly requireFromCwd: 'requireFromCwd';
181
readonly resolve: 'resolve';
182
readonly resolveFromDirectory: 'resolveFromDirectory';
183
readonly configLoader: 'configLoader';
184
readonly processEnv: 'processEnv';
185
readonly jestTestAdapter: 'jestTestAdapter';
186
readonly globalNamespace: 'globalNamespace';
187
readonly jestWrapper: 'jestWrapper';
188
readonly jestConfigWrapper: 'jestConfigWrapper';
189
};
190
```
191
192
[Utilities](./utilities.md)
193
194
## Types
195
196
### Core Plugin Types
197
198
```typescript { .api }
199
interface PluginDeclaration {
200
kind: PluginKind;
201
name: string;
202
factory: Function;
203
}
204
205
interface TestRunnerCapabilities {
206
reloadEnvironment: boolean;
207
}
208
```
209
210
### Test Execution Types
211
212
```typescript { .api }
213
interface DryRunOptions {
214
coverageAnalysis: CoverageAnalysis;
215
files: string[];
216
}
217
218
interface MutantRunOptions {
219
activeMutant: Mutant;
220
sandboxFileName: string;
221
testFilter?: string[];
222
disableBail: boolean;
223
hitLimit?: number;
224
}
225
226
interface DryRunResult {
227
status: DryRunStatus;
228
tests?: TestResult[];
229
errorMessage?: string;
230
mutantCoverage?: MutantCoverage;
231
}
232
233
interface MutantRunResult {
234
status: MutantRunStatus;
235
tests?: TestResult[];
236
errorMessage?: string;
237
killedBy?: string[];
238
survivalReason?: string;
239
}
240
```
241
242
### Jest Integration Types
243
244
```typescript { .api }
245
interface RunSettings {
246
jestConfig: Config.InitialOptions;
247
testNamePattern?: string;
248
fileNamesUnderTest?: string[];
249
testLocationInResults?: boolean;
250
}
251
252
interface JestRunResult {
253
results: AggregatedResult;
254
globalConfig: Config.GlobalConfig;
255
}
256
257
interface JestTestAdapter {
258
run(settings: RunSettings): Promise<JestRunResult>;
259
}
260
```
261
262
### Jest and Stryker Core Types
263
264
```typescript { .api }
265
// Jest configuration types (from @jest/types)
266
namespace Config {
267
interface InitialOptions {
268
[key: string]: unknown;
269
testEnvironment?: string;
270
collectCoverageFrom?: string[];
271
coverageReporters?: string[];
272
setupFilesAfterEnv?: string[];
273
transform?: { [key: string]: string };
274
testMatch?: string[];
275
testPathIgnorePatterns?: string[];
276
moduleNameMapping?: { [key: string]: string };
277
}
278
279
interface GlobalConfig extends InitialOptions {
280
projects: ProjectConfig[];
281
watch: boolean;
282
watchman: boolean;
283
}
284
285
interface ProjectConfig extends InitialOptions {
286
displayName?: string;
287
rootDir: string;
288
testMatch: string[];
289
}
290
}
291
292
// Jest test result types (from @jest/test-result)
293
interface AggregatedResult {
294
numFailedTests: number;
295
numPassedTests: number;
296
numPendingTests: number;
297
numTotalTests: number;
298
success: boolean;
299
testResults: TestResult[];
300
}
301
302
// Stryker core types
303
type CoverageAnalysis = 'off' | 'all' | 'perTest';
304
305
interface Mutant {
306
id: string;
307
fileName: string;
308
mutatorName: string;
309
replacement: string;
310
range: [number, number];
311
}
312
313
enum DryRunStatus {
314
Complete = 'Complete',
315
Error = 'Error',
316
Timeout = 'Timeout'
317
}
318
319
enum MutantRunStatus {
320
Killed = 'Killed',
321
Survived = 'Survived',
322
Timeout = 'Timeout',
323
Error = 'Error'
324
}
325
326
interface TestResult {
327
id: string;
328
name: string;
329
status: TestStatus;
330
timeSpentMs?: number;
331
failureMessage?: string;
332
}
333
334
enum TestStatus {
335
Success = 'Success',
336
Failed = 'Failed',
337
Skipped = 'Skipped'
338
}
339
340
// Stryker constants
341
const INSTRUMENTER_CONSTANTS = {
342
NAMESPACE: '__stryker__'
343
} as const;
344
```