Implementation:DevExpress Testcafe BrowserJob
| Knowledge Sources | |
|---|---|
| Domains | Test Execution, Browser Management |
| Last Updated | 2026-02-12 12:00 GMT |
Overview
BrowserJob manages the sequential execution of a test queue within a single browser connection group, coordinating test run lifecycle events and completion ordering.
Description
BrowserJob extends AsyncEventEmitter and is responsible for feeding tests to a group of browser connections one at a time. It maintains a queue of TestRunController instances, tracks pass/fail counts, and ensures test-run-done events are emitted in the order tests were started (via a completion queue). It handles concurrency constraints, fixture-level sequencing for disablePageReloads, and browser disconnection errors. When all queued tests complete, it reports an aggregate result (done, errored, or aborted) back to each browser connection.
Usage
BrowserJob is instantiated by the Task class during test session setup -- one BrowserJob per browser connection group. It is not used directly by test authors. The runner infrastructure calls popNextTestRunInfo when a browser connection is ready for its next test, and abort to cancel all remaining tests in the job.
Code Reference
Source Location
- Repository: DevExpress_Testcafe
- File: src/runner/browser-job.ts
- Lines: 1-294
Signature
export default class BrowserJob extends AsyncEventEmitter {
private _status: BrowserJobStatus;
private _startTime: Date;
private _total: number;
private _passed: number;
private readonly _opts: Dictionary<OptionValue>;
private readonly _proxy: Proxy;
public readonly browserConnections: BrowserConnection[];
private readonly _screenshots: Screenshots;
public readonly warningLog: WarningLog;
public readonly fixtureHookController: FixtureHookController;
private _result: BrowserJobResultInfo | null;
private _testRunControllerQueue: TestRunController[];
private readonly _reportsPending: TestRunController[];
private readonly _connectionErrorListener: (error: Error) => void;
private readonly _completionQueue: TestRunController[];
private _resolveWaitingLastTestInFixture: Function | null;
private readonly _messageBus: MessageBus;
private readonly _testRunHook: TestRunHookController;
private readonly _disableConcurrencyQueue: Dictionary<TestRunController[]>;
public constructor({
tests,
browserConnections,
proxy,
screenshots,
warningLog,
fixtureHookController,
opts,
messageBus,
}: BrowserJobInit);
public get hasQueuedTestRuns(): boolean;
public get currentTestRun(): LegacyTestRun | TestRun | null;
public async popNextTestRunInfo(connection: BrowserConnection): Promise<NextTestRunInfo | null>;
public abort(): void;
}
Import
import BrowserJob from '../runner/browser-job';
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| tests | Test[] |
Yes | Array of test definitions to execute in sequence |
| browserConnections | BrowserConnection[] |
Yes | Browser connections in this group (one per concurrency slot) |
| proxy | Proxy |
Yes | Hammerhead proxy instance for URL rewriting |
| screenshots | Screenshots |
Yes | Screenshot manager for creating capturers per test run |
| warningLog | WarningLog |
Yes | Shared warning log for non-fatal issues |
| fixtureHookController | FixtureHookController |
Yes | Manages before/after fixture hook execution |
| opts | Dictionary<OptionValue> |
Yes | Runner options including concurrency, live mode, quarantine mode, etc. |
| messageBus | MessageBus |
Yes | Central event bus for cross-component communication |
Outputs
| Name | Type | Description |
|---|---|---|
| popNextTestRunInfo return | null> | Returns { testRunId, url } for the next test to run, or null if no tests are available
|
| hasQueuedTestRuns | boolean |
Whether there are remaining tests in any queue |
| currentTestRun | LegacyTestRun | null | The currently active test run at the head of the completion queue |
Events Emitted
| Event | Payload | Description |
|---|---|---|
start |
Date |
Fired when the first test begins execution |
test-run-create |
TestRunInfo |
Fired when a new test run is created |
test-run-ready |
TestRunController |
Fired when a test run is ready for execution |
test-run-before-done |
TestRunController |
Fired before a test run completes (for reporter sequencing) |
test-run-done |
TestRun |
Fired when a test run finishes, in completion order |
test-run-restart |
TestRunController |
Fired when a test run needs to restart (quarantine mode) |
test-action-done |
ActionEventArg |
Fired after each test action completes |
done |
none | Fired when all tests in the job have completed |
Usage Examples
// Internal usage within Task._createBrowserJobs
const job = new BrowserJob({
tests: this.tests,
browserConnections: browserConnectionGroup,
screenshots: this.screenshots,
warningLog: this.warningLog,
fixtureHookController: this.fixtureHookController,
messageBus: this._messageBus,
proxy,
opts,
});
// Listen for lifecycle events
job.on('test-run-done', async (testRun) => {
await messageBus.emit('test-run-done', testRun);
});
job.once('start', async (startTime) => {
await messageBus.emit('start', task);
});
job.once('done', async () => {
// Handle job completion
});
// Pop the next test for a browser connection
const nextInfo = await job.popNextTestRunInfo(connection);
if (nextInfo) {
// Navigate browser to nextInfo.url
// nextInfo.testRunId identifies the test run
}
// Abort all remaining tests
job.abort();
Internal Mechanics
Completion Queue
The _completionQueue ensures test-run-done events are emitted in the order tests were started, not the order they finish. Each TestRunController is appended to the queue when it begins. When a test finishes, the queue drains from the front as long as the head controller is marked done.
Concurrency Handling
When opts.concurrency > 1, multiple tests may execute in parallel across connections. The _isNextTestRunAvailable method gates whether a connection can pick up the next test, checking for fixture hook blocking and pending reports. The _disableConcurrencyQueue is used when a fixture has disableConcurrency set, splitting out that fixture's tests into a per-connection queue.
Result Reporting
Once all completion queue entries drain and no queued tests remain, _setResult reports the final status (done, errored, or aborted) to each browser connection via bc.reportJobResult.