Principle:DevExpress Testcafe CI Reporter And Artifacts
| Knowledge Sources | |
|---|---|
| Domains | Testing, CI_CD, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
CI Reporter and Artifacts is the generation of machine-readable test reports and collection of visual artifacts for integration with continuous integration platforms.
Description
CI platforms require structured test results in standardized formats to display pass/fail statistics, generate trend reports, and integrate with notification systems. This principle encompasses the transformation of test execution data into consumable formats and the systematic capture of visual evidence (screenshots, videos) for debugging failures.
Key aspects include:
- Machine-Readable Formats: Generating xUnit XML for JUnit-compatible systems, JSON for custom dashboards
- Multiple Reporters: Running several reporters simultaneously (spec for console, xUnit for CI, JSON for storage)
- Screenshot Management: Capturing screenshots on test failures with configurable paths and naming patterns
- Video Recording: Recording full test execution for post-mortem analysis
- Report Aggregation: Combining results from parallel test runs
- Artifact Storage: Persisting reports and screenshots as CI artifacts for later access
- Stream Handling: Writing to files or stdout based on CI platform requirements
Usage
Use CI Reporter and Artifacts when:
- Integrating TestCafe with CI platforms (Jenkins, GitHub Actions, GitLab CI, TeamCity)
- Generating JUnit XML for test result visualization in CI dashboards
- Creating JSON reports for custom analytics or dashboards
- Capturing screenshots automatically on test failures for debugging
- Recording videos of test execution for visual validation
- Storing test results for historical trend analysis
- Integrating with issue tracking systems (JIRA, GitHub Issues)
Theoretical Basis
Core Concept: Test execution events (test start, test end, assertion failure, etc.) are observed and transformed into structured formats that CI platforms can consume, while visual artifacts are captured at key moments and stored with standardized naming conventions.
Reporter Event Flow:
// Observer pattern for test events
CLASS ReporterPluginHost:
reporters = [] // List of active reporters
METHOD reportTestDone(testName, errors, duration):
FOR EACH reporter IN reporters:
reporter.reportTestDone(testName, errors, duration)
METHOD reportTaskDone(passed, failed, skipped, totalTime):
FOR EACH reporter IN reporters:
reporter.reportTaskDone(passed, failed, skipped, totalTime)
// xUnit XML Reporter
CLASS XUnitReporter:
testCases = []
METHOD reportTestDone(testName, errors, duration):
testCase = {
name: testName,
time: duration,
failures: errors.map(e => {
message: e.message,
stackTrace: e.stack
})
}
testCases.append(testCase)
METHOD reportTaskDone(passed, failed, skipped, totalTime):
xml = generateXUnitXML(testCases, passed, failed, skipped, totalTime)
WRITE_TO_FILE(outputPath, xml)
// JSON Reporter
CLASS JSONReporter:
results = []
METHOD reportTestDone(testName, errors, duration):
results.append({
name: testName,
errs: errors,
durationMs: duration,
passed: errors.length === 0
})
METHOD reportTaskDone(passed, failed, skipped, totalTime):
json = JSON.stringify({
passed: passed,
failed: failed,
skipped: skipped,
total: passed + failed + skipped,
durationMs: totalTime,
tests: results
})
WRITE_TO_FILE(outputPath, json)
Screenshot Capture Strategy:
// Screenshot configuration
CONFIG ScreenshotConfig:
path: string // Base directory for screenshots
takeOnFails: boolean // Capture on test failure
pathPattern: string // Naming pattern with placeholders
fullPage: boolean // Capture full page vs viewport
// Path pattern placeholders
PLACEHOLDERS = {
${DATE}: current_date,
${TIME}: current_time,
${TEST_ID}: test_identifier,
${FIXTURE}: fixture_name,
${TEST}: test_name,
${BROWSER}: browser_name,
${QUARANTINE_ATTEMPT}: retry_number
}
FUNCTION captureScreenshot(testRun, screenshotPath):
IF NOT testRun.test.failed AND NOT config.takeOnFails:
RETURN null
// Generate screenshot filename
filename = REPLACE_PLACEHOLDERS(
config.pathPattern,
{
TEST_ID: testRun.test.id,
FIXTURE: testRun.test.fixture.name,
TEST: testRun.test.name,
BROWSER: testRun.browser.alias
}
)
fullPath = JOIN_PATH(config.path, filename)
// Capture browser viewport or full page
IF config.fullPage:
image = CAPTURE_FULL_PAGE(testRun.browser)
ELSE:
image = CAPTURE_VIEWPORT(testRun.browser)
WRITE_FILE(fullPath, image)
RETURN fullPath
Multiple Reporter Coordination:
// Multiple reporters can run simultaneously
reporters = [
{ name: "spec", output: stdout },
{ name: "xunit", output: "reports/xunit.xml" },
{ name: "json", output: "reports/results.json" }
]
FUNCTION dispatchEvent(eventName, ...args):
promises = []
FOR EACH reporter IN reporters:
IF reporter HAS METHOD eventName:
promise = reporter[eventName](...args)
promises.append(promise)
AWAIT Promise.all(promises) // Wait for all reporters
xUnit XML Format:
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="10" failures="2" errors="0" time="45.123">
<testsuite name="My Test Suite" tests="10" failures="2" skipped="1" time="45.123">
<testcase name="Test login success" time="2.456" classname="LoginFixture">
<!-- Passed test - no child elements -->
</testcase>
<testcase name="Test login failure" time="1.234" classname="LoginFixture">
<failure message="Expected 'Dashboard' but got 'Error'">
<![CDATA[
AssertionError: Expected 'Dashboard' but got 'Error'
at LoginPage.verifyTitle (login.js:45:12)
]]>
</failure>
</testcase>
</testsuite>
</testsuites>