0
# Core Test Execution
1
2
The fundamental `runTest` function that executes individual test files with environment setup, framework integration, and result collection. This is the core engine that handles all aspects of running a single test file.
3
4
## Capabilities
5
6
### RunTest Function
7
8
The main test execution function that handles complete test lifecycle for individual test files.
9
10
```typescript { .api }
11
/**
12
* Execute a single test file with complete environment setup and teardown
13
* @param path - Absolute path to the test file
14
* @param globalConfig - Jest global configuration
15
* @param config - Project-specific configuration
16
* @param resolver - Module resolver for the test
17
* @param context - Test runner context with changed files information
18
* @param sendMessageToJest - Optional callback for sending events to Jest
19
* @returns Promise resolving to complete test results
20
*/
21
export default function runTest(
22
path: string,
23
globalConfig: Config.GlobalConfig,
24
config: Config.ProjectConfig,
25
resolver: Resolver,
26
context: TestRunnerContext,
27
sendMessageToJest?: TestFileEvent
28
): Promise<TestResult>;
29
```
30
31
**Usage Examples:**
32
33
The `runTest` function is internal to the jest-runner package and not directly exported. It is used internally by the `TestRunner` class. For most use cases, you should use the `TestRunner` class instead:
34
35
```typescript
36
import TestRunner from "jest-runner";
37
import { TestWatcher } from "jest-watcher";
38
import type { Test } from "@jest/test-result";
39
import type { Config } from "@jest/types";
40
41
// Use TestRunner to execute tests (recommended approach)
42
const runner = new TestRunner(globalConfig, context);
43
const watcher = new TestWatcher({ isWatchMode: false });
44
45
await runner.runTests([test], watcher, { serial: true });
46
```
47
48
Note: The `runTest` function is used internally by `TestRunner` for individual test execution but is not part of the public API.
49
50
### Test Execution Process
51
52
The `runTest` function follows a comprehensive execution process with multiple phases.
53
54
**Execution Phases:**
55
56
1. **File Analysis**: Read test file and parse docblock pragmas
57
2. **Environment Resolution**: Determine test environment (node, jsdom, custom)
58
3. **Transformer Setup**: Configure code transformation pipeline
59
4. **Environment Creation**: Instantiate test environment with console setup
60
5. **Runtime Initialization**: Create Jest runtime with module caching
61
6. **Setup Files**: Execute project setup files and configuration
62
7. **Test Framework Execution**: Run the actual test using configured framework
63
8. **Result Collection**: Gather test results, coverage, and performance data
64
9. **Cleanup**: Tear down environment and release resources
65
66
**Environment Setup:**
67
68
```typescript
69
// Test environment resolution from docblock or config
70
const testEnvironment = customEnvironment || projectConfig.testEnvironment;
71
const TestEnvironment = await transformer.requireAndTranspileModule(testEnvironment);
72
73
// Environment instantiation with configuration
74
const environment = new TestEnvironment({
75
globalConfig,
76
projectConfig: {
77
...projectConfig,
78
testEnvironmentOptions: {
79
...projectConfig.testEnvironmentOptions,
80
...extraTestEnvironmentOptions
81
}
82
}
83
}, {
84
console: testConsole,
85
docblockPragmas,
86
testPath: path
87
});
88
```
89
90
### Test Framework Integration
91
92
The function integrates with configurable test frameworks (Jest Circus, Jasmine, custom frameworks).
93
94
```typescript { .api }
95
/**
96
* Test framework function signature that runTest expects
97
*/
98
type TestFramework = (
99
globalConfig: Config.GlobalConfig,
100
config: Config.ProjectConfig,
101
environment: JestEnvironment,
102
runtime: RuntimeType,
103
testPath: string,
104
sendMessageToJest?: TestFileEvent
105
) => Promise<TestResult>;
106
```
107
108
**Framework Selection:**
109
- Uses `process.env.JEST_JASMINE === '1'` for Jasmine2 compatibility
110
- Falls back to `projectConfig.testRunner` (default: Jest Circus)
111
- Supports custom test frameworks implementing the `TestFramework` interface
112
113
### Console and Logging Management
114
115
Sophisticated console handling for different Jest modes and output capture.
116
117
**Console Modes:**
118
119
```typescript
120
// Silent mode - no output
121
if (globalConfig.silent) {
122
testConsole = new NullConsole(consoleOut, consoleOut, consoleFormatter);
123
}
124
125
// Verbose mode - immediate output
126
else if (globalConfig.verbose) {
127
testConsole = new CustomConsole(consoleOut, consoleOut, consoleFormatter);
128
}
129
130
// Default mode - buffered output
131
else {
132
testConsole = new BufferedConsole();
133
}
134
```
135
136
**Console Freezing:**
137
After test completion, the console is "frozen" to prevent logging after test completion, which helps detect asynchronous cleanup issues.
138
139
### Performance and Memory Tracking
140
141
Comprehensive performance monitoring and memory leak detection.
142
143
**Performance Metrics:**
144
145
```typescript { .api }
146
interface TestPerformanceStats {
147
start: number;
148
end: number;
149
runtime: number;
150
slow: boolean;
151
loadTestEnvironmentStart: number;
152
loadTestEnvironmentEnd: number;
153
setupFilesStart: number;
154
setupFilesEnd: number;
155
}
156
```
157
158
**Memory Management:**
159
- Optional leak detection with `LeakDetector`
160
- Heap usage tracking when `globalConfig.logHeapUsage` is enabled
161
- Garbage collection before memory measurement
162
- Source map cleanup to prevent memory leaks
163
164
### Coverage Collection
165
166
Support for both Babel-based and V8-based code coverage collection.
167
168
**Coverage Types:**
169
170
```typescript
171
// Babel-based coverage (default)
172
const coverage = runtime.getAllCoverageInfoCopy();
173
if (coverage && Object.keys(coverage).length > 0) {
174
result.coverage = coverage;
175
}
176
177
// V8-based coverage (when configured)
178
if (collectV8Coverage) {
179
await runtime.collectV8Coverage();
180
// ... execute test ...
181
await runtime.stopCollectingV8Coverage();
182
183
const v8Coverage = runtime.getAllV8CoverageInfoCopy();
184
if (v8Coverage && v8Coverage.length > 0) {
185
result.v8Coverage = v8Coverage;
186
}
187
}
188
```
189
190
### Error Handling and Process Management
191
192
Robust error handling with proper cleanup and process exit prevention.
193
194
**Process Exit Prevention:**
195
```typescript
196
// Override process.exit to prevent tests from killing the process
197
if (environment.global && environment.global.process && environment.global.process.exit) {
198
const realExit = environment.global.process.exit;
199
200
environment.global.process.exit = function exit(...args: Array<any>) {
201
const error = new ErrorWithStack(
202
`process.exit called with "${args.join(', ')}"`,
203
exit
204
);
205
// Log formatted error and call real exit
206
const formattedError = formatExecError(error, projectConfig, {noStackTrace: false});
207
process.stderr.write(formattedError);
208
return realExit(...args);
209
};
210
}
211
```
212
213
**Stack Trace Enhancement:**
214
- Increases `Error.stackTraceLimit` to 100 for better debugging
215
- Installs source map support for both runtime and test errors
216
- Preserves error stack traces before uninstalling source maps
217
218
### Setup Files Execution
219
220
Handles project-level setup files with support for both CommonJS and ESM.
221
222
```typescript
223
// Execute setup files before test execution
224
for (const path of projectConfig.setupFiles) {
225
const esm = runtime.unstable_shouldLoadAsEsm(path);
226
227
if (esm) {
228
await runtime.unstable_importModule(path);
229
} else {
230
const setupFile = runtime.requireModule(path);
231
if (typeof setupFile === 'function') {
232
await setupFile();
233
}
234
}
235
}
236
```
237
238
## Types
239
240
```typescript { .api }
241
interface TestResult {
242
console: ConsoleBuffer;
243
coverage?: CoverageMap;
244
displayName?: Config.DisplayName;
245
leaks: boolean;
246
memoryUsage?: number;
247
numFailingTests: number;
248
numPassingTests: number;
249
numPendingTests: number;
250
numTodoTests: number;
251
perfStats: TestPerformanceStats;
252
skipped: boolean;
253
testFilePath: string;
254
testResults: Array<AssertionResult>;
255
v8Coverage?: V8CoverageResult[];
256
}
257
258
interface TestRunnerContext {
259
changedFiles?: Set<string>;
260
sourcesRelatedToTestsInChangedFiles?: Set<string>;
261
}
262
263
interface AssertionResult {
264
ancestorTitles: Array<string>;
265
duration?: number;
266
failureDetails: Array<unknown>;
267
failureMessages: Array<string>;
268
fullName: string;
269
invocations?: number;
270
location?: Callsite;
271
numPassingAsserts: number;
272
retryReasons?: Array<string>;
273
status: 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled';
274
title: string;
275
}
276
277
interface ConsoleBuffer extends Array<LogEntry> {}
278
279
interface LogEntry {
280
message: string;
281
origin: string;
282
type: LogType;
283
}
284
285
type LogType = 'assert' | 'count' | 'debug' | 'dir' | 'dirxml' | 'error' | 'group' | 'groupCollapsed' | 'groupEnd' | 'info' | 'log' | 'time' | 'warn';
286
287
type TestFileEvent = (
288
eventName: string,
289
args: Array<any>
290
) => void | Promise<void>;
291
292
interface JestEnvironment {
293
global: typeof globalThis;
294
getVmContext(): vm.Context | null;
295
setup(): Promise<void>;
296
teardown(): Promise<void>;
297
}
298
299
interface Callsite {
300
column: number;
301
line: number;
302
}
303
```