Implementation:DevExpress Testcafe TestCafe CreateRunner
| Knowledge Sources | |
|---|---|
| Domains | Testing, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Concrete method for creating test runner instances from a TestCafe instance, establishing the bridge between framework configuration and test execution provided by TestCafe.
Description
The createRunner method on the TestCafe class instantiates a Runner object that coordinates test execution. It delegates to the internal _createRunner method, passing false to indicate standard (non-live) mode. The Runner constructor receives shared resources from the parent TestCafe instance (proxy, browser connection gateway) and a cloned configuration to prevent cross-runner mutation.
The method also provides createLiveModeRunner for watch mode, which creates a LiveModeRunner with file watching capabilities. Live mode runners are singleton - attempting to create multiple live mode runners throws an error.
Usage
Call createRunner on a TestCafe instance after initialization and before configuring test sources and browsers. The returned Runner provides a fluent API for configuration and a run method for execution. Multiple runners can be created from a single TestCafe instance for parallel test sessions with different configurations.
Code Reference
Source Location
- Repository: testcafe
- File: src/testcafe.js
- Lines: 102-104 (createRunner), 66-77 (_createRunner), 106-111 (createLiveModeRunner)
Signature
createRunner(): Runner
createLiveModeRunner(): LiveModeRunner
// Internal method (not part of public API)
_createRunner(isLiveMode: boolean): Runner | LiveModeRunner
Import
// createRunner is a method on TestCafe instances
const createTestCafe = require('testcafe');
const testcafe = await createTestCafe();
const runner = testcafe.createRunner();
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| None | - | - | createRunner takes no parameters |
Outputs
| Name | Type | Description |
|---|---|---|
| runner | Runner | Runner instance configured with proxy, browser gateway, and cloned configuration |
| liveModeRunner | LiveModeRunner | LiveModeRunner instance with file watching capabilities (createLiveModeRunner only) |
Usage Examples
Basic Runner Creation
const createTestCafe = require('testcafe');
(async () => {
const testcafe = await createTestCafe();
try {
const runner = testcafe.createRunner();
await runner
.src('tests/**/*.js')
.browsers('chrome')
.reporter('spec')
.run();
}
finally {
await testcafe.close();
}
})();
Multiple Runners for Parallel Test Suites
const createTestCafe = require('testcafe');
(async () => {
const testcafe = await createTestCafe();
try {
// Runner 1: Chrome tests
const runner1 = testcafe.createRunner();
const promise1 = runner1
.src('tests/chrome-specific/**/*.js')
.browsers('chrome')
.reporter('spec')
.run();
// Runner 2: Firefox tests
const runner2 = testcafe.createRunner();
const promise2 = runner2
.src('tests/firefox-specific/**/*.js')
.browsers('firefox')
.reporter('json', 'firefox-report.json')
.run();
// Wait for both to complete
const [chromeFailures, firefoxFailures] = await Promise.all([promise1, promise2]);
console.log('Chrome failures:', chromeFailures);
console.log('Firefox failures:', firefoxFailures);
}
finally {
await testcafe.close();
}
})();
Live Mode Runner for Development
const createTestCafe = require('testcafe');
(async () => {
const testcafe = await createTestCafe();
try {
const liveRunner = testcafe.createLiveModeRunner();
// Live mode watches files and re-runs tests on changes
await liveRunner
.src('tests/**/*.js')
.browsers('chrome')
.run();
}
finally {
await testcafe.close();
}
})();
Runner Configuration Independence
const createTestCafe = require('testcafe');
(async () => {
const testcafe = await createTestCafe();
try {
const runner1 = testcafe.createRunner();
const runner2 = testcafe.createRunner();
// Runners have independent configurations
runner1.src('tests/smoke/**/*.js').browsers('chrome:headless');
runner2.src('tests/integration/**/*.js').browsers('firefox:headless');
// Configurations don't affect each other
const results = await Promise.all([
runner1.run(),
runner2.run()
]);
console.log('Total failures:', results[0] + results[1]);
}
finally {
await testcafe.close();
}
})();
Implementation Details
Internal Flow
- _createRunner(isLiveMode) determines Runner class based on mode (Runner or LiveModeRunner)
- Creates new runner instance with shared resources:
- proxy: Shared hammerhead proxy from TestCafe instance
- browserConnectionGateway: Shared gateway for browser connections
- configuration: Cloned configuration (via configuration.clone()) to prevent mutation
- Runner constructor (src/runner/index.js:53-74):
- Creates MessageBus for event communication
- Creates Bootstrapper for test compilation and browser management
- Initializes internal state (_options, warningLog, pendingTaskPromises)
- Creates FlagList to track API method calls (prevents double-calling src/browsers/reporter)
- Registers runner in testcafe.runners array for lifecycle management
- Returns runner instance
Live Mode Constraints
The createLiveModeRunner method enforces singleton behavior:
createLiveModeRunner() {
if (this.runners.some(runner => runner instanceof LiveModeRunner))
throw new GeneralError(RUNTIME_ERRORS.cannotCreateMultipleLiveModeRunners);
return this._createRunner(true);
}
Only one live mode runner can exist per TestCafe instance because file watching creates global state that would conflict between multiple live runners.
Configuration Cloning
The configuration is cloned to ensure runner independence:
configuration: this.configuration.clone(OPTION_NAMES.hooks)
This allows multiple runners to modify their configurations without affecting each other or the parent TestCafe instance.