A plugin to use the jest test runner and framework in Stryker, the JavaScript mutation testing framework
—
Configuration loading and validation for different Jest project types including custom projects and Create React App setups. Handles Jest config merging and validation.
Core configuration interface for customizing Jest runner behavior within Stryker.
/**
* Jest-specific configuration options for Stryker Jest runner
*/
export interface JestOptions {
/** Type of Jest project setup */
projectType: JestProjectType;
/** Path to Jest configuration file (optional) */
configFile?: string;
/** Custom Jest configuration object (optional) */
config?: { [k: string]: unknown };
/** Enable Jest's --findRelatedTests flag for optimized test execution */
enableFindRelatedTests: boolean;
}
/**
* Supported Jest project types
*/
export type JestProjectType = 'create-react-app' | 'custom';Usage Examples:
// stryker.conf.js - Custom project configuration
module.exports = {
testRunner: "jest",
jest: {
projectType: "custom",
configFile: "./jest.config.js",
enableFindRelatedTests: true,
config: {
testEnvironment: "node",
collectCoverageFrom: ["src/**/*.{js,ts}"],
coverageReporters: ["text", "lcov"]
}
}
};// stryker.conf.js - Create React App project
module.exports = {
testRunner: "jest",
jest: {
projectType: "create-react-app",
enableFindRelatedTests: false
}
};Root configuration interface that combines Jest options with Stryker options.
/**
* Root Jest runner options interface
*/
export interface JestRunnerOptions {
jest: JestOptions;
[k: string]: unknown;
}
/**
* Combined interface extending Stryker core options with Jest options
*/
export interface JestRunnerOptionsWithStrykerOptions extends StrykerOptions, JestRunnerOptions {}Usage Example:
import { JestRunnerOptionsWithStrykerOptions } from "@stryker-mutator/jest-runner";
// Used internally by Stryker to type check complete configuration
const config: JestRunnerOptionsWithStrykerOptions = {
// Stryker core options
mutate: ['src/**/*.js'],
testRunner: 'jest',
coverageAnalysis: 'perTest',
// Jest-specific options
jest: {
projectType: 'custom',
enableFindRelatedTests: true,
config: {
testMatch: ['**/__tests__/**/*.test.js']
}
}
};Abstract interface and implementations for loading Jest configuration from different sources.
/**
* Base interface for Jest configuration loaders
*/
export interface JestConfigLoader {
loadConfig(): Promise<Config.InitialOptions>;
}
/**
* Configuration loader for custom Jest projects
* Loads configuration from Jest config files, package.json, or defaults
*/
export class CustomJestConfigLoader implements JestConfigLoader {
loadConfig(): Promise<Config.InitialOptions>;
}
/**
* Configuration loader for Create React App projects
* Uses react-scripts Jest configuration with CRA-specific optimizations
*/
export class ReactScriptsJestConfigLoader implements JestConfigLoader {
loadConfig(): Promise<Config.InitialOptions>;
}
/**
* Factory function to create appropriate config loader based on project type
* @param options - Stryker options containing Jest configuration
* @param injector - Dependency injector for creating loader instances
* @param log - Logger for configuration warnings and debug information
* @returns Configured Jest config loader instance
*/
export function configLoaderFactory(
options: StrykerOptions,
injector: Injector<JestPluginContext>,
log: Logger
): CustomJestConfigLoader | ReactScriptsJestConfigLoader;Usage Examples:
import { configLoaderFactory, CustomJestConfigLoader } from "@stryker-mutator/jest-runner";
// Typically used internally by Stryker through dependency injection
const loader = configLoaderFactory(options, injector, logger);
const jestConfig = await loader.loadConfig();
// Direct usage for custom scenarios
const customLoader = new CustomJestConfigLoader(/* dependencies */);
const config = await customLoader.loadConfig();Default configuration overrides applied by Stryker for optimal mutation testing performance.
/**
* Default Jest configuration overrides for Stryker integration
* Applied to all Jest configurations to optimize for mutation testing
*/
export const JEST_OVERRIDE_OPTIONS: Readonly<Config.InitialOptions>;The override options disable Jest features that interfere with mutation testing:
const JEST_OVERRIDE_OPTIONS = {
// Prevent conflicts with Stryker's result processing
testResultsProcessor: undefined,
// Disable Jest's built-in coverage collection (Stryker handles this)
collectCoverage: false,
// Reduce verbose output during mutation testing
verbose: false,
// Disable desktop notifications during testing
notify: false,
// Ensure all tests run (bail not supported programmatically)
bail: false,
// Disable default reporters for cleaner output
reporters: [],
};Usage Example:
import { JEST_OVERRIDE_OPTIONS } from "@stryker-mutator/jest-runner";
// These overrides are automatically applied by the Jest runner
// but can be inspected for debugging or custom integrations
console.log('Stryker Jest overrides:', JEST_OVERRIDE_OPTIONS);
// Example of manual config merging (typically done internally)
const finalConfig = {
...userJestConfig,
...customOptions,
...JEST_OVERRIDE_OPTIONS // Applied last to ensure overrides take effect
};// From Jest types
namespace Config {
interface InitialOptions {
testEnvironment?: string;
testRunner?: string;
setupFiles?: string[];
setupFilesAfterEnv?: string[];
testMatch?: string[];
testPathIgnorePatterns?: string[];
collectCoverageFrom?: string[];
coverageDirectory?: string;
roots?: string[];
globals?: { [key: string]: any };
// ... many more Jest configuration options
}
interface GlobalConfig extends InitialOptions {
// Resolved global configuration
}
interface ProjectConfig extends InitialOptions {
// Resolved project-specific configuration
}
}interface StrykerOptions {
mutate: string[];
testRunner: string;
coverageAnalysis: CoverageAnalysis;
files: string[];
// ... other Stryker core options
}
type CoverageAnalysis = 'off' | 'all' | 'perTest';interface JestPluginContext extends PluginContext {
[pluginTokens.jestWrapper]: JestWrapper;
[pluginTokens.resolve]: RequireResolve;
[pluginTokens.requireFromCwd]: typeof requireResolve;
[pluginTokens.processEnv]: typeof process.env;
[pluginTokens.jestConfigWrapper]: JestConfigWrapper;
}
const pluginTokens = {
requireFromCwd: 'requireFromCwd',
resolve: 'resolve',
resolveFromDirectory: 'resolveFromDirectory',
configLoader: 'configLoader',
processEnv: 'processEnv',
jestTestAdapter: 'jestTestAdapter',
globalNamespace: 'globalNamespace',
jestWrapper: 'jestWrapper',
jestConfigWrapper: 'jestConfigWrapper',
} as const;The Jest runner applies a layered configuration approach:
Loaded from Jest configuration sources in priority order:
configFile pathjest.config.js / jest.config.tspackage.json jest propertyApplied from Stryker jest.config option:
jest: {
config: {
// User overrides applied here
testEnvironment: "jsdom",
setupFilesAfterEnv: ["./test-setup.js"]
}
}Internal optimizations for mutation testing:
const JEST_OVERRIDE_OPTIONS = {
testResultsProcessor: undefined, // Prevent conflicts
collectCoverage: false, // Handled by Stryker
verbose: false, // Reduce noise
notify: false, // Disable notifications
bail: false, // Run all tests
reporters: [], // Disable default reporters
};Applied during test execution:
projectType: "custom")configFile option for custom pathsjest: {
projectType: "custom",
configFile: "./config/jest.config.js",
config: {
preset: "ts-jest",
testEnvironment: "node"
}
}projectType: "create-react-app")configFile option ignored with warningjest: {
projectType: "create-react-app",
enableFindRelatedTests: false // Often disabled for CRA
}enableFindRelatedTests)When enabled, Jest runs only tests related to mutated files:
Install with Tessl CLI
npx tessl i tessl/npm-stryker-mutator--jest-runner