Implementation:DevExpress Testcafe Screenshots And VideoRecorder
| Knowledge Sources | |
|---|---|
| Domains | Testing, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Concrete screenshot and video capture implementation for TestCafe that records visual artifacts during test execution with configurable path patterns and encoding options.
Description
The TestCafe visual capture system consists of the Screenshots class (src/screenshots/index.js:L9-80) and VideoRecorder class (src/video-recorder/recorder.js:L24-202).
The Screenshots class manages still image capture with configurable options: enabled flag, path for base directory, pathPattern for file naming (supporting placeholders ${DATE}_${TIME}/${FIXTURE}/${TEST}/${BROWSER}), pathPatternOnFails for failure-specific patterns, fullPage for full-page scrolling captures, and thumbnails for generating preview images. The createCapturerFor() method (L61-73) instantiates a Capturer for each test run, passing a PathPattern instance that resolves placeholders using test metadata and timestamp.
The VideoRecorder class captures continuous video using ffmpeg, with options for failedOnly (only save failed test videos), singleFile (concatenate all tests), ffmpegPath (custom ffmpeg binary), pathPattern (output naming), and encodingOptions (codec, bitrate, fps). It subscribes to browser job events: _onTestRunCreate() (L113-141) starts recording, _onTestRunBeforeDone() (L165-192) stops recording and conditionally encodes/saves based on test result.
Both systems use moment.js for timestamps, make-dir for recursive directory creation, and debug for logging. Path patterns emit warnings for problematic placeholders in unsupported contexts (e.g., ${TEST} in singleFile mode).
Usage
Use Screenshots and VideoRecorder classes when configuring a test run to enable visual artifact capture for debugging and documentation.
Code Reference
Source Location
- Repository: testcafe
- File: src/screenshots/index.js (Screenshots), src/video-recorder/recorder.js (VideoRecorder)
- Lines: L9-80 (Screenshots), L24-202 (VideoRecorder)
Signature
// Screenshots class
class Screenshots {
constructor({ enabled, path, pathPattern, pathPatternOnFails, fullPage, thumbnails })
createCapturerFor(test, testIndex, quarantine, connection, warningLog): Capturer
getScreenshotsInfo(test): ScreenshotInfo[]
hasCapturedFor(test): boolean
getPathFor(test): string
}
// VideoRecorder class
class VideoRecorder extends EventEmitter {
constructor(browserJob, basePath, opts, encodingOpts, warningLog)
// Internal lifecycle methods (called by browserJob events)
_onTestRunCreate(testRun)
_onTestRunBeforeDone(testRun)
_getTargetVideoPath(testRunRecorder): string
}
Import
import Screenshots from './screenshots';
import VideoRecorder from './video-recorder/recorder';
// Initialize screenshot manager
const screenshots = new Screenshots({
enabled: true,
path: './screenshots',
pathPattern: '${DATE}_${TIME}/${FIXTURE}/${TEST}.png',
fullPage: false
});
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | Enable/disable screenshot capture |
| path | string | Yes | Base directory for screenshot storage |
| pathPattern | string | No | File naming pattern with placeholders (default: '${DATE}_${TIME}/${FIXTURE}/${TEST}.png') |
| pathPatternOnFails | string | No | Alternative pattern for failed tests only |
| fullPage | boolean | No | Capture full scrollable page (default: false) |
| thumbnails | boolean | No | Generate thumbnail previews (default: false) |
| failedOnly | boolean | No | (Video) Only save videos for failed tests |
| singleFile | boolean | No | (Video) Concatenate all tests into one video |
| ffmpegPath | string | No | (Video) Custom ffmpeg binary path |
Outputs
| Name | Type | Description |
|---|---|---|
| Screenshot files | PNG/JPEG | Image files saved to resolved path pattern |
| Video files | MP4 | Encoded video files (via ffmpeg) |
| ScreenshotInfo | object | Metadata about captured screenshots (path, size, timestamp) |
| Capturer | object | Per-test capturer instance for manual screenshot API |
Usage Examples
Basic Screenshot Configuration
import Screenshots from './screenshots';
const screenshots = new Screenshots({
enabled: true,
path: './test-results/screenshots',
pathPattern: '${DATE}_${TIME}/${FIXTURE}/${TEST}/${BROWSER}.png',
pathPatternOnFails: '${DATE}_${TIME}/failed/${FIXTURE}/${TEST}/${BROWSER}.png',
fullPage: true,
thumbnails: true
});
// Create capturer for test run
const test = { name: 'Login test', fixture: { name: 'Auth' } };
const capturer = screenshots.createCapturerFor(
test,
0, // testIndex
null, // quarantine
browserConnection,
warningLog
);
// Manual screenshot capture
await capturer.captureAction({ selector: '#login-button' });
Path Pattern Examples
// Hierarchical organization
// Pattern: '${DATE}_${TIME}/${FIXTURE}/${TEST}/${BROWSER}.png'
// Output: 2026-02-12_14-30-45/Auth/Login test/chrome.png
// Flat organization with timestamps
// Pattern: '${TEST}_${DATE}_${TIME}.png'
// Output: Login test_2026-02-12_14-30-45.png
// Include quarantine attempt
// Pattern: '${FIXTURE}/${TEST}/attempt_${QUARANTINE_ATTEMPT}.png'
// Output: Auth/Login test/attempt_2.png
// Browser-specific directories
// Pattern: '${BROWSER}/${DATE}/${FIXTURE}_${TEST}.png'
// Output: chrome/2026-02-12/Auth_Login test.png
Video Recording Configuration
import VideoRecorder from './video-recorder/recorder';
const videoRecorder = new VideoRecorder(
browserJob,
'./test-results/videos',
{
failedOnly: true, // Only save failed test videos
singleFile: false, // Create separate video per test
ffmpegPath: '/usr/local/bin/ffmpeg',
pathPattern: '${DATE}_${TIME}/${FIXTURE}/${TEST}/${BROWSER}.mp4',
timeStamp: new Date()
},
{
// FFmpeg encoding options
r: 30, // 30 fps
c: 'libx264', // H.264 codec
preset: 'ultrafast', // Encoding speed
pix_fmt: 'yuv420p' // Pixel format
},
warningLog
);
// Video recorder automatically subscribes to browser job events
// Recording starts on test-run-create, stops on test-run-before-done
Screenshot Info Retrieval
// After test execution
const screenshotInfo = screenshots.getScreenshotsInfo(test);
console.log(screenshotInfo);
// [
// {
// screenshotPath: '/path/to/screenshot1.png',
// thumbnailPath: '/path/to/screenshot1_thumb.png',
// userAgent: 'Chrome 96.0.4664.45',
// quarantineAttempt: null,
// takenOnFail: true
// },
// ...
// ]
// Check if screenshots were captured
if (screenshots.hasCapturedFor(test)) {
const basePath = screenshots.getPathFor(test);
console.log(`Screenshots saved to: ${basePath}`);
}
Video Encoding Options
// High quality, slow encoding
const hqOptions = {
r: 60, // 60 fps
c: 'libx264',
preset: 'slow', // Better compression
crf: 18, // Quality (0-51, lower = better)
pix_fmt: 'yuv420p'
};
// Fast encoding for CI
const fastOptions = {
r: 15, // 15 fps
c: 'libx264',
preset: 'ultrafast',
crf: 28,
pix_fmt: 'yuv420p'
};
// VP8/WebM format
const webmOptions = {
r: 30,
c: 'libvpx', // VP8 codec
b: '1M', // 1 Mbps bitrate
pix_fmt: 'yuv420p'
};
Single File Video Concatenation
// When singleFile: true, all tests are concatenated
const videoRecorder = new VideoRecorder(
browserJob,
'./test-results/videos',
{
singleFile: true,
pathPattern: '${DATE}_${TIME}/all-tests.mp4'
// Note: ${TEST}, ${FIXTURE} placeholders are nullified
},
encodingOpts,
warningLog
);
// Internal concatenation uses ffmpeg concat demuxer:
// ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4