Skip to main content

EXTENSIONS

Image Comparison

Karate provides built-in image comparison for visual regression testing. Compare baseline images against current screenshots to detect unintended UI changes, with detailed diff reports embedded directly in HTML test reports.

On this page:

Video Demo

Watch the image comparison video demo for a walkthrough of visual testing with Karate.

compareImage

The compareImage keyword compares two images and embeds a visual diff UI into the HTML report.

Gherkin
Feature: Basic image comparison

Scenario: Compare screenshots
* def baseline = read('classpath:screenshots/login.png')
* def current = karate.readAsBytes('current-login.png')
* compareImage { baseline: '#(baseline)', latest: '#(current)' }

Loading Images

Images can be loaded using path prefixes or as byte arrays:

Gherkin
Feature: Image loading options

Scenario: Different ways to load images
# Using path prefixes
* compareImage { baseline: 'classpath:screenshots/login.png', latest: 'file:/tmp/login.png' }

# Using this: for relative paths
* compareImage { baseline: 'this:baseline.png', latest: 'this:current.png' }

# Using byte arrays from screenshot()
* def latestBytes = screenshot(false)
* compareImage { baseline: 'classpath:screenshots/login.png', latest: '#(latestBytes)' }

# Using karate.readAsBytes()
* def baseline = karate.readAsBytes('classpath:screenshots/login.png')
* compareImage { baseline: '#(baseline)', latest: 'current.png' }
PrefixDescriptionExample
classpath:Load from classpath (src/test/resources)classpath:screenshots/login.png
file:Load from absolute file pathfile:/tmp/screenshot.png
this:Load relative to current feature filethis:baseline.png

Tolerance Threshold

Allow minor pixel differences with failureThreshold:

Gherkin
Feature: Tolerance-based comparison

Scenario: Compare with 2% tolerance
* configure imageComparison = { failureThreshold: 2 }
* def baseline = read('classpath:screenshots/dashboard.png')
* def current = screenshot(false)
* compareImage { baseline: '#(baseline)', latest: '#(current)' }

The failureThreshold is a percentage (0-100). A value of 2 means comparison passes if less than 2% of pixels differ.

Comparison Engines

Karate supports two comparison algorithms, each suited for different use cases.

Resemble Engine

The default engine. Best for pixel-perfect comparisons with anti-aliasing detection and color tolerance.

Gherkin
Feature: Resemble engine

Scenario: Pixel-perfect comparison
* configure imageComparison = { engine: 'resemble' }
* compareImage { baseline: 'baseline.png', latest: 'current.png' }

When to use Resemble:

  • Pixel-perfect UI validation
  • Detecting color shifts
  • Anti-aliasing tolerance needed
  • Fine-grained control over color channels

SSIM Engine

Structural Similarity Index. Best for perceptual comparisons where minor pixel shifts are acceptable.

Gherkin
Feature: SSIM engine

Scenario: Structural similarity comparison
* configure imageComparison = { engine: 'ssim' }
* compareImage { baseline: 'baseline.png', latest: 'current.png' }

When to use SSIM:

  • Perceptual similarity over pixel-perfect
  • Cross-browser comparisons (minor rendering differences)
  • Images with compression artifacts
  • Faster comparison for large images

Combining Engines

Use both engines together with different behaviors:

Gherkin
Feature: Combined engines

Scenario: Use lowest mismatch percentage
# Comma separator: evaluate both, use the lowest mismatch percentage
* configure imageComparison = { engine: 'resemble,ssim' }
* compareImage { baseline: 'baseline.png', latest: 'current.png' }

Scenario: Fallback engine
# Pipe separator: use second engine only if first fails
* configure imageComparison = { engine: 'resemble|ssim' }
* compareImage { baseline: 'baseline.png', latest: 'current.png' }
SeparatorBehavior
, (comma)Run both engines, use the lowest mismatch percentage
| (pipe)Use second engine as fallback if first fails

Configuration Options

Global Configuration

Set defaults for all comparisons using configure imageComparison:

Gherkin
Feature: Global configuration

Background:
* configure imageComparison = { failureThreshold: 1, hideUiOnSuccess: true }

Scenario: All comparisons use global config
* compareImage { baseline: 'page1.png', latest: 'current1.png' }
* compareImage { baseline: 'page2.png', latest: 'current2.png' }
OptionTypeDefaultDescription
enginestring'resemble'Comparison engine: 'resemble', 'ssim', or combined
failureThresholdnumber0.0Percentage of pixels allowed to differ (0-100)
allowScalingbooleanfalseScale images to match dimensions automatically
hideUiOnSuccessbooleanfalseHide comparison UI in reports when images match
mismatchShouldPassbooleanfalseTreat mismatches as passes (useful for initial baselining)
onShowRebasefunctionnullCustom callback for Rebase button in HTML report
onShowConfigfunctionnullCustom callback for Show Config in HTML report

Initial Baselining

When creating baselines for the first time, use mismatchShouldPass to prevent failures:

Gherkin
Feature: Initial baseline creation

Background:
# All comparisons pass even if images differ
* configure imageComparison = { mismatchShouldPass: true }

Scenario: Create baselines
* driver 'https://httpbin.org'
* def current = screenshot(false)
# This passes but shows the diff UI in reports for review
* compareImage { baseline: 'baseline.png', latest: '#(current)' }

After reviewing the report and downloading baselines, remove mismatchShouldPass.

Per-Comparison Options

Override global settings for individual comparisons using the options parameter:

Gherkin
Feature: Per-comparison options

Background:
* configure imageComparison = { failureThreshold: 1 }

Scenario: Override for specific comparison
# This comparison ignores colors
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ignoreColors: true } }

Ignored Regions

Exclude dynamic areas like timestamps, ads, or loading animations:

Gherkin
Feature: Ignored regions

Scenario: Exclude dynamic content
* def ignoredAreas =
"""
[
{ "top": 10, "left": 900, "bottom": 40, "right": 1200 },
{ "top": 500, "left": 50, "bottom": 550, "right": 250 }
]
"""
* compareImage { baseline: 'baseline.png', latest: 'current.png', options: { ignoredBoxes: '#(ignoredAreas)' } }

Each region is defined with top, left, bottom, right coordinates in pixels.

Ignoring Colors

Ignore specific colors or all colors:

Gherkin
Feature: Color ignoring

Scenario: Ignore all colors (structure only)
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ignoreColors: true } }

Scenario: Ignore specific color (e.g., purple overlay)
* def purple = { "r": 190, "g": 0, "b": 255 }
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ignoreAreasColoredWith: '#(purple)' } }

Resemble Options

Fine-tune the Resemble engine:

Gherkin
Feature: Resemble options

Scenario: Anti-aliasing detection
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ignoreAntialiasing: true } }

Scenario: Use ignore preset
# Presets: 'nothing', 'less', 'antialiasing', 'colors', 'alpha'
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ignore: 'antialiasing' } }

Scenario: Custom color tolerances
* def tolerances =
"""
{
"red": 4,
"green": 4,
"blue": 4,
"alpha": 4,
"minBrightness": 4,
"maxBrightness": 250
}
"""
* compareImage { baseline: 'base.png', latest: 'current.png', options: { tolerances: '#(tolerances)' } }
OptionTypeDescription
ignoredBoxesarrayRegions to exclude: [{top, left, bottom, right}]
ignorestringPreset: 'nothing', 'less', 'antialiasing', 'colors', 'alpha'
ignoreColorsbooleanCompare brightness only
ignoreAntialiasingbooleanIgnore anti-aliasing differences
ignoreAreasColoredWithobjectIgnore specific color: {r, g, b} or {r, g, b, a}
tolerancesobjectCustom thresholds: {red, green, blue, alpha, minBrightness, maxBrightness}

SSIM Options

Configure the SSIM algorithm:

Gherkin
Feature: SSIM options

Scenario: High-precision SSIM
* configure imageComparison = { engine: 'ssim' }
* compareImage {
baseline: 'base.png',
latest: 'current.png',
options: { ssim: 'WEBER', rgb2grayVersion: 'INTEGER', k1: 0.01, k2: 0.03, windowSize: 11 }
}

Scenario: Fast SSIM
* configure imageComparison = { engine: 'ssim' }
* compareImage { baseline: 'base.png', latest: 'current.png', options: { ssim: 'FAST' } }
OptionTypeDefaultDescription
ssimstring'WEBER'Algorithm: 'FAST' or 'WEBER'
rgb2grayVersionstring'INTEGER'Grayscale conversion: 'ORIGINAL' or 'INTEGER'
k1number0.01First stability constant
k2number0.03Second stability constant
windowSizeinteger11Comparison window size
bitDepthinteger8Bits per pixel (8, 16, 32)
maxSizeinteger256Max dimension before downsampling

Report Integration

Viewing Diffs

The comparison UI is automatically embedded in HTML reports showing:

  • Side-by-side baseline and latest images
  • Highlighted diff overlay
  • Mismatch percentage
  • Rebase and Show Config buttons

Custom Rebase Callback

Customize the filename when rebasing:

Gherkin
Feature: Custom rebase

Scenario: Custom rebase filename
* text onRebaseFn =
"""
function(config, downloadLatestFn) {
var timestamp = new Date().toISOString().replace(/:/g, '-');
downloadLatestFn('baseline-' + timestamp + '.png');
return 'Baseline saved with timestamp: ' + timestamp;
}
"""
* configure imageComparison = { onShowRebase: '#(onRebaseFn)' }
* compareImage { baseline: 'base.png', latest: 'current.png' }

karate.compareImage()

For programmatic control, use the JavaScript API:

Gherkin
Feature: Programmatic comparison

Scenario: Using karate.compareImage()
* def baseline = karate.readAsBytes('classpath:screenshots/login.png')
* def latest = screenshot(false)
* def result = karate.compareImage(baseline, latest)
* print 'Mismatch percentage:', result.mismatchPercentage
* print 'Engine used:', result.engine
* if (result.isMismatch) karate.fail('Images differ by ' + result.mismatchPercentage + '%')

Scenario: With options
* def options = { ignoreColors: true, failureThreshold: 5 }
* def result = karate.compareImage(baseline, latest, options)
* match result.isMismatch == false

The result object contains:

PropertyDescription
baselineBaseline image bytes
latestLatest image bytes
mismatchPercentagePercentage of differing pixels
engineEngine used for comparison
failureThresholdConfigured threshold
isMismatchtrue if mismatch exceeds threshold
isBaselineMissingtrue if baseline file not found
isScaleMismatchtrue if dimensions differ
errorError message if comparison failed

karate.embed()

Embed images or other content into HTML reports:

Gherkin
Feature: Embedding content

Scenario: Embed screenshot in report
* def bytes = screenshot(false)
* karate.embed(bytes, 'image/png')

Scenario: Embed with custom label
* def bytes = karate.readAsBytes('classpath:test-image.png')
* karate.embed(bytes, 'image/png')

This is useful for adding custom screenshots or images to reports outside of compareImage.

Screenshot Integration

Combine with UI testing for visual regression:

Gherkin
Feature: Visual regression with screenshots

Background:
* configure driver = { type: 'chrome' }
* configure imageComparison = { failureThreshold: 1, hideUiOnSuccess: true }

Scenario: Compare page screenshot
* driver 'https://httpbin.org'
* def current = screenshot(false)
* compareImage { baseline: 'classpath:baselines/httpbin.png', latest: '#(current)' }

Scenario: Compare element screenshot
* driver 'https://httpbin.org'
* def element = locate('h2')
* def current = element.screenshot()
* compareImage { baseline: 'classpath:baselines/header.png', latest: '#(current)' }
Screenshot Methods
  • screenshot() - Captures viewport and auto-embeds in report
  • screenshot(false) - Captures viewport, returns bytes without embedding
  • element.screenshot() - Captures specific element only

Troubleshooting

Images Won't Match

Problem: Images differ unexpectedly

Solutions:

  • Check image dimensions match (or enable allowScaling: true)
  • Increase failureThreshold for minor differences
  • Use ignoredBoxes for dynamic content areas
  • Try SSIM engine instead of Resemble
  • Check HTML report diff to identify specific differences

Performance Issues

Problem: Image comparison slows down tests

Solutions:

  • Enable hideUiOnSuccess: true to reduce report size
  • Compare specific elements instead of full page
  • Reduce image resolution before comparison
  • Run visual tests separately from functional tests

Baseline Maintenance

Problem: Baselines outdated after UI changes

Solutions:

  • Set mismatchShouldPass: true temporarily while updating
  • Use Rebase button in HTML report to download new baselines
  • Organize baselines by feature/page for easier maintenance
  • Version control baseline images with tests

Missing Baseline

Problem: Baseline file not found

Solutions:

  • Check path prefix is correct (classpath:, file:, this:)
  • Verify file exists in expected location
  • Use karate.readAsBytes() to debug file loading
  • Check result.isBaselineMissing when using karate.compareImage()

Resources

Next Steps