Vitest visual regression testing
Turn your Vitest browser-mode component tests into visual regression tests: capture a DOM archive of each render and diff it on every pull request. No Storybook.
You do not need Storybook to visually test your components. If you already run component tests in Vitest browser mode, @uiverify/vitest records a DOM archive of each rendered test, and UI Verify replays and screenshots that archive deterministically. It is the same archive-replay engine our Playwright integration uses, and it matches Chromatic's Vitest integration.
1. Get a project API key
Sign up at uiverify.ai, create a Vitest project, and store its API key in CI as UIVERIFY_API_KEY.
2. Add the capture plugin
Install the SDK and add uiverifyPlugin() to your vitest.config.ts. Your tests must run in Vitest 4 browser mode on the Playwright provider (@vitest/browser-playwright) with Chromium - that is where the real DOM to capture exists. Every browser-mode test then archives its final DOM; add named mid-test checkpoints with takeSnapshot().
npm i -D @uiverify/vitest @vitest/browser-playwrightimport { 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" }] },
},
});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 () => {
render(<Menu />);
await takeSnapshot("closed"); // optional named checkpoint
// final state is auto-archived at test end
});3. Run your tests and upload the archive
Run your Vitest suite as usual. Each test writes what it rendered into ./uiverify-archive; then upload that directory. playwright install --with-deps downloads the browsers Vitest browser mode drives.
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@latest upload --static-dir ./uiverify-archive4. Install the GitHub App
Install the GitHub App from your project settings and point it at your repo, so UI Verify can post a check and a comment on each pull request. Uploads still work without it, but nothing shows up on GitHub.
5. Wire it into CI
name: UI Verify
on: pull_request
jobs:
visual:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history so the baseline can be resolved
- run: npm ci
- run: npx playwright install --with-deps
- run: npx vitest run
- run: npx -y uiverify@latest upload --static-dir ./uiverify-archive
env:
UIVERIFY_API_KEY: ${{ secrets.UIVERIFY_API_KEY }}npx playwright install --with-deps is required on a clean runner: Vitest browser mode drives Playwright's Chromium, so without the browsers the test run fails before it captures anything. And keep fetch-depth: 0 so the baseline resolves against your real branch history.Why archive-replay instead of a live screenshot?
A screenshot of a live component flakes on anything non-deterministic - a clock, live data, a feature flag, an animation caught mid-frame. Archive-replay bakes the DOM into a static archive at test time, then replays it identically on every run, so a diff means a real change and not a coincidence of timing. See Fix flaky visual tests.
Visual testing for agents
UI Verify captures your UI on every pull request and an AI judge tells an intended change from a real regression. See how it works.
Get started