Vitest visual regression testing

UI Verify turns the Vitest browser-mode tests you already have into visual regression tests. One plugin archives what each test renders, UI Verify screenshots it in one pinned browser and diffs it against the baseline, and your coding agent sees what its change did to the UI before it opens a pull request. Every pull request is checked again. No Storybook, and no screenshots in your repo.

UI Verify's review screen for a Vitest browser-mode test of a storefront product grid: the baseline, and the pull request with Spotlight dimming everything except the eight add-to-cart buttons that changed.
A Vitest browser-mode test of a storefront grid, reviewed in UI Verify. The pull request restyled the add-to-cart button, 0.71% of the capture's pixels changed, and Spotlight dims everything else so the eight changed buttons are the only thing lit.

What is Vitest visual regression testing?

Vitest visual regression testing compares what a browser-mode component test renders against an approved baseline image, so a change to the pixels shows up as a diff you review. Unit assertions check the logic and never see the UI; a visual test catches the padding, color, font or layout change that every assertion passes straight through.

Vitest is a good place for it. A browser-mode test renders one component, or one page, in isolation with the data you give it, so most of what makes screenshot tests flaky on a live app is gone before you start. With @uiverify/vitest there is no per-test code to write: each test is captured as it ends.

How do you set up visual testing in Vitest?

Your tests need Vitest 4 or 5 in browser mode, on the Playwright provider (@vitest/browser-playwright), with Chromium. Setup takes a few minutes.

1. Install the SDK

Add @uiverify/vitest and Vitest's Playwright provider as dev dependencies.

bash
npm i -D @uiverify/vitest@1.6.0 @vitest/browser-playwright

2. Add the plugin to your Vitest config

uiverifyPlugin() is the whole integration. Every browser-mode test now archives its final DOM, plus the stylesheets, fonts and images that DOM uses.

vitest.config.ts
import { defineConfig } from "vitest/config";
import { playwright } from "@vitest/browser-playwright";
import { uiverifyPlugin } from "@uiverify/vitest/plugin"; 

export default defineConfig({
  plugins: [uiverifyPlugin()], 
  test: {
    browser: { enabled: true, provider: playwright(), instances: [{ browser: "chromium" }] },
  },
});

3. Choose the moment, if you need to

A test with no extra code is captured when it ends. To capture at a moment you choose, or several named states, await your render and call takeSnapshot(). A test that calls it is not captured again at its end.

menu.test.tsx
import { test } from "vitest";
import { render } from "vitest-browser-react"; // or your framework's browser render helper
import { takeSnapshot } from "@uiverify/vitest";

test("menu", async () => {
  await render(<Menu />); // await it so the DOM is committed before capture
  await takeSnapshot("closed");
});

4. Run the tests and upload the archive

Run Vitest as usual, then upload ./uiverify-archive with your project API key. UI Verify replays each test, screenshots it and diffs it against the baseline.

bash
npx playwright install --with-deps   # one-time: browsers for Vitest browser mode
npx vitest run                       # writes ./uiverify-archive
UIVERIFY_API_KEY=your_key npx -y uiverify@1.8.0 upload --static-dir ./uiverify-archive

5. Run it on every pull request

Run the same commands in CI, on pull requests and on your default branch; UI Verify renders only the tests a change affects. Accept the first default-branch build once, or add --auto-accept-changes to that upload, and it becomes the baseline every pull request diffs against. The full GitHub Actions workflow, global CSS and font setup, and whole-page captures are in the Vitest quickstart.

How does UI Verify compare to toMatchScreenshot and Chromatic?

Teams that visual-test Vitest today use Vitest's built-in toMatchScreenshot() assertion or Chromatic's Vitest plugin. All three start from the same browser-mode tests. They differ in where the screenshot is taken, where the baselines live, and who reviews a change.

UI VerifyVitest toMatchScreenshot()Chromatic for Vitest
Where the screenshot is takenUI Verify's cloud, replaying an archive of each test in one pinned browserThe machine running the test, so each OS gets its own baseline (-chromium-darwin, -chromium-linux)Chromatic's cloud, from an archive of each test
Where baselines liveHosted, one per branch, resolved from gitPNG files committed in __screenshots__/Hosted by Chromatic
Updating a baselineAccept in the dashboard or from your agent; merging advances itRe-run with --update and commit the new PNGsAccept in Chromatic's web app
Where you review a changeA check and a comment on the pull request, and the review queueA failing test, with diff images written to diskA check on the pull request, an opt-in pull request comment, and Chromatic's web app
Skipping unchanged testsOn by default: the Vite module graph picks the tests a change affectsNo carry-forward: every test that runs is screenshotted and diffed again (vitest --changed narrows which tests run)TurboSnap, supported for Vitest
Review from a coding agentMCP tools return each diff and accept or reject itThe agent reads the failing test and the PNGs on diskIts MCP server serves component docs, not build review
Intended change or regressionAn optional AI judge labels each change and says whyA pixel thresholdA pixel diff, judged by a reviewer
PriceFree for 10,000 snapshots a month (50,000 for open source); paid plans include more, then per snapshotFree, it runs in your CIPer snapshot, with a free tier
Sources: Vitest visual regression testing guide, Chromatic for Vitest, Chromatic MCP, Chromatic changelog, April 2026, Chromatic pricing, checked 2026-10-17.

Vitest's own guide says why the built-in assertion needs care: rendering differs across operating systems, fonts and GPUs, so it recommends Docker, CI-only runs or a cloud service. Chromatic and UI Verify both take that cloud route. For the full Chromatic comparison, including pricing at your volume, see UI Verify vs Chromatic.

What does UI Verify add to Vitest?

  • Your coding agent checks its own UI work. While it edits, the agent runs the affected Vitest tests, uploads the archive with uiverify check, and reads the diffs over MCP, so it sees what its change did to the UI before it opens a pull request. See Check visual changes mid-edit.
  • Every pull request is checked again. UI Verify posts a check and a comment with the diff on the pull request, and a change waits in the review queue until you, or your agent, accept or reject it.
  • The same pixels on every machine. Every capture is replayed in one fixed environment, so your Mac and the Linux CI runner produce the same screenshot. You still freeze in-app inputs like the clock and live data; the determinism checklist shows how.
  • No screenshots in your repo. Baselines are hosted, one per branch, resolved from git, and every version of a test is kept, so you can see how a component looked build over build. See baselines.
  • Only what changed re-renders. UI Verify re-renders the tests your pull request affects and carries the rest forward at a fifth of the price of a render, so a small change no longer pays for the whole suite. It is on by default; see skip unchanged.
  • Baselines advance when you merge. Nothing to regenerate on the right OS and nothing to commit.
  • Flaky changes stay out of the way. A change that does not reproduce on a re-render is marked flaky instead of turning the pull request red. See automatic flake detection.
  • An AI judge, if you want one. Turn it on and each change is labeled an intended change or a likely regression, with the reason. See the AI judge.

When is toMatchScreenshot or Chromatic the better choice?

toMatchScreenshot() is the right tool for a small suite that only ever runs on one machine, or inside one Docker image everyone renders through. It is free, it needs no service, and it can screenshot in Firefox and WebKit as well as Chromium, where UI Verify renders Vitest captures in Chromium.

Chromatic is a strong choice if your team already uses it for Storybook and wants one tool and one bill, or relies on its designer sign-off workflow and published Storybooks. UI Verify fits when you want your coding agent to review its own UI changes, an AI judge on the pull request, and a lower price per snapshot.

Frequently asked questions

Do I need Storybook for Vitest visual testing?

No. @uiverify/vitest captures your Vitest browser-mode tests directly, and UI Verify renders them without a Storybook build.

Which Vitest versions does UI Verify support?

Vitest 4 and 5, in browser mode, on the Playwright provider (@vitest/browser-playwright) with Chromium. Tests that run in jsdom or happy-dom have no real DOM to capture.

Do I have to call takeSnapshot() in every test?

No. Every browser-mode test is captured when it ends. Call takeSnapshot() to capture at a moment you choose or several named states instead (a test that calls it is not captured again at its end), opt a test out with disableAutoSnapshot(), or scope capture to files like *.visual.test.tsx with Vitest's own include.

Can Vitest visual tests cover whole pages?

Yes. Render the page's component inside the layouts and providers your app wraps it in, give it fixture data instead of a live backend, and the capture shows the page the way users see it. The Vitest quickstart covers whole pages, including Next.js App Router routes.

Why do Vitest visual tests flake?

Usually live data or a capture taken before the component finished rendering, then the clock. UI Verify already holds animations, fonts and randomness still. Flaky Vitest visual tests walks through the fixes.

Why do toMatchScreenshot baselines fail in CI?

Operating systems rasterize text and edges differently, so a baseline made on a Mac does not match a render on a Linux CI runner. Why Vitest screenshot baselines drift in CI shows it and the fixes.

How much does Vitest visual testing with UI Verify cost?

It is free for 10,000 snapshots a month, and 50,000 a month for open-source projects. A snapshot is one capture (a test's end-of-test capture, or each takeSnapshot() call) in one browser at one viewport, and the tests your pull request does not touch are carried forward at a fifth of that price instead of re-rendered. See snapshot billing.

Can my coding agent set it up?

Yes. The Set up visual testing skill wires the plugin and CI, and Deterministic Vitest captures is the determinism checklist it applies. The Vitest quickstart also opens with a prompt you can paste into your agent.

Visual-test your Vitest suite today

Add one plugin, upload once, and your next pull request is checked. Free for 10,000 snapshots a month, 50,000 for open source.