4 min readplaywrightvisual-testingsdkclistudioplatformannouncement

Visual Regression Testing: From a Pixel Diff to the Element That Caused It

TestRelic Team

A failing screenshot comparison can tell you that 80,858 pixels changed. It can't tell you that one card gained a 24px margin and pushed everything below it down the page. TestRelic now covers visual regression testing end to end around that gap: in the Playwright reporter, the CLI, Studio and the cloud.

Your existing screenshot tests, in the report

If your suite already uses toHaveScreenshot() or toMatchSnapshot(), there's nothing to rewrite. Upgrade @testrelic/playwright-analytics and every comparison shows up in the report: baseline, actual and diff side by side, a wipe slider, an onion-skin blend, or Playwright's own diff image, with the differing-pixel count and ratio.

TestRelic doesn't compare images itself. Playwright already ships the comparator, so the reporter reads the comparison Playwright made, and nothing new lands in your dependency tree.

Native Playwright has one blind spot: toHaveScreenshot attaches nothing when the images match, so a passing visual check is invisible to any reporter. The new toMatchVisualBaseline matcher runs the same comparator with the same options, and also records the baseline it passed against:

import { test, expect } from '@testrelic/playwright-analytics/fixture';

test('release health dashboard', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page).toMatchVisualBaseline('release-health-dashboard');
});

Naming the element, not just the pixels

With expect imported from the TestRelic fixture, both matchers capture a DOM snapshot before the screenshot: element geometry, a curated set of computed styles, visible text and identity attributes. That snapshot is diffed against a committed baseline, and the report lists what changed as seven kinds of change: added, removed, moved, resized, restyled, text and attrs. Hover a row in the Elements tab and that element's box is drawn over the screenshot, so the change and the pixels it caused are connected.

Knock-on movement is kept apart from the edit that caused it. When one card gains a margin, the ten elements below it that only moved are grouped under that card rather than reported as eleven equal findings.

DOM baselines are text, a <name>.dom.json beside each image baseline, so a restyle arrives in code review as margin-top: 24px instead of an opaque binary change. --update-snapshots rewrites both files together, and the mask option you already pass excludes regions from the DOM comparison as well as the pixel one. The DOM comparison needs Playwright 1.51 or later; everything else in the reporter runs on 1.35.

Verdicts that say what happened

A first run of a visual suite has nothing to compare against, so Playwright writes the baselines and fails the tests. The report now says exactly that: a first write is new, a rewrite under --update-snapshots is updated, and a match is passed, one record per assertion.

Each comparison also records where its committed baseline file lives. That's what makes the next step possible.

Accept or reject, wherever you saw it

When a visual change is intended, the baseline has to move. When it isn't, someone should say so on the record. TestRelic handles both on every surface, and every surface writes to the same ledger.

In the terminal, tr visual lists the comparisons in the report your last Playwright run wrote. tr visual accept copies this run's render over the committed baseline file that Playwright reads next time, and touches nothing else. tr visual reject changes no files. Both record the decision, with an optional --note, and sync it to TestRelic Cloud when the run was uploaded there.

tr visual                        # every comparison in the last report
tr visual show drift-target      # one comparison in full
tr visual accept drift-target --note "the accent card restyle is intended"
tr visual reject structural-swap

In Studio, a Visual tab sits in the cloud test stack beside Steps, Console and Network: baseline against this run, the element list with the changed element's box drawn over the render, and Accept and Reject buttons.

In the cloud, every Playwright session has a Visual tab, most-changed comparison first, and a standalone Visual Regression workspace triages a whole session's comparisons at once. Each decision is stored with who made it and why, so the CLI, Studio and the web all show the same answer.

Anything that can't be decided (a pass, a baseline that was only just written, a size mismatch) is refused on every surface, with the reason, rather than offered as a button that would fail.

Get started

  1. Upgrade the reporter to the latest version: npm install -D @testrelic/playwright-analytics@latest. Accepting a baseline needs 2.16.2 or later.
  2. Run your suite. Existing screenshot comparisons appear in the report straight away. Import expect from @testrelic/playwright-analytics/fixture to add the DOM comparison, and use toMatchVisualBaseline to record passes too.
  3. Review where you work: tr visual in the terminal, the Visual tab in Studio, or the session's Visual tab in the cloud.

The report and the DOM comparison are part of the free SDK. The cloud needs a paid plan, the CLI needs Growth or above and Studio needs Pro or above, and a 14-day trial unlocks both; see Plans & Billing.