CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-runner

Jest's test runner responsible for orchestrating test execution, managing worker processes, and coordinating parallel test runs

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

custom-runner.mddocs/

Custom Test Runner Framework

Abstract base classes and interfaces for building custom test runners with both callback and event-driven patterns. This framework enables extending Jest's test execution capabilities with custom test runners for different testing scenarios.

Imports

import { 
  CallbackTestRunner,
  EmittingTestRunner,
  type CallbackTestRunnerInterface,
  type EmittingTestRunnerInterface,
  type OnTestStart,
  type OnTestFailure,
  type OnTestSuccess,
  type UnsubscribeFn
} from "jest-runner";

Capabilities

CallbackTestRunner Abstract Class

Base class for building custom test runners using callback-style interfaces for test lifecycle events.

/**
 * Abstract base class for callback-style test runners
 * Suitable for runners that prefer explicit callback handling over events
 */
abstract class CallbackTestRunner extends BaseTestRunner implements CallbackTestRunnerInterface {
  readonly supportsEventEmitters = false;
  readonly isSerial?: boolean;
  
  constructor(globalConfig: Config.GlobalConfig, context: TestRunnerContext);
  
  /**
   * Execute tests using callback-style event handling
   * @param tests - Array of test objects to execute
   * @param watcher - Test watcher for interrupt handling
   * @param onStart - Callback invoked when each test starts
   * @param onResult - Callback invoked when each test succeeds
   * @param onFailure - Callback invoked when each test fails
   * @param options - Execution options including serial mode
   */
  abstract runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    onStart: OnTestStart,
    onResult: OnTestSuccess,
    onFailure: OnTestFailure,
    options: TestRunnerOptions
  ): Promise<void>;
}

Usage Example:

import { CallbackTestRunner } from "jest-runner";
import type { Test, TestResult, SerializableError } from "@jest/test-result";

class CustomCallbackRunner extends CallbackTestRunner {
  async runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    onStart: OnTestStart,
    onResult: OnTestSuccess,
    onFailure: OnTestFailure,
    options: TestRunnerOptions
  ): Promise<void> {
    for (const test of tests) {
      if (watcher.isInterrupted()) break;
      
      try {
        await onStart(test);
        
        // Custom test execution logic
        const result = await this.executeCustomTest(test);
        
        await onResult(test, result);
      } catch (error) {
        await onFailure(test, this.formatError(error));
      }
    }
  }
  
  private async executeCustomTest(test: Test): Promise<TestResult> {
    // Custom test execution implementation
    return {
      numPassingTests: 1,
      numFailingTests: 0,
      numPendingTests: 0,
      numTodoTests: 0,
      testFilePath: test.path,
      // ... other TestResult properties
    };
  }
}

EmittingTestRunner Abstract Class

Base class for building custom test runners using event-driven interfaces for real-time test progress reporting.

/**
 * Abstract base class for event-emitting test runners
 * Suitable for runners that need real-time event broadcasting
 */
abstract class EmittingTestRunner extends BaseTestRunner implements EmittingTestRunnerInterface {
  readonly supportsEventEmitters = true;
  readonly isSerial?: boolean;
  
  constructor(globalConfig: Config.GlobalConfig, context: TestRunnerContext);
  
  /**
   * Execute tests using event-driven progress reporting
   * @param tests - Array of test objects to execute
   * @param watcher - Test watcher for interrupt handling
   * @param options - Execution options including serial mode
   */
  abstract runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    options: TestRunnerOptions
  ): Promise<void>;
  
  /**
   * Register event listener for test execution events
   * @param eventName - Name of the event to listen for
   * @param listener - Function to call when event is emitted
   * @returns Unsubscribe function to remove the listener
   */
  abstract on<Name extends keyof TestEvents>(
    eventName: Name,
    listener: (eventData: TestEvents[Name]) => void | Promise<void>
  ): UnsubscribeFn;
}

Usage Example:

import { EmittingTestRunner } from "jest-runner";
import Emittery from "emittery";

class CustomEmittingRunner extends EmittingTestRunner {
  private eventEmitter = new Emittery<TestEvents>();
  
  async runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    options: TestRunnerOptions
  ): Promise<void> {
    for (const test of tests) {
      if (watcher.isInterrupted()) break;
      
      try {
        await this.eventEmitter.emit('test-file-start', [test]);
        
        // Custom test execution logic
        const result = await this.executeCustomTest(test);
        
        await this.eventEmitter.emit('test-file-success', [test, result]);
      } catch (error) {
        await this.eventEmitter.emit('test-file-failure', [test, error]);
      }
    }
  }
  
  on<Name extends keyof TestEvents>(
    eventName: Name,
    listener: (eventData: TestEvents[Name]) => void | Promise<void>
  ): UnsubscribeFn {
    return this.eventEmitter.on(eventName, listener);
  }
}

Test Runner Interfaces

Type definitions for implementing custom test runners without extending the abstract base classes.

/**
 * Interface for callback-style test runners
 */
interface CallbackTestRunnerInterface {
  readonly isSerial?: boolean;
  readonly supportsEventEmitters?: boolean;
  
  runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    onStart: OnTestStart,
    onResult: OnTestSuccess,
    onFailure: OnTestFailure,
    options: TestRunnerOptions
  ): Promise<void>;
}

/**
 * Interface for event-emitting test runners
 */
interface EmittingTestRunnerInterface {
  readonly isSerial?: boolean;
  readonly supportsEventEmitters: true;
  
  runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    options: TestRunnerOptions
  ): Promise<void>;
  
  on<Name extends keyof TestEvents>(
    eventName: Name,
    listener: (eventData: TestEvents[Name]) => void | Promise<void>
  ): UnsubscribeFn;
}

Runner Implementation Examples

Complete examples showing how to implement both callback and event-driven test runners.

Callback Runner Implementation:

class ESLintTestRunner extends CallbackTestRunner {
  async runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    onStart: OnTestStart,
    onResult: OnTestSuccess,
    onFailure: OnTestFailure,
    options: TestRunnerOptions
  ): Promise<void> {
    // Access inherited properties
    const { collectCoverage } = this._globalConfig;
    const { changedFiles } = this._context;
    
    for (const test of tests) {
      if (watcher.isInterrupted()) break;
      
      await onStart(test);
      
      try {
        // Run ESLint on the test file
        const results = await this.runESLint(test.path);
        
        const testResult: TestResult = {
          numFailingTests: results.errorCount,
          numPassingTests: results.errorCount === 0 ? 1 : 0,
          numPendingTests: 0,
          numTodoTests: 0,
          testFilePath: test.path,
          console: [],
          leaks: false,
          // Map ESLint messages to test output
          testResults: results.messages.map(msg => ({
            title: `ESLint: ${msg.ruleId || 'Error'}`,
            status: msg.severity === 2 ? 'failed' : 'passed',
            ancestorTitles: [],
            fullName: `${test.path}:${msg.line}:${msg.column}`,
          })),
        };
        
        await onResult(test, testResult);
      } catch (error) {
        await onFailure(test, {
          message: error.message,
          stack: error.stack,
          type: error.constructor.name,
        });
      }
    }
  }
}

Event-Driven Runner Implementation:

class PuppeteerTestRunner extends EmittingTestRunner {
  private eventEmitter = new Emittery<TestEvents>();
  
  async runTests(
    tests: Array<Test>,
    watcher: TestWatcher,
    options: TestRunnerOptions
  ): Promise<void> {
    const browser = await puppeteer.launch();
    
    try {
      for (const test of tests) {
        if (watcher.isInterrupted()) break;
        
        await this.eventEmitter.emit('test-file-start', [test]);
        
        try {
          const page = await browser.newPage();
          const result = await this.runBrowserTest(test, page);
          await page.close();
          
          await this.eventEmitter.emit('test-file-success', [test, result]);
        } catch (error) {
          await this.eventEmitter.emit('test-file-failure', [test, error]);
        }
      }
    } finally {
      await browser.close();
    }
  }
  
  on<Name extends keyof TestEvents>(
    eventName: Name,
    listener: (eventData: TestEvents[Name]) => void | Promise<void>
  ): UnsubscribeFn {
    return this.eventEmitter.on(eventName, listener);
  }
}

Types

type OnTestStart = (test: Test) => Promise<void>;
type OnTestFailure = (test: Test, serializableError: SerializableError) => Promise<void>;
type OnTestSuccess = (test: Test, testResult: TestResult) => Promise<void>;
type UnsubscribeFn = () => void;
type JestTestRunner = CallbackTestRunner | EmittingTestRunner;

abstract class BaseTestRunner {
  readonly isSerial?: boolean;
  abstract readonly supportsEventEmitters: boolean;
  
  protected readonly _globalConfig: Config.GlobalConfig;
  protected readonly _context: TestRunnerContext;
  
  constructor(globalConfig: Config.GlobalConfig, context: TestRunnerContext);
}

docs

core-execution.md

custom-runner.md

index.md

test-runner.md

worker-management.md

tile.json