Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:DevExpress Testcafe TestRunController

From Leeroopedia
Knowledge Sources
Domains Test Execution, Lifecycle Management
Last Updated 2026-02-12 12:00 GMT

Overview

TestRunController manages the full lifecycle of a single test's execution, including creation, quarantine retry logic, fixture hooks, disconnection handling, and native automation mode.

Description

TestRunController extends AsyncEventEmitter and acts as a wrapper around an individual TestRun instance. It is responsible for:

  • Creating the TestRun (or LegacyTestRun) with the appropriate constructor
  • Running fixture before/after hooks and test-run-level hooks
  • Managing quarantine mode: tracking attempts, deciding whether to restart or finalize
  • Handling browser disconnections with a threshold-based retry mechanism (DISCONNECT_THRESHOLD = 3)
  • Blocking test execution while fixture hooks are in progress
  • Registering and unregistering custom client script routes via the proxy
  • Determining native automation mode support per browser connection

Usage

TestRunController is instantiated by BrowserJob._createTestRunController for each test in the queue. The BrowserJob calls start(connection, startRunExecutionTime) to kick off execution and listens for lifecycle events. This class is not used directly by test authors.

Code Reference

Source Location

Signature

const DISCONNECT_THRESHOLD = 3;

export default class TestRunController extends AsyncEventEmitter {
    private readonly _quarantine: null | Quarantine;
    private _disconnectionCount: number;
    private readonly _proxy: Proxy;
    public readonly index: number;
    public test: Test;
    private readonly _opts: Dictionary<OptionValue>;
    private _screenshots: Screenshots;
    private readonly _warningLog: WarningLog;
    private readonly _fixtureHookController: FixtureHookController;
    private readonly _testRunCtor: LegacyTestRun['constructor'] | TestRun['constructor'];
    public testRun: null | LegacyTestRun | TestRun;
    public done: boolean;
    private readonly _messageBus: MessageBus;
    private readonly _testRunHook: TestRunHookController;
    private clientScriptRoutes: string[];
    private isNativeAutomation: boolean;
    public readonly id: string;

    public constructor({
        test,
        index,
        proxy,
        screenshots,
        warningLog,
        fixtureHookController,
        opts,
        testRunHook,
        messageBus,
    }: TestRunControllerInit);

    public get blocked(): boolean;
    public async start(connection: BrowserConnection, startRunExecutionTime?: Date): Promise<string | null>;
}

Import

import TestRunController from '../runner/test-run-controller';

I/O Contract

Inputs

Name Type Required Description
test Test Yes The test definition to execute
index number Yes 1-based index of this test in the queue (used for reporting)
proxy Proxy Yes Hammerhead proxy for URL rewriting and client script routing
screenshots Screenshots Yes Screenshot manager for creating a capturer bound to this test run
warningLog WarningLog Yes Warning log for non-fatal issues
fixtureHookController FixtureHookController Yes Manages fixture before/after hooks and test blocking
opts Dictionary<OptionValue> Yes Runner options including quarantineMode, disableNativeAutomation, TestRunCtor, etc.
testRunHook TestRunHookController Yes Manages test-run-level before/after hooks
messageBus MessageBus Yes Central event bus for cross-component communication

Outputs

Name Type Description
start return null> The session URL to navigate the browser to, or null if the test is skipped or a hook failed
blocked boolean Whether this controller's test is currently blocked by a fixture hook
done boolean Whether this test run has fully completed
testRun LegacyTestRun | null The underlying test run instance (set after start is called)
id string Unique identifier for this controller instance

Events Emitted

Event Payload Description
test-run-create { testRun, legacy, test, index, quarantine } Fired when a new TestRun instance is created
test-run-ready none Fired when the test run is ready for execution (first quarantine attempt only)
test-run-before-done none Fired before the test run completes (for sequencing reporters)
test-run-done none Fired when the test run is fully done (after hooks and client script cleanup)
test-run-restart none Fired when the test needs to restart (quarantine retry or disconnection)
test-action-done ActionEventArg Fired after each test action completes

Usage Examples

// Internal usage within BrowserJob._createTestRunController
const testRunController = new TestRunController({
    test,
    index:                 index + 1,
    proxy:                 this._proxy,
    screenshots:           this._screenshots,
    warningLog:            this.warningLog,
    fixtureHookController: this.fixtureHookController,
    opts:                  this._opts,
    messageBus:            this._messageBus,
    testRunHook:           this._testRunHook,
});

// Listen for lifecycle events
testRunController.on('test-run-create', async (testRunInfo) => {
    await this.emit('test-run-create', testRunInfo);
});

testRunController.on('test-run-done', async () => {
    await this._onTestRunDone(testRunController);
});

testRunController.on('test-run-restart', async () => {
    await this._onTestRunRestart(testRunController);
});

// Start the test on a connection
const testRunUrl = await testRunController.start(connection, startTime);
if (testRunUrl) {
    // Browser navigates to testRunUrl to begin the test
}

Internal Mechanics

Quarantine Mode

When opts.quarantineMode is enabled, the controller creates a Quarantine instance that tracks attempts and errors. After each test run completes:

  1. The result is pushed to quarantine.attempts
  2. If the threshold is not reached, the test restarts via _keepInQuarantine
  3. Once the threshold is reached (configurable attemptLimit and successThreshold), the test is finalized
  4. If multiple attempts occurred, the test is marked as unstable if any attempt passed

Disconnection Handling

Each disconnection increments _disconnectionCount. If the count reaches DISCONNECT_THRESHOLD (3), the connection's processDisconnection is called with true to indicate threshold exceeded. Otherwise, the test is restarted.

Native Automation

Before creating a test run, _handleNativeAutomationMode checks whether the browser supports native automation (e.g., CDP). If disableNativeAutomation is not set but the browser does not support it, a GeneralError is thrown.

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment