Skip to content
Testing

What Is Visual Regression Testing? Screenshots, Baselines, and Diffs

Detect unexpected rendering changes while keeping baseline approval a deliberate design decision.

What Is Visual Regression Testing? Screenshots, Baselines, and Diffs

Key takeaways

  • Visual regression testing compares current rendering with an approved reference image.
  • A difference identifies a change, while review determines whether the change is a defect.
  • Stable data, fonts, browser versions, and capture conditions reduce irrelevant differences.
  • Screenshot checks complement functional and accessibility tests rather than proving those properties.

Visual regression testing compares a new rendering of an interface with an approved reference image, usually a screenshot. It helps detect unintended changes in layout, spacing, typography, colors, and visible content.

Imagine a delivery-address form after a shared stylesheet update. The save operation still works, but a long label overlaps its input at a narrow viewport. A functional test may pass while a screenshot comparison reveals the layout change.

The comparison identifies changed pixels or regions. It does not decide whether the new design is correct; that remains a review decision.

How a Visual Test Works

A typical workflow establishes a known page state, captures it, and compares the image with a baseline.

Known interface state
        |
Capture current screenshot
        |
Compare with approved baseline
        |
Review unexpected differences

The first baseline needs review too. Automatically accepting the first capture can preserve an existing defect as the expected appearance.

Later failures may indicate a regression, an intentional redesign, or an unstable test environment. The comparison artifacts help distinguish those causes.

A Focused Playwright Example

Playwright provides screenshot assertions. This example assumes a running test application with a deterministically seeded account, a named address form, and a status message that signals the form has finished loading.

import { test, expect } from '@playwright/test';

test('address form at narrow width', async ({ page }) => {
  await page.setViewportSize({ width: 390, height: 844 });
  await page.goto('http://localhost:3000/account/address');

  await expect(page.getByRole('status')).toHaveText('Address loaded');
  await page.evaluate(() => document.fonts.ready);

  const form = page.getByRole('form', { name: 'Delivery address' });
  await expect(form).toHaveScreenshot('address-form-narrow.png', {
    animations: 'disabled',
  });
});

The application labels and readiness signal are illustrative. Adapt them to a real state your application exposes.

The screenshot assertion reference documents comparison controls. Here the form is the capture target so unrelated page content does not dominate the diff.

Waiting for fonts and a loaded state addresses specific sources of variation. Neither step guarantees that every image, widget, or asynchronous update is settled.

Visual and Functional Tests Answer Different Questions

QuestionSuitable evidence
Did saving persist the address?Functional assertions and a read-back
Did the field label become clipped?Visual comparison at the relevant width
Can a keyboard user complete the form?Keyboard interaction and accessibility checks
Does the service enforce ownership?Authorization tests
Did a shared spacing rule change several components?Focused component and page screenshots

A screenshot captures appearance at a moment in time. It cannot prove that an invisible permission check works or that the next interaction succeeds.

Likewise, a successful browser action does not establish that every part of the screen looks correct.

Stabilize Inputs Before Adjusting Tolerance

Use predictable names, dates, amounts, and records. Include deliberately difficult fixtures, such as a long address or validation message, rather than relying only on short ideal content.

Keep browser versions, operating-system images, installed fonts, viewport, and relevant rendering settings consistent. Playwright’s visual-comparison guide notes that environmental differences can alter screenshots.

Control animation and volatile content deliberately. Masking a changing advertisement may be appropriate when it is outside the requirement. Masking the address form’s error area would hide behavior the test should examine.

A stable loading spinner is still the wrong state if the test is meant to capture a completed form.

Choose Coverage Around Layout Risks

Component screenshots help isolate shared controls and their states. Page screenshots reveal how those components fit together with navigation, content, and responsive rules.

For the address flow, useful cases might include:

  • A narrow viewport with a long label.
  • Validation errors beside populated fields.
  • A wide layout with the full address visible.
  • A supported alternate theme.

Choose widths around meaningful layout changes and known trouble spots. Every additional browser, viewport, and state adds a baseline to maintain.

Separate references where rendering legitimately differs. One image should not be expected to represent every browser and operating system.

Understand What the Threshold Allows

Comparison tools can distinguish per-pixel color tolerance from the total number or ratio of differing pixels.

Those settings answer different questions. A small color variation across many pixels is different from a missing icon in one region.

Use tolerance to accommodate understood noise. Raising a global threshold until the suite passes may hide a small but important defect, especially in a large page screenshot.

If one region is unstable, investigate that region or narrow the capture. A focused assertion can make a meaningful change more visible.

Review Baseline Updates as Changes to Expectations

When a design change is intentional, inspect the previous image, current image, and diff before replacing the baseline.

Check whether the changed regions match the intended work. A new button style may be expected while an unrelated label shift is not.

Baseline updates should travel with a clear explanation and an owner who can judge the appearance. Bulk replacement after an unexplained failure removes the evidence the test was meant to preserve.

When browser or font upgrades change many images, identify that environmental change explicitly so reviewers can assess the batch coherently.

Make Failures Useful in CI

Retain the baseline, actual capture, and diff where reviewers can inspect them. Record the browser project and environment so a developer can reproduce the comparison.

A visual suite is valuable when a failure leads to a clear decision: fix the interface, correct unstable capture conditions, or approve an intended change.

Start with a few important states and keep their inputs controlled. Expand coverage when the existing comparisons produce useful findings instead of routine noise.

A baseline is an approved expectation, so changing it deserves the same attention as changing an assertion.
Top