Implementation:DevExpress Testcafe CI Reporter Usage
| Knowledge Sources | |
|---|---|
| Domains | Testing, CI_CD, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Reporter plugin system for generating xUnit XML and JSON test reports in CI environments, with screenshot artifact management.
Description
TestCafe's reporter system provides a plugin architecture for transforming test execution events into various output formats. The `Reporter.getReporterPlugins` static method processes reporter configurations and instantiates reporter plugins, handling output stream creation (file or stdout) and plugin factory resolution. The system supports multiple simultaneous reporters, enabling teams to generate console output for developers, xUnit XML for Jenkins/GitHub Actions, and JSON for custom dashboards in a single test run.
The implementation includes:
- Plugin Loading: Dynamic loading of built-in and custom reporter plugins
- Stream Management: Automatic creation of output file streams with directory creation
- Multiple Outputs: Simultaneous reporting to console and multiple file formats
- Screenshot Integration: Coordinated capture and storage of failure screenshots
- Error Handling: Graceful handling of reporter plugin errors with detailed messages
Usage
Use this implementation when:
- Configuring TestCafe for CI pipeline integration
- Generating JUnit-compatible XML reports for Jenkins, GitHub Actions, TeamCity
- Creating JSON reports for custom test result processing
- Capturing screenshots on test failures for debugging
- Running multiple reporters simultaneously (console + file outputs)
Code Reference
Source Location
- Repository: testcafe
- File: src/reporter/index.ts
- Lines: 287-307 (getReporterPlugins method)
- Related: src/screenshots/index.js:9-80 (screenshot management)
Signature
class Reporter {
public static async getReporterPlugins(
reporters: ReporterSource[] = []
): Promise<ReporterPluginSource[]>
}
interface ReporterSource {
name: string; // Reporter name (e.g., 'xunit', 'json', 'spec')
output?: string; // Output file path or stream
options?: object; // Reporter-specific options
}
interface ReporterPluginSource {
plugin: ReporterPlugin; // Instantiated reporter plugin
name: string; // Processed reporter name
outStream?: WritableStream; // Output stream (file or stdout)
}
Import
// Internal TestCafe usage
import Reporter from './reporter';
// CLI usage - no direct import needed
// Configured via command-line flags or .testcaferc.js
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| reporters | ReporterSource[] | No | Array of reporter configurations (default: spec to stdout) |
| reporters[].name | string | Yes | Reporter name ('spec', 'list', 'minimal', 'xunit', 'json', or custom) |
| reporters[].output | string | No | File path for output (default: stdout) |
| reporters[].options | object | No | Reporter-specific configuration options |
Outputs
| Name | Type | Description |
|---|---|---|
| ReporterPluginSource[] | array | Array of instantiated reporter plugins with output streams |
| report files | files | Generated report files (xunit.xml, results.json, etc.) |
| screenshots | files | Captured screenshots in configured directory |
Usage Examples
CLI: Single Reporter to File
# Generate xUnit XML report
testcafe chrome tests/ --reporter xunit:report.xml
# Generate JSON report
testcafe chrome tests/ --reporter json:results.json
CLI: Multiple Reporters
# Console output + xUnit XML + JSON
testcafe chrome tests/ \
--reporter spec,xunit:report.xml,json:results.json
# Spec to console, xUnit to file
testcafe chrome tests/ \
--reporter spec \
--reporter xunit:./reports/junit.xml
CLI: Screenshots on Failures
# Take screenshots on failures only
testcafe chrome tests/ \
--screenshots path=./screenshots,takeOnFails=true \
--reporter xunit:report.xml
# Custom screenshot path pattern
testcafe chrome tests/ \
--screenshots path=./screenshots,takeOnFails=true,pathPattern='${DATE}_${TIME}/${TEST}.png' \
--reporter json:results.json
Configuration File: .testcaferc.js
module.exports = {
reporter: [
{
name: 'spec',
output: 'stdout'
},
{
name: 'xunit',
output: 'reports/junit.xml'
},
{
name: 'json',
output: 'reports/results.json'
}
],
screenshots: {
path: './screenshots',
takeOnFails: true,
pathPattern: '${DATE}_${TIME}/${FIXTURE}/${TEST}/${BROWSER}.png'
}
};
Programmatic API
const createTestCafe = require('testcafe');
(async () => {
const testcafe = await createTestCafe('localhost', 1337, 1338);
const runner = testcafe.createRunner();
await runner
.src('tests/**/*.js')
.browsers('chrome:headless')
.reporter('spec') // Console output
.reporter('xunit', 'report.xml') // xUnit file
.reporter('json', 'results.json') // JSON file
.screenshots({
path: './screenshots',
takeOnFails: true
})
.run();
await testcafe.close();
})();
GitHub Actions: Artifact Upload
name: TestCafe Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
- run: npm ci
- name: Run TestCafe tests
run: |
testcafe chrome:headless tests/ \
--reporter xunit:reports/junit.xml \
--reporter json:reports/results.json \
--screenshots path=screenshots,takeOnFails=true
continue-on-error: true
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-reports
path: reports/
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v3
with:
name: test-screenshots
path: screenshots/
- name: Publish test results
if: always()
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: reports/junit.xml
Built-in Reporters
// Available built-in reporters:
reporters = [
'spec', // Detailed spec-style console output (default)
'list', // Simple list format
'minimal', // Minimal console output
'xunit', // JUnit-compatible XML
'json' // Machine-readable JSON
]
// Custom reporters can be installed via npm:
// npm install testcafe-reporter-html
// testcafe chrome tests/ --reporter html:report.html
JSON Report Format
// Example JSON output structure
{
"startTime": "2026-02-12T04:00:00.000Z",
"endTime": "2026-02-12T04:05:23.456Z",
"userAgents": ["Chrome 110.0.0 / macOS 10.15"],
"passed": 8,
"failed": 2,
"skipped": 1,
"total": 11,
"fixtures": [
{
"name": "Login Tests",
"path": "/tests/login.test.js",
"tests": [
{
"name": "Login with valid credentials",
"errs": [],
"durationMs": 2456,
"screenshotPath": null,
"skipped": false
},
{
"name": "Login with invalid credentials",
"errs": [
{
"errMsg": "AssertionError: expected 'Error' to equal 'Dashboard'",
"userAgent": "Chrome 110.0.0 / macOS 10.15"
}
],
"durationMs": 1234,
"screenshotPath": "/screenshots/2026-02-12_04-03-45/login-failure.png",
"skipped": false
}
]
}
]
}