Visual Regression Quickstart

How to Set Up Visual Regression Testing in Playwright

In about ten minutes you will have a real Playwright visual regression test running locally, a baseline committed to git, and a CI job that fails on unexpected pixel drift.

Before you start

  • Node.js 20 or newer installed
  • A local dev server (Next.js, Vite, Astro, anything)
  • A git repo where you can commit baseline images
  • Basic familiarity with running npm scripts

Step 1

Install Playwright

Playwright ships its own visual comparison engine. You do not need a separate diffing library, a cloud dashboard, or any of the $7.5K/mo vendor wrappers that market themselves as visual testing platforms. One install, three browsers, zero external services.

install

Step 2

Write your first toHaveScreenshot assertion

Visual regression testing works by capturing a reference image (the baseline) and comparing every future run against it. ThetoHaveScreenshotmatcher is the one line that does the whole thing.

tests/homepage.spec.ts

maxDiffPixelRatio: 0.01 allows up to 1% of pixels to differ before the test fails. That tolerance absorbs font antialiasing differences between machines without masking real regressions.

Step 3

Generate and commit the baseline

The first run has no baseline to compare against, so Playwright creates one and marks the test as failed on purpose. That failure is the signal to review the image, commit it, and move on.

first run

Baselines live in a sibling folder named <spec>-snapshots/. Commit them. They are source of truth, just like your tests.

Step 4

Trigger a regression on purpose

Before you trust the test, prove it actually catches something. Change a button color or a heading size, rerun, and confirm the test fails with a diff image.

regression

Open the diff image. Playwright highlights every changed pixel in magenta, which makes it obvious whether the diff is a real regression or flakiness from a dynamic element you forgot to mask.

Skip the boilerplate

Assrt generates the full Playwright visual regression suite from one sentence, commits real TypeScript code to your repo, and masks dynamic regions automatically. Open source, zero vendor lock-in, your tests stay yours.

Get Started

Step 5

Mask dynamic regions

The number one cause of flaky visual tests is content that legitimately changes between runs: timestamps, animated hero elements, third party ads, live counters. Mask them at capture time instead of tweaking diff thresholds until false positives disappear.

tests/homepage.spec.ts

animations: "disabled" freezes CSS animations at their final state. Combined with masks, this is usually enough to drop flakiness to zero without touching the pixel ratio at all.

Step 6

Update baselines intentionally

When a UI change is intentional, do not hand edit the PNG or bump the tolerance. Regenerate the baseline with the update flag, eyeball the diff in git, then commit.

update baseline

Treat every baseline update as a code review step. A regenerated baseline that nobody looked at is functionally identical to no test at all.

Step 7

Wire it into CI

Local machines and CI runners render text slightly differently, which is why most teams generate baselines inside Docker and pin Playwright to one version. The official Playwright image uses the same Chromium build as CI, so baselines captured in it match what GitHub Actions sees.

.github/workflows/visual.yml

When the job fails, download the artifact and open index.html. Playwright serves the actual, expected, and diff images side by side, so reviewers can approve or reject without pulling the branch locally.

What to do next

You now have one page covered. The real value shows up at 20 or 200 pages. Scaling by hand means writing a spec per route, picking selectors to mask, tuning thresholds, and keeping baselines in sync. Assrt does that scaffolding for you, generates real Playwright TypeScript (not proprietary YAML), and commits the output into your repo. The tests are yours to keep, fork, and run without a cloud dependency.

Related Guides