CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stryker-mutator--jest-runner

A plugin to use the jest test runner and framework in Stryker, the JavaScript mutation testing framework

Pending
Overview
Eval results
Files

test-runner.mddocs/

Test Runner

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.

Capabilities

Jest Test Runner Class

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
});

Test Runner Factory

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 dependencies

Jest Test Adapters

Adapter 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
});

Types

Test Runner Interface

interface TestRunner {
  init(): Promise<void>;
  capabilities(): TestRunnerCapabilities;
  dryRun(options: Pick<DryRunOptions, 'coverageAnalysis' | 'files'>): Promise<DryRunResult>;
  mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
}

interface TestRunnerCapabilities {
  reloadEnvironment: boolean;
}

Options and Results

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'
}

Mutant and Test Types

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;
}

Implementation Details

Configuration Merging

The test runner merges Jest configuration from multiple sources:

  1. File-based config: Loaded from Jest config files or package.json
  2. User config: Custom configuration from Stryker jest options
  3. Override config: Internal Stryker optimizations and requirements

Coverage Analysis Modes

  • off: No coverage analysis, fastest execution
  • all: Global coverage analysis for all tests
  • perTest: Individual test coverage tracking (recommended)

Hit Limiting

Prevents infinite loops during mutation testing by limiting the number of times instrumented code can be executed:

  • Configurable hit limit per mutant run
  • Automatic timeout when limit is exceeded
  • Helps identify problematic mutations

Environment Variables

The test runner manages several environment variables:

  • BABEL_ENV: Set to 'test' for proper Babel transformation
  • NODE_ENV: Set to 'test' for consistent environment
  • FORCE_COLOR: Set to '0' to disable colored output
  • Active mutant variable: Set during mutant runs for instrumenter

Performance Optimizations

  • Related tests: Uses --findRelatedTests to run only relevant tests
  • Disabled features: Turns off Jest features that slow down mutation testing
  • Lazy execution: Defers expensive operations until needed
  • Result caching: Optimizes repeated test executions

Install with Tessl CLI

npx tessl i tessl/npm-stryker-mutator--jest-runner

docs

configuration.md

environment-integration.md

index.md

plugin-integration.md

test-runner.md

utilities.md

tile.json