CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-testcafe

Automated browser testing for the modern web development stack.

Pending
Overview
Eval results
Files

programmatic-api.mddocs/

Programmatic API

TestCafe's programmatic API enables you to create, configure, and run tests through JavaScript code rather than the command line, providing fine-grained control over test execution and integration with other tools.

Capabilities

TestCafe Instance Creation

Create and configure TestCafe instances programmatically.

/**
 * Creates a TestCafe instance for programmatic test execution
 * @param hostname - Hostname for TestCafe servers (default: 'localhost')
 * @param port1 - Port for main TestCafe server (default: auto-assigned)
 * @param port2 - Port for file server (default: auto-assigned)
 * @param sslOptions - SSL configuration for HTTPS
 * @param developmentMode - Enable development mode features
 * @param retryTestPages - Retry test pages on failure
 * @param cache - Enable caching
 * @param configFile - Path to configuration file
 * @returns Promise resolving to TestCafe instance
 */
function createTestCafe(
    hostname?: string,
    port1?: number,
    port2?: number,
    sslOptions?: SSLOptions,
    developmentMode?: boolean,
    retryTestPages?: boolean,
    cache?: boolean,
    configFile?: string
): Promise<TestCafe>;

// Alternative: Configuration object approach
function createTestCafe(config?: TestCafeConfiguration): Promise<TestCafe>;

interface TestCafe {
    /** Create a test runner instance */
    createRunner(): Runner;
    
    /** Create browser connection for remote browsers */
    createBrowserConnection(): Promise<BrowserConnection>;
    
    /** Create live mode runner */
    createLiveModeRunner(): LiveModeRunner;
    
    /** Close TestCafe instance and cleanup resources */
    close(): Promise<void>;
}

interface SSLOptions {
    key?: string;
    cert?: string;
    pfx?: string;
    passphrase?: string;
}

interface TestCafeConfiguration {
    hostname?: string;
    port1?: number;
    port2?: number;
    ssl?: SSLOptions;
    developmentMode?: boolean;
    retryTestPages?: boolean;
    cache?: boolean;
    configFile?: string;
}

Usage Examples:

import createTestCafe from 'testcafe';

// Basic TestCafe instance
async function runBasicTests() {
    const testcafe = await createTestCafe('localhost', 1337, 1338);
    
    try {
        const runner = testcafe.createRunner();
        
        const failedCount = await runner
            .src(['tests/fixture1.js', 'tests/fixture2.js'])
            .browsers(['chrome', 'firefox'])
            .run();
        
        console.log(`Tests failed: ${failedCount}`);
    } finally {
        await testcafe.close();
    }
}

// Configuration object approach
async function runConfiguredTests() {
    const testcafe = await createTestCafe({
        hostname: 'localhost',
        port1: 1337,
        port2: 1338,
        ssl: {
            key: './ssl/private-key.pem',
            cert: './ssl/certificate.pem'
        },
        developmentMode: true
    });
    
    try {
        // Test execution code
    } finally {
        await testcafe.close();
    }
}

// Auto-port assignment
async function runAutoPortTests() {
    const testcafe = await createTestCafe(); // Uses default localhost and auto-assigned ports
    
    try {
        const runner = testcafe.createRunner();
        await runner.src('tests/**/*.js').browsers('chrome').run();
    } finally {
        await testcafe.close();
    }
}

Test Runner Configuration

Configure test execution through the Runner interface.

interface Runner {
    /** Set test source files or globs */
    src(source: string | string[]): Runner;
    
    /** Set target browsers */
    browsers(browsers: string | string[]): Runner;
    
    /** Set test execution concurrency */
    concurrency(concurrency: number): Runner;
    
    /** Set test reporter */
    reporter(reporter: string | ReporterPlugin, output?: string): Runner;
    
    /** Set test filter */
    filter(filter: (testName: string, fixtureName: string, fixturePath: string, testMeta: object, fixtureMeta: object) => boolean): Runner;
    
    /** Run tests and return number of failed tests */
    run(options?: RunOptions): Promise<number>;
    
    /** Stop test execution */
    stop(): Promise<void>;
}

interface RunOptions {
    /** Skip JS errors in tests */
    skipJsErrors?: boolean;
    
    /** Disable page reloads */
    disablePageReloads?: boolean;
    
    /** Quarantine mode for unstable tests */
    quarantineMode?: boolean | QuarantineOptions;
    
    /** Debug mode */
    debugMode?: boolean;
    
    /** Debug on fail */
    debugOnFail?: boolean;
    
    /** Skip uncaught errors */
    skipUncaughtErrors?: boolean;
    
    /** Selector timeout */
    selectorTimeout?: number;
    
    /** Assertion timeout */
    assertionTimeout?: number;
    
    /** Page load timeout */
    pageLoadTimeout?: number;
    
    /** Test execution speed */
    speed?: number;
    
    /** Stop on first test failure */
    stopOnFirstFail?: boolean;
}

interface QuarantineOptions {
    /** Number of attempts to run failing tests */
    attemptLimit?: number;
    
    /** Number of successful runs required to pass */
    successThreshold?: number;
}

Usage Examples:

async function configureRunner() {
    const testcafe = await createTestCafe();
    
    try {
        const runner = testcafe.createRunner();
        
        const failedCount = await runner
            .src(['tests/login.js', 'tests/checkout.js'])
            .browsers(['chrome:headless', 'firefox:headless'])
            .concurrency(3)
            .reporter('spec')
            .filter((testName, fixtureName) => {
                return testName.includes('critical') || fixtureName.includes('smoke');
            })
            .run({
                skipJsErrors: true,
                quarantineMode: true,
                speed: 0.8,
                stopOnFirstFail: false,
                selectorTimeout: 10000,
                assertionTimeout: 5000
            });
        
        if (failedCount > 0) {
            console.error(`${failedCount} tests failed`);
            process.exit(1);
        }
    } finally {
        await testcafe.close();
    }
}

// Multiple reporter configuration
async function runWithMultipleReporters() {
    const testcafe = await createTestCafe();
    
    try {
        const runner = testcafe.createRunner();
        
        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter([
                {
                    name: 'spec',
                    output: process.stdout
                },
                {
                    name: 'json',
                    output: 'reports/test-results.json'
                },
                {
                    name: 'xunit',
                    output: 'reports/test-results.xml'
                }
            ])
            .run();
    } finally {
        await testcafe.close();
    }
}

Browser Management

Manage browser connections and configurations.

interface BrowserConnection {
    /** Browser connection URL for remote browsers */
    url: string;
    
    /** Unique identifier for the connection */
    id: string;
    
    /** Connection ready promise */
    ready: Promise<void>;
    
    /** Establish browser connection */
    establish(userAgent: string): Promise<void>;
    
    /** Close browser connection */
    close(): Promise<void>;
}

interface LiveModeRunner extends Runner {
    /** Watch files for changes */
    watchFiles(files: string | string[]): LiveModeRunner;
    
    /** Start live mode */
    run(): Promise<void>;
    
    /** Stop live mode */
    stop(): Promise<void>;
}

Usage Examples:

// Remote browser connection
async function setupRemoteBrowser() {
    const testcafe = await createTestCafe();
    
    try {
        const connection = await testcafe.createBrowserConnection();
        
        console.log(`Connect remote browser to: ${connection.url}`);
        
        // Wait for browser to connect
        await connection.ready;
        console.log('Remote browser connected');
        
        const runner = testcafe.createRunner();
        
        await runner
            .src('tests/remote-tests.js')
            .browsers(connection)
            .run();
            
    } finally {
        await testcafe.close();
    }
}

// Live mode testing
async function runLiveMode() {
    const testcafe = await createTestCafe();
    
    try {
        const liveRunner = testcafe.createLiveModeRunner();
        
        await liveRunner
            .src('tests/live-tests.js')
            .browsers('chrome')
            .watchFiles(['tests/**/*.js', 'src/**/*.js'])
            .run();
            
    } finally {
        await testcafe.close();
    }
}

// Multiple browser connections
async function runMultipleBrowsers() {
    const testcafe = await createTestCafe();
    
    try {
        const connection1 = await testcafe.createBrowserConnection();
        const connection2 = await testcafe.createBrowserConnection();
        
        console.log(`Browser 1: ${connection1.url}`);
        console.log(`Browser 2: ${connection2.url}`);
        
        await Promise.all([connection1.ready, connection2.ready]);
        
        const runner = testcafe.createRunner();
        
        await runner
            .src('tests/cross-browser.js')
            .browsers([connection1, connection2, 'chrome:headless'])
            .concurrency(3)
            .run();
            
    } finally {
        await testcafe.close();
    }
}

Advanced Configuration

Advanced TestCafe configuration and customization options.

// Custom reporter integration
interface ReporterPlugin {
    reportTaskStart(startTime: Date, userAgents: string[], testCount: number): void;
    reportFixtureStart(name: string, path: string, meta: object): void;
    reportTestStart(name: string, meta: object): void;
    reportTestDone(name: string, testRunInfo: TestRunInfo): void;
    reportTaskDone(endTime: Date, passed: number, warnings: string[], result: object): void;
}

interface TestRunInfo {
    errs: TestError[];
    durationMs: number;
    unstable: boolean;
    screenshotPath: string;
    screenshots: Screenshot[];
    videos: Video[];
    quarantine: object;
    skipped: boolean;
}

// Custom browser provider
interface BrowserProvider {
    openBrowser(id: string, pageUrl: string, browserName: string): Promise<void>;
    closeBrowser(id: string): Promise<void>;
    resizeWindow(id: string, width: number, height: number): Promise<void>;
    takeScreenshot(id: string, screenshotPath: string, pageWidth: number, pageHeight: number): Promise<void>;
}

Usage Examples:

// Custom reporter
class CustomReporter {
    reportTaskStart(startTime, userAgents, testCount) {
        console.log(`Starting ${testCount} tests at ${startTime}`);
        console.log(`User agents: ${userAgents.join(', ')}`);
    }
    
    reportFixtureStart(name, path, meta) {
        console.log(`\n=== Fixture: ${name} ===`);
        console.log(`Path: ${path}`);
    }
    
    reportTestStart(name, meta) {
        console.log(`\n► Running: ${name}`);
    }
    
    reportTestDone(name, testRunInfo) {
        const status = testRunInfo.errs.length > 0 ? 'FAILED' : 'PASSED';
        const duration = testRunInfo.durationMs;
        
        console.log(`◄ ${status}: ${name} (${duration}ms)`);
        
        if (testRunInfo.errs.length > 0) {
            testRunInfo.errs.forEach(err => {
                console.error(`   Error: ${err.errMsg}`);
            });
        }
        
        if (testRunInfo.screenshots.length > 0) {
            console.log(`   Screenshots: ${testRunInfo.screenshots.length}`);
        }
    }
    
    reportTaskDone(endTime, passed, warnings, result) {
        console.log(`\n=== Test Results ===`);
        console.log(`Passed: ${passed}`);
        console.log(`Failed: ${result.failedCount}`);
        console.log(`Total: ${result.passedCount + result.failedCount}`);
        console.log(`Duration: ${endTime - result.startTime}ms`);
        
        if (warnings.length > 0) {
            console.log(`Warnings: ${warnings.length}`);
        }
    }
}

async function runWithCustomReporter() {
    const testcafe = await createTestCafe();
    
    try {
        const runner = testcafe.createRunner();
        
        await runner
            .src('tests/**/*.js')
            .browsers('chrome')
            .reporter(new CustomReporter())
            .run();
            
    } finally {
        await testcafe.close();
    }
}

// Configuration with environment variables
async function runEnvironmentSpecificTests() {
    const config = {
        hostname: process.env.TESTCAFE_HOSTNAME || 'localhost',
        port1: parseInt(process.env.TESTCAFE_PORT1) || undefined,
        port2: parseInt(process.env.TESTCAFE_PORT2) || undefined,
        developmentMode: process.env.NODE_ENV === 'development'
    };
    
    const testcafe = await createTestCafe(config);
    
    try {
        const runner = testcafe.createRunner();
        
        const browsers = process.env.BROWSERS 
            ? process.env.BROWSERS.split(',')
            : ['chrome:headless'];
        
        const sources = process.env.TEST_FILES
            ? process.env.TEST_FILES.split(',')
            : ['tests/**/*.js'];
        
        await runner
            .src(sources)
            .browsers(browsers)
            .concurrency(parseInt(process.env.CONCURRENCY) || 1)
            .run({
                speed: parseFloat(process.env.TEST_SPEED) || 1,
                skipJsErrors: process.env.SKIP_JS_ERRORS === 'true',
                quarantineMode: process.env.QUARANTINE_MODE === 'true'
            });
            
    } finally {
        await testcafe.close();
    }
}

Integration Examples

Real-world integration examples with build systems and CI/CD.

// Integration with build systems
async function integrationWithBuildSystem() {
    // Pre-test setup
    console.log('Building application...');
    await buildApplication();
    
    console.log('Starting test server...');
    const server = await startTestServer();
    
    const testcafe = await createTestCafe();
    
    try {
        const runner = testcafe.createRunner();
        
        const failedCount = await runner
            .src('tests/integration/**/*.js')
            .browsers(['chrome:headless'])
            .run({
                pageLoadTimeout: 30000,
                assertionTimeout: 10000
            });
        
        // Post-test cleanup
        console.log('Stopping test server...');
        await server.close();
        
        if (failedCount > 0) {
            throw new Error(`${failedCount} tests failed`);
        }
        
    } finally {
        await testcafe.close();
    }
}

// Parallel test execution
async function runParallelTests() {
    const testGroups = [
        'tests/unit/**/*.js',
        'tests/integration/**/*.js',
        'tests/e2e/**/*.js'
    ];
    
    const results = await Promise.all(
        testGroups.map(async (group) => {
            const testcafe = await createTestCafe();
            
            try {
                const runner = testcafe.createRunner();
                
                const failedCount = await runner
                    .src(group)
                    .browsers('chrome:headless')
                    .run();
                
                return { group, failedCount };
            } finally {
                await testcafe.close();
            }
        })
    );
    
    const totalFailed = results.reduce((sum, result) => sum + result.failedCount, 0);
    
    results.forEach(result => {
        console.log(`${result.group}: ${result.failedCount} failed`);
    });
    
    if (totalFailed > 0) {
        process.exit(1);
    }
}

// Conditional test execution
async function runConditionalTests() {
    const testcafe = await createTestCafe();
    
    try {
        const runner = testcafe.createRunner();
        
        // Filter tests based on environment or conditions
        const testFilter = (testName, fixtureName, fixturePath, testMeta, fixtureMeta) => {
            // Skip slow tests in CI
            if (process.env.CI && testMeta.slow) {
                return false;
            }
            
            // Run only smoke tests in staging
            if (process.env.ENVIRONMENT === 'staging' && !testMeta.smoke) {
                return false;
            }
            
            // Skip browser-specific tests
            if (testMeta.browserSpecific && !testMeta.browserSpecific.includes(process.env.BROWSER)) {
                return false;
            }
            
            return true;
        };
        
        await runner
            .src('tests/**/*.js')
            .browsers(process.env.BROWSER || 'chrome:headless')
            .filter(testFilter)
            .run();
            
    } finally {
        await testcafe.close();
    }
}

Install with Tessl CLI

npx tessl i tessl/npm-testcafe

docs

assertions.md

browser-automation.md

client-functions.md

element-selection.md

index.md

programmatic-api.md

request-interception.md

user-roles.md

tile.json