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 Runner Fluent API

From Leeroopedia
Knowledge Sources
Domains Testing, Web_Automation
Last Updated 2026-02-12 04:00 GMT

Overview

Concrete fluent interface for configuring test execution through chainable method calls provided by the TestCafe Runner class.

Description

The Runner class provides a comprehensive fluent API with methods that configure different aspects of test execution and return the runner instance to enable chaining. Each method stores configuration in the runner's internal _options object and some methods enforce single-call constraints using the apiMethodWasCalled FlagList to prevent conflicting configurations.

Methods fall into two categories: single-call methods (src, browsers, reporter, clientScripts) that throw errors if called multiple times, and multi-call methods (concurrency, screenshots, video, filter, etc.) that can be called multiple times with later calls overriding earlier ones.

Usage

Use the fluent API to configure a runner after creation and before calling run. Chain methods in a logical order: test sources, browsers, reporters, then optional configuration like screenshots, videos, and concurrency. The API enables readable, self-documenting test setup code.

Code Reference

Source Location

  • Repository: testcafe
  • File: src/runner/index.js
  • Lines: 700-798 (fluent API methods)

Signature

class Runner {
    // Test sources
    src(...sources: string[]): Runner

    // Browsers
    browsers(...browsers: string[]): Runner

    // Concurrency
    concurrency(n: number): Runner

    // Reporter
    reporter(name: string, output?: Writable): Runner

    // Test filtering
    filter(fn: (testName, fixtureName, fixturePath, testMeta, fixtureMeta) => boolean): Runner

    // Proxy configuration
    useProxy(proxy: string, proxyBypass?: string | string[]): Runner

    // Screenshots
    screenshots(path: string, takeOnFails?: boolean, pathPattern?: string): Runner
    screenshots(options: ScreenshotOptions): Runner

    // Video recording
    video(path: string, options?: VideoOptions, encodingOptions?: VideoEncodingOptions): Runner

    // Tested application
    startApp(command: string, initDelay?: number): Runner

    // TypeScript configuration
    tsConfigPath(path: string): Runner

    // Client scripts
    clientScripts(...scripts: (string | ClientScriptInit)[]): Runner

    // Compiler options
    compilerOptions(opts: CompilerOptions): Runner

    // Execute tests
    run(options?: RunOptions): Promise<number>

    // Stop execution
    stop(): Promise<void>
}

Import

const createTestCafe = require('testcafe');

const testcafe = await createTestCafe();
const runner = testcafe.createRunner();
// Use fluent API methods on runner

I/O Contract

Single-Call Methods (throw if called multiple times)

Method Parameters Description
src ...sources: string[] Test file paths or glob patterns
browsers ...browsers: string[] Browser aliases or connection objects
reporter name: string, output?: Writable Reporter name and optional output stream
clientScripts ...scripts Client-side scripts to inject

Multi-Call Methods (can be called multiple times)

Method Parameters Description
concurrency n: number Number of parallel browser instances (default: 1)
filter fn: Function Test filter function (testName, fixtureName, etc.)
useProxy proxy: string, proxyBypass?: string/string[] Proxy server and bypass rules
screenshots path/options Screenshot path and configuration
video path: string, options?, encodingOptions? Video recording configuration
startApp command: string, initDelay?: number Command to start tested application
tsConfigPath path: string Path to TypeScript configuration file
compilerOptions opts: object Compiler-specific options

Outputs

All methods return the Runner instance (this) for chaining.

Usage Examples

Basic Fluent Configuration

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome', 'firefox')
            .reporter('spec')
            .concurrency(2)
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Advanced Configuration with Screenshots and Video

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome:headless')
            .reporter('spec')
            .screenshots({
                path: 'screenshots/',
                takeOnFails: true,
                pathPattern: '${DATE}_${TIME}/test-${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.png',
                fullPage: true
            })
            .video('videos/', {
                failedOnly: true,
                singleFile: false
            })
            .concurrency(4)
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Test Filtering

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter('spec')
            .filter((testName, fixtureName, fixturePath, testMeta, fixtureMeta) => {
                // Only run tests marked as 'smoke'
                return testMeta.type === 'smoke';
            })
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Starting Tested Application

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter('spec')
            .startApp('node server.js', 5000)  // Start server, wait 5s
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Client Scripts Injection

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter('spec')
            .clientScripts([
                'scripts/mock-date.js',
                { module: 'lodash' },
                {
                    content: 'window.myGlobal = "test";',
                    page: 'https://example.com'
                }
            ])
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

TypeScript Configuration

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.ts')
            .browsers('chrome')
            .reporter('spec')
            .tsConfigPath('./tsconfig.test.json')
            .compilerOptions({
                typescript: {
                    configPath: './tsconfig.test.json',
                    customCompilerModulePath: './custom-typescript'
                }
            })
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Proxy Configuration

const createTestCafe = require('testcafe');

(async () => {
    const testcafe = await createTestCafe();

    try {
        const runner = testcafe.createRunner();

        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter('spec')
            .useProxy('http://proxy.company.com:8080', [
                'localhost',
                '*.internal.com'
            ])
            .run();
    }
    finally {
        await testcafe.close();
    }
})();

Implementation Details

Single-Call Enforcement

Methods like src, browsers, reporter, and clientScripts check the apiMethodWasCalled flag and throw if called multiple times:

src(...sources) {
    if (this.apiMethodWasCalled.src)
        throw new GeneralError(RUNTIME_ERRORS.multipleAPIMethodCallForbidden, OPTION_NAMES.src);

    this._options[OPTION_NAMES.src] = this._prepareArrayParameter(sources);
    this.apiMethodWasCalled.src     = true;

    return this;
}

This prevents accidental configuration conflicts and makes the API more predictable.

Array Parameter Preparation

Methods accepting multiple arguments use _prepareArrayParameter to flatten nested arrays:

_prepareArrayParameter(array) {
    array = flatten(array);  // lodash flattenDeep

    if (this.isCli)
        return array.length === 0 ? void 0 : array;

    return array;
}

This allows both spread arguments and array arguments:

  • runner.src('test1.js', 'test2.js')
  • runner.src(['test1.js', 'test2.js'])
  • runner.src('test1.js', ['test2.js', 'test3.js'])

Configuration Storage

All methods store configuration in this._options, which is later merged with the global configuration object during run preparation:

concurrency(concurrency) {
    this._options.concurrency = concurrency;
    return this;
}

Related Pages

Implements Principle

Related Implementations

Page Connections

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