Implementation:DevExpress Testcafe LiveModeRunner
| Knowledge Sources | |
|---|---|
| Domains | Testing, Live Mode, File Watching |
| Principle | Live mode test execution |
| Last Updated | 2026-02-12 12:00 GMT |
Overview
LiveModeRunner and LiveModeController together implement TestCafe's live mode, which watches test files for changes and automatically re-runs tests without restarting the browser or the test process.
Description
Live mode is split across two primary files:
LiveModeRunner (src/live/test-runner.js, 216 lines)
LiveModeRunner extends the standard Runner class and adds live-mode-specific lifecycle management. Key behaviors:
- Initialization: The constructor creates a
LiveModeTestRunController(which manages individual test run lifecycles) and aLiveModeController(which handles file watching and keyboard input). It setsembeddingOptionswith a customTestRunCtorfrom the test run controller.
run(options): The entry point for live mode. It sets up configuration, parses the file list, initializes the controller (which starts file watching and keyboard listening), creates the runnable configuration, and runs the first test cycle. It returns a promise that resolves only when the user explicitly exits (via_waitUntilExit, a promise controlled bystopInfiniteWaiting/rejectInfiniteWaiting).
runTests(isFirstRun): Executes a test cycle. On subsequent runs (not the first), it re-fetches tests from the bootstrapper to pick up file changes. It finishes any previous test runs, validates configuration, sets the expected test count, resets state, restores message bus listeners, and runs the task.
suspend(): Stops the current test run gracefully by cancelling the runner task and waiting for in-progress tests to complete.
_createRunnableConfiguration(): Overrides the parent to cache the configuration, avoiding re-bootstrapping on every re-run.
- Resource management:
_disposeAssetsis overridden to defer actual disposal -- assets (browser set, reporters, tested app) are stored and only disposed during final_disposewhen the runner exits.
LiveModeController (src/live/controller.ts, 151 lines)
LiveModeController extends EventEmitter and orchestrates the user-facing live mode experience:
init(files): Registers a keyboard observer for interactive commands, starts file watching on all test files, and displays the intro message.
runTests(sourceChanged?): Triggers a test re-run via the runner, unless watching is paused or tests are already running.
onTestRunDone(err): Called after each test cycle completes. Logs results and handles the special case of test-files-not-found errors.
toggleWatching(): Pauses or resumes file watching (toggled by keyboard shortcut).
stop(): Suspends the current run via the runner.
restart(): Stops (if running) and re-runs tests.
exit(): Terminates the live mode session.
addFileToWatches(filename): Adds a file to the watcher dynamically.
dispose(): Stops file watching and removes the keyboard observer.
Usage
Live mode is activated by running TestCafe with the --live (or -L) CLI flag, or by calling the programmatic API with the live option. The runner stays active indefinitely, re-running tests when source files change or when the user presses a keyboard shortcut. It is the primary development-time workflow for TestCafe users.
Code Reference
Source Location
- Repository: DevExpress_Testcafe
- File (Runner): src/live/test-runner.js
- Lines: 1-216
- File (Controller): src/live/controller.ts
- Lines: 1-151
Signature
LiveModeRunner:
class LiveModeRunner extends Runner {
constructor ({ proxy, browserConnectionGateway, configuration }) { ... }
runTests (isFirstRun = false) { ... }
run (options) { ... }
suspend () { ... }
stop () { ... }
exit () { ... }
setBootstrappingError (err) { ... }
_validateRunOptions () { ... }
_createRunnableConfiguration () { ... }
_finishPreviousTestRuns () { ... }
_validateRunnableConfiguration (isFirstRun) { ... }
_createTask (tests, browserConnectionGroups, proxy, opts) { ... }
_createBootstrapper (browserConnectionGateway, messageBus) { ... }
_createController () { ... }
_waitUntilExit () { ... }
_disposeAssets (browserSet, reporters, testedApp) { ... }
_dispose () { ... }
}
LiveModeController:
class LiveModeController extends EventEmitter {
private running: boolean;
private restarting: boolean;
private watchingPaused: boolean;
private stopping: boolean;
private logger: Logger;
private readonly runner: LiveModeRunner;
private keyboardObserver: LiveModeKeyboardEventObserver;
private fileWatcher: FileWatcher;
public constructor (runner: LiveModeRunner);
public init (files: string[]): Promise<void>;
public dispose (): void;
public runTests (sourceChanged?: boolean): Promise<void>;
public onTestRunDone (err: Error): void;
public toggleWatching (): void;
public stop (): Promise<void>;
public restart (): Promise<void>;
public exit (): Promise<void>;
public addFileToWatches (filename: string): void;
protected _createFileWatcher (): FileWatcher;
protected _createKeyboardObserver (): LiveModeKeyboardEventObserver;
private _isTestFilesNotFoundError (err: Error): boolean;
private _initFileWatching (files: string[]): void;
private _setRunning (): void;
}
Import
import LiveModeRunner from './test-runner';
import LiveModeController from './controller';
// Internal imports only; live mode is activated via CLI flag or API option
I/O Contract
Inputs (LiveModeRunner)
| Name | Type | Required | Description |
|---|---|---|---|
| proxy | Proxy |
Yes | The testcafe-hammerhead proxy instance. |
| browserConnectionGateway | BrowserConnectionGateway |
Yes | Gateway managing browser connections. |
| configuration | Configuration |
Yes | The TestCafe configuration object. |
options (to run) |
Object |
No | Run-time options (same as standard runner options). |
Inputs (LiveModeController)
| Name | Type | Required | Description |
|---|---|---|---|
| runner | LiveModeRunner |
Yes | The live mode runner instance this controller manages. |
files (to init) |
string[] |
Yes | Array of test file paths to watch for changes. |
Outputs
| Name | Type | Description |
|---|---|---|
| run() | Promise<void> |
Resolves when the user exits live mode (via Ctrl+C or the exit command).
|
| runTests() | Promise<void> |
Resolves when a single test cycle completes. |
| suspend() | Promise<void> |
Resolves when the current test run is gracefully stopped. |
| configurationCache | null | Cached runnable configuration (tests, browser connections, etc.) to avoid re-bootstrapping. |
Usage Examples
# Activate live mode from the CLI
testcafe chrome tests/ --live
# Or using the short flag
testcafe chrome tests/ -L
// Programmatic API usage
const createTestCafe = require('testcafe');
async function runLiveMode () {
const testcafe = await createTestCafe('localhost', 1337, 1338);
const liveRunner = testcafe.createLiveModeRunner();
await liveRunner
.src('tests/')
.browsers('chrome')
.run();
// The promise above resolves only when the user exits live mode
await testcafe.close();
}
runLiveMode();
Keyboard shortcuts during live mode:
| Key | Action |
|---|---|
Ctrl+S |
Toggle file watching on/off |
Ctrl+R |
Restart current test run |
Ctrl+C |
Stop current run / Exit live mode |
Related Pages
Note: This is an orphan Implementation — live mode test execution is an internal subsystem with no dedicated Principle page.