A plugin to use the jest test runner and framework in Stryker, the JavaScript mutation testing framework
—
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.
The primary test runner implementation that manages Jest test execution for mutation testing.
/**
* Main Jest test runner implementation for Stryker
* Manages Jest configuration, test execution, and result processing
*/
export class JestTestRunner implements TestRunner {
/**
* Initialize the test runner with Jest configuration
* Loads and merges Jest config from various sources
*/
init(): Promise<void>;
/**
* Get test runner capabilities
* @returns Capabilities indicating reloadEnvironment support
*/
capabilities(): TestRunnerCapabilities;
/**
* Execute dry run for initial test execution and coverage analysis
* @param options - Options including coverage analysis mode and files to test
* @returns Results of test execution with optional coverage data
*/
dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
/**
* Execute tests with an active mutant for mutation testing
* @param options - Options including active mutant, test filters, and limits
* @returns Results of mutant testing execution
*/
mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
}Usage Example:
import { JestTestRunner } from "@stryker-mutator/jest-runner";
// Note: Typically instantiated through Stryker's dependency injection
// Test runner is created and managed by Stryker internally
// Configuration is passed through Stryker options
const runner = new JestTestRunner(logger, options, adapter, configLoader, jestWrapper, namespace);
// Initialize with Jest configuration
await runner.init();
// Check capabilities
const caps = runner.capabilities(); // { reloadEnvironment: true }
// Execute dry run for coverage analysis
const dryResult = await runner.dryRun({
coverageAnalysis: 'perTest',
files: ['src/example.js']
});
// Execute mutant run
const mutantResult = await runner.mutantRun({
activeMutant: { id: '1', replacement: '>' },
sandboxFileName: 'src/example.js',
testFilter: ['should pass basic test'],
disableBail: false,
hitLimit: 10
});Factory functions for creating Jest test runner instances with dependency injection.
/**
* Create a Jest test runner factory with optional custom namespace
* @param namespace - Global namespace for instrumenter (defaults to Stryker namespace)
* @returns Factory function with dependency injection configuration
*/
export function createJestTestRunnerFactory(
namespace?: typeof INSTRUMENTER_CONSTANTS.NAMESPACE | '__stryker2__'
): {
(injector: Injector<PluginContext>): JestTestRunner;
inject: ['$injector'];
};
/**
* Default Jest test runner factory instance
* Pre-configured with standard Stryker namespace
*/
export const jestTestRunnerFactory: ReturnType<typeof createJestTestRunnerFactory>;Usage Example:
import { createJestTestRunnerFactory, jestTestRunnerFactory } from "@stryker-mutator/jest-runner";
// Create custom factory with different namespace
const customFactory = createJestTestRunnerFactory('__customStryker__');
// Use default factory (typical usage)
const defaultFactory = jestTestRunnerFactory;
// Factories are used by Stryker's dependency injection system
// to create test runner instances with proper dependenciesAdapter pattern implementation that abstracts differences between Jest versions.
/**
* Factory function that creates version-appropriate Jest test adapter
* Automatically selects adapter based on detected Jest version
* @returns Jest test adapter instance compatible with current Jest version
*/
export function jestTestAdapterFactory(): JestTestAdapter;
/**
* Abstract interface for Jest test execution adapters
* Provides version-agnostic interface for running Jest tests
*/
export interface JestTestAdapter {
run(settings: RunSettings): Promise<JestRunResult>;
}
/**
* Jest test adapter for versions prior to 25.x
* Handles legacy Jest API and configuration patterns
*/
export class JestLessThan25TestAdapter implements JestTestAdapter {
run(settings: RunSettings): Promise<JestRunResult>;
}
/**
* Jest test adapter for versions 25.x and later
* Uses modern Jest API with improved performance and features
*/
export class JestGreaterThan25TestAdapter implements JestTestAdapter {
run(settings: RunSettings): Promise<JestRunResult>;
}Usage Example:
import { jestTestAdapterFactory } from "@stryker-mutator/jest-runner";
// Factory automatically selects appropriate adapter
const adapter = jestTestAdapterFactory();
// Execute tests with version-appropriate adapter
const result = await adapter.run({
jestConfig: myJestConfig,
fileNamesUnderTest: ['src/example.js'],
testLocationInResults: true
});interface TestRunner {
init(): Promise<void>;
capabilities(): TestRunnerCapabilities;
dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
}
interface TestRunnerCapabilities {
reloadEnvironment: boolean;
}interface DryRunOptions {
coverageAnalysis: CoverageAnalysis;
files: string[];
}
interface MutantRunOptions {
activeMutant: Mutant;
sandboxFileName: string;
testFilter?: string[];
disableBail: boolean;
hitLimit?: number;
}
interface DryRunResult {
status: DryRunStatus;
tests?: TestResult[];
errorMessage?: string;
mutantCoverage?: MutantCoverage;
}
interface MutantRunResult {
status: MutantRunStatus;
tests?: TestResult[];
errorMessage?: string;
killedBy?: string[];
survivalReason?: string;
}
type CoverageAnalysis = 'off' | 'all' | 'perTest';
enum DryRunStatus {
Complete = 'Complete',
Error = 'Error',
Timeout = 'Timeout'
}
enum MutantRunStatus {
Killed = 'Killed',
Survived = 'Survived',
Error = 'Error',
Timeout = 'Timeout'
}interface Mutant {
id: string;
replacement: string;
fileName: string;
location: Location;
}
interface TestResult {
id: string;
name: string;
status: TestStatus;
timeSpentMs: number;
fileName?: string;
startPosition?: Position;
failureMessage?: string;
}
enum TestStatus {
Success = 'Success',
Failed = 'Failed',
Skipped = 'Skipped'
}
interface Position {
line: number;
column: number;
}The test runner merges Jest configuration from multiple sources:
off: No coverage analysis, fastest executionall: Global coverage analysis for all testsperTest: Individual test coverage tracking (recommended)Prevents infinite loops during mutation testing by limiting the number of times instrumented code can be executed:
The test runner manages several environment variables:
BABEL_ENV: Set to 'test' for proper Babel transformationNODE_ENV: Set to 'test' for consistent environmentFORCE_COLOR: Set to '0' to disable colored output--findRelatedTests to run only relevant testsInstall with Tessl CLI
npx tessl i tessl/npm-stryker-mutator--jest-runner