0
# Environment Integration
1
2
Jest environment enhancement utilities that provide Stryker-specific functionality including instrumenter context sharing and test event handling for coverage analysis.
3
4
## Capabilities
5
6
### Jest Environment Mixin
7
8
Enhances Jest environment classes with Stryker integration for mutation testing and coverage analysis.
9
10
```typescript { .api }
11
/**
12
* Mixin function that enhances a Jest environment class with Stryker functionality
13
* Adds instrumenter context sharing and test event handling for coverage analysis
14
* @param JestEnvironmentClass - Jest environment class to enhance
15
* @returns Enhanced Jest environment class with Stryker integration
16
*/
17
export function mixinJestEnvironment<T extends typeof JestEnvironment>(
18
JestEnvironmentClass: T & { [STRYKER_JEST_ENV]?: true }
19
): T;
20
```
21
22
**Usage Examples:**
23
24
```typescript
25
import { mixinJestEnvironment } from "@stryker-mutator/jest-runner";
26
import NodeEnvironment from "jest-environment-node";
27
import JSDOMEnvironment from "jest-environment-jsdom";
28
29
// Enhance Node.js environment
30
const StrykerNodeEnvironment = mixinJestEnvironment(NodeEnvironment);
31
32
// Enhance JSDOM environment
33
const StrykerJSDOMEnvironment = mixinJestEnvironment(JSDOMEnvironment);
34
35
// Use in Jest configuration
36
module.exports = {
37
testEnvironment: StrykerNodeEnvironment,
38
// or
39
testEnvironment: "./custom-stryker-environment.js"
40
};
41
```
42
43
```typescript
44
// custom-stryker-environment.js
45
const { mixinJestEnvironment } = require("@stryker-mutator/jest-runner");
46
const NodeEnvironment = require("jest-environment-node").default;
47
48
module.exports = mixinJestEnvironment(NodeEnvironment);
49
```
50
51
### Pre-built Environment Exports
52
53
The package provides pre-built Jest environments with Stryker integration for common use cases.
54
55
```typescript { .api }
56
// Available as CommonJS exports through package.json exports map
57
58
// Node.js environment with Stryker integration
59
"@stryker-mutator/jest-runner/jest-env/node"
60
61
// JSDOM environment with Stryker integration
62
"@stryker-mutator/jest-runner/jest-env/jsdom"
63
64
// JSDOM v16 environment with Stryker integration
65
"@stryker-mutator/jest-runner/jest-env/jsdom-sixteen"
66
```
67
68
**Usage Examples:**
69
70
```javascript
71
// Jest configuration using pre-built environments
72
module.exports = {
73
// Use Node.js environment
74
testEnvironment: "@stryker-mutator/jest-runner/jest-env/node",
75
76
// Use JSDOM environment
77
testEnvironment: "@stryker-mutator/jest-runner/jest-env/jsdom",
78
79
// Use JSDOM v16 environment
80
testEnvironment: "@stryker-mutator/jest-runner/jest-env/jsdom-sixteen"
81
};
82
```
83
84
```typescript
85
// Import for programmatic use
86
const StrykerNodeEnv = require("@stryker-mutator/jest-runner/jest-env/node");
87
const StrykerJSDOMEnv = require("@stryker-mutator/jest-runner/jest-env/jsdom");
88
```
89
90
## Types
91
92
### Jest Environment Types
93
94
```typescript { .api }
95
import type {
96
JestEnvironment,
97
EnvironmentContext,
98
JestEnvironmentConfig,
99
} from '@jest/environment';
100
import type { Circus } from '@jest/types';
101
102
interface StrykerJestEnvironment extends JestEnvironment {
103
readonly [STRYKER_JEST_ENV]: true;
104
handleTestEvent: Circus.EventHandler;
105
}
106
107
interface EnvironmentContext {
108
testPath: string;
109
docblockPragmas: Record<string, string | string[]>;
110
console: Console;
111
}
112
113
interface JestEnvironmentConfig {
114
projectConfig: Config.ProjectConfig;
115
globalConfig: Config.GlobalConfig;
116
}
117
```
118
119
### Test Event Types
120
121
```typescript { .api }
122
namespace Circus {
123
interface Event {
124
name: string;
125
test?: TestEntry;
126
}
127
128
interface TestEntry {
129
name: string;
130
parent: DescribeBlock;
131
}
132
133
interface DescribeBlock {
134
name: string;
135
parent?: DescribeBlock;
136
}
137
138
interface State {
139
currentDescribeBlock: DescribeBlock;
140
currentlyRunningTest?: TestEntry;
141
}
142
143
type EventHandler = (event: Event, state: State) => Promise<void> | void;
144
}
145
```
146
147
### Instrumenter Context
148
149
```typescript { .api }
150
interface InstrumenterContext {
151
currentTestId?: string;
152
hitCount?: number;
153
hitLimit?: number;
154
activeMutant?: Mutant;
155
mutantCoverage?: MutantCoverage;
156
}
157
```
158
159
## Implementation Details
160
161
### Instrumenter Context Sharing
162
163
The mixin creates a shared context between the test environment and Stryker's instrumenter:
164
165
- **Global Access**: Available as `global.__stryker__` or custom namespace
166
- **Test Tracking**: Tracks current test ID for per-test coverage
167
- **Hit Limiting**: Monitors execution counts to prevent infinite loops
168
- **Mutant State**: Shares active mutant information during mutation testing
169
170
### Test Event Handling
171
172
The enhanced environment intercepts Jest test events for coverage analysis:
173
174
- **test_start**: Sets current test ID for coverage tracking
175
- **test_done**: Clears current test ID when test completes
176
- **Async Support**: Handles both synchronous and asynchronous test events
177
- **Event Forwarding**: Preserves original environment's event handling
178
179
### Coverage Analysis Integration
180
181
Per-test coverage analysis requires the environment mixin to:
182
183
1. **Track Test Execution**: Identify which test is currently running
184
2. **Associate Coverage**: Link code execution to specific tests
185
3. **Aggregate Results**: Collect coverage data across all tests
186
4. **Report Coverage**: Provide coverage information to Stryker
187
188
### Environment Compatibility
189
190
The mixin is designed to work with any Jest environment:
191
192
- **Node.js Environment**: Server-side testing with full Node.js APIs
193
- **JSDOM Environment**: Browser simulation with DOM APIs
194
- **Custom Environments**: Any environment extending Jest's base environment
195
- **Backward Compatibility**: Preserves existing environment functionality
196
197
### Test File Registration
198
199
The environment automatically registers test files with Stryker:
200
201
```typescript
202
// Tracks which test files have Stryker environment integration
203
state.testFilesWithStrykerEnvironment.add(context.testPath);
204
```
205
206
This information is used for:
207
- Coverage verification
208
- Test file validation
209
- Mutation testing optimization
210
- Error reporting and debugging
211
212
### Global Namespace Configuration
213
214
The environment respects custom global namespaces:
215
216
```typescript
217
// Uses configured namespace or defaults to '__stryker__'
218
const namespace = this.global.__strykerGlobalNamespace__ ?? '__stryker__';
219
this.#strykerContext = this.global[namespace] = state.instrumenterContext;
220
```
221
222
This allows for:
223
- Custom instrumenter configurations
224
- Avoiding naming conflicts
225
- Supporting multiple Stryker instances
226
- Compatibility with different Stryker versions