👁️ codeceptjs-visual-helper
A visual regression testing helper for CodeceptJS, providing pixel-by-pixel screenshot comparison with comprehensive support for Playwright, Puppeteer, WebDriver, Appium, WebDriverIO and TestCafe.
Overview 📖
This helper enables automated visual regression testing by comparing screenshots captured during test execution against established baseline images. When differences are detected, the helper generates diff images that highlight the discrepancies, facilitating rapid identification of unintended visual changes.
Key Features
- Multi-driver Support — Seamlessly integrates with Playwright, Puppeteer, WebDriver, Appium, WebDriverIO and TestCafe
- Configurable Tolerance — Define acceptable thresholds for pixel differences
- Ignore Regions — Exclude dynamic content areas from comparison
- Baseline Variations — Support multiple baseline versions for responsive or themed layouts
- Detailed Reporting — Comprehensive diff images and statistics for each comparison
Installation 📦
Requires Node.js 22.19.0 or later. The package is tested with CodeceptJS 4 on Node 22.23.4, 24.22.1 and 26.12.1. Node 18 and 20 are no longer supported.
npm install @digital-commons-official/codeceptjs-visual-helper --save-dev
Configuration ⚙️
Add the helper to your codecept.conf.js configuration file:
helpers: {
Playwright: {
// Your browser helper configuration
},
VisualHelper: {
require: '@digital-commons-official/codeceptjs-visual-helper',
baselineDir: './tests/screenshots/baseline/',
diffDir: './tests/screenshots/diff/',
actualDir: './tests/output/',
tolerance: 1.5,
threshold: 0.1
}
}
Configuration Options
| Option | Type | Default | Description | |
|---|---|---|---|---|
baselineDir | string | ./tests/screenshots/baseline/ | Directory containing baseline images | |
diffDir | string | false | ./tests/screenshots/diff/ | Directory for generated diff images; set to false to disable |
actualDir | string | global.output_dir | Directory for captured screenshots | |
tolerance | number | 0 | Permitted percentage of differing pixels (0–100) | |
threshold | number | 0.1 | Pixelmatch colour comparison threshold (0–1) | |
diffPrefix | string | Diff_ | Filename prefix for diff images | |
imageFormat | string | 'webp' | 'webp' (lossless) or 'png' for older baselines | |
saveIntermediateImages | boolean | false | Retain intermediate processing images for debugging | |
captureActual | boolean | 'missing' | 'missing' | Automatic capture of actual screenshots |
captureBaseline | boolean | 'missing' | 'missing' | Automatic capture of baseline images |
Usage 🚀
Asserting Visual Matches
The assertVisualMatch method compares the current viewport against a baseline image, failing the test if differences exceed the configured tolerance:
// Basic full-page comparison
await I.assertVisualMatch('homepage');
// With custom tolerance
await I.assertVisualMatch('dashboard', { tolerance: 2.5 });
// Element-specific comparison
await I.assertVisualMatch('navigation', { element: '#main-nav' });
// Excluding dynamic regions
await I.assertVisualMatch('profile-page', {
ignoreRegions: [
{ x: 10, y: 10, width: 200, height: 50 } // Timestamp area
]
});
Comparing Without Assertions
The compareVisual method performs comparison and returns detailed results without throwing exceptions:
const result = await I.compareVisual('checkout-form');
if (!result.isMatch) {
console.log(`Visual difference detected: ${result.differencePercent}%`);
console.log(`Diff image saved to: ${result.diffImagePath}`);
}
Capturing Screenshots
// Capture current viewport as actual image
await I.captureScreenshot('landing-page');
// Capture and save as new baseline
await I.captureScreenshot('landing-page', 'baseline');
// Capture specific element
await I.captureScreenshot('footer', 'baseline', 'footer.main');
Comparison Options
| Option | Type | Description |
|---|---|---|
tolerance | number | Override the default tolerance for this comparison |
compareWith | string | Specify a custom baseline image name |
element | string | CSS selector for element-specific comparison |
bounds | object | Bounding box { x, y, width, height } to constrain comparison |
ignoreRegions | array | Array of regions [{ x, y, width, height }] to exclude |
pixelmatchArgs | object | Override pixelmatch library options |
Baseline Variations
The helper supports multiple baseline variations using the tilde (~) suffix convention:
homepage.png # Primary baseline
homepage~dark.png # Dark theme variant
homepage~tablet.png # Tablet viewport variant
During comparison, the helper evaluates all matching variations and reports the best match, enabling comprehensive testing across different visual states.
Comparison Result Object
interface VisualComparisonResult {
isMatch: boolean; // Whether difference is within tolerance
differencePercent: number; // Percentage of differing pixels
differentPixels: number; // Count of differing pixels
totalPixels: number; // Total pixels in the image
comparedPixels: number; // Pixels compared (excluding masked regions)
variationName: string; // Name of the matched variation
diffImagePath: string; // Path to the generated diff image
variations: Array<...>; // Results for all evaluated variations
}
Development 🛠️
Project Structure
project/helper/
├── src/
│ ├── index.js # Main VisualHelper class
│ ├── index.d.ts # TypeScript declarations
│ ├── config/
│ │ └── defaults.js # Default configuration values
│ ├── drivers/
│ │ └── adapter.js # Browser driver abstraction layer
│ ├── services/
│ │ ├── comparator.js # Image comparison logic
│ │ └── path-builder.js # File path construction
│ └── utils/
│ ├── conversion.js # Type conversion utilities
│ ├── filesystem.js # File system operations
│ └── image.js # PNG and WebP manipulation functions
└── tests/
├── config/ # Configuration tests
├── services/ # Service tests
├── utils/ # Utility tests
└── integration/ # Visual comparison integration tests
Running Tests
# Execute all tests (unit, integration, e2e)
task test
# Execute helper unit tests only
task project:test:helper
# Execute integration tests with visual diff output
task project:test:helper:integration
# Execute CodeceptJS end-to-end tests
task project:test:helper:e2e
Integration Tests
The integration tests generate actual diff images that may be inspected visually. Following execution, examine the project/helper/test-output/ directory to review:
- Identical comparison — Baseline and actual images with zero differences
- Different comparison — Images with intentional differences and highlighted diff output
- Tolerance comparison — Demonstration of strict versus lenient tolerance settings
- UI simulation — Complex page comparison with ignore regions
Release & Publishing
The helper is designed to be published as an npm package. The following tasks support the release workflow:
# Inspect package contents locally without publishing
task project:release:helper
# Check the publishing authorization rules in an isolated runner
task project:test:npm
GitLab CI publishes from the protected default branch using npm trusted publishing
(OIDC). The release job takes the default runner tag, served by the group's
self-hosted runners, and requests the npm identity. npm rejects provenance from self-hosted runners, so versions after 3.0.0
carry no provenance attestation. No long-lived npm token or local .npmrc is needed.
Licence 📜
EUPL-1.2