npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vitest-image-snapshot

v0.6.46

Published

Visual regression testing for images. Compare rendered outputs against reference images to catch visual bugs.

Readme

Image Snapshot Testing

Visual regression testing for images. Compare rendered outputs against reference images to catch visual bugs.

  • Native vitest integratio
  • Accepts ImageData or PNG buffers - test WebGPU, Canvas, or any image processing
  • Aggregated HTML diff report for visual failures

Setup

1. Install

pnpm install --save-dev vitest-image-snapshot

2. Import in your test file

import { imageMatcher } from "vitest-image-snapshot";

imageMatcher(); // Call once at the top level

3. (Optional) Configure HTML diff report

Configure the reporter in vitest.config.ts:

import { defineConfig } from 'vitest/config'
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'

const __dirname = dirname(fileURLToPath(import.meta.url))

export default defineConfig({
  test: {
    include: ['src/test/**/*.test.ts'],
    reporters: [
      'default',
      ['vitest-image-snapshot/reporter', {
        reportPath: join(__dirname, '__image_diff_report__'),  // Absolute path recommended for monorepos
        autoOpen: 'failures',  // Auto-open report in browser on failures (or 'always' to always open or 'never')
      }]
    ],
  },
})

Default behavior (no configuration):

  • Report location: {vitest.config.root}/__image_diff_report__/index.html
  • Auto-open: failures (can override with IMAGE_DIFF_AUTO_OPEN=always or IMAGE_DIFF_AUTO_OPEN=never env var)

Configuration options:

  • reportPath: Absolute or relative to config.root (default: '__image_diff_report__')
  • autoOpen: Auto-open report in browser on failures, always or never (default: 'failures' or 'never' on CI)
  • port: Port for html report server (default: 4343)

Basic Usage

Accepts standard browser ImageData or Buffer (pre-encoded PNGs):

// With ImageData (from canvas, shader tests, etc.)
await expect(imageData).toMatchImage("snapshot-name");

// With Buffer (pre-encoded PNG)
await expect(pngBuffer).toMatchImage("snapshot-name");

// Auto-generated name from test name (single snapshot per test only)
await expect(imageData).toMatchImage();

Options

await expect(imageData).toMatchImage({
  name: "edge-detection",
  threshold: 0.2,  // Allow more color variation
});

See Match Options for all available configuration options.

Updating Snapshots

When you intentionally change shader behavior:

# Update all snapshots
pnpm vitest -- -u

# Update specific test file
pnpm vitest ImageSnapshot.test.ts -- -u

Diff Report

If you added ImageSnapshotReporter to vitest.config.ts, failed tests generate a self-contained HTML report with:

  • Expected vs Actual side-by-side
  • Diff visualization (mismatched pixels highlighted)
  • Mismatch statistics
  • All images copied to report directory (portable and shareable)

Default location: {vitest.config.root}/__image_diff_report__/index.html

Monorepo behavior: In workspace mode (running tests from workspace root), each package's report goes to its own directory when using absolute paths in config.

Auto-open on failure:

IMAGE_DIFF_AUTO_OPEN=failures pnpm vitest

# Always auto-open
IMAGE_DIFF_AUTO_OPEN=always pnpm vitest

Or enable via inline reporter config:

reporters: [
  'default',
  ['vitest-image-snapshot/reporter', { autoOpen: 'failures' /* or 'always' or 'never' */ }]
]

IMAGE_DIFF_AUTO_OPEN will override reporter config if both are set.

CI

When a CI environment is detected then IMAGE_DIFF_AUTO_OPEN and config options are ignored and autoOpen is set to "never".

The report is still generated and can be saved as an artifact for review or published to a static hosting service if you prefer.

Directory Structure

package-root/
├── src/test/
│   ├── ImageSnapshot.test.ts
│   ├── __image_snapshots__/       # Reference images (commit to git)
│   │   └── snapshot-name.png
│   ├── __image_actual__/          # Current test outputs (gitignore, always saved)
│   │   └── snapshot-name.png
│   └── __image_diffs__/           # Diff visualizations (gitignore, only on failure)
│       └── snapshot-name.png
└── __image_diff_report__/         # HTML report (gitignore, self-contained)
    ├── index.html
    └── src/test/                  # Copied images preserving directory structure
        ├── __image_snapshots__/
        ├── __image_actual__/
        └── __image_diffs__/

Notes:

  • __image_actual__/ saves on every run (pass or fail) for manual inspection
  • Report copies all images to __image_diff_report__/ preserving directory structure
  • Report is self-contained and portable (can be zipped, shared, or committed)

API Reference

toMatchImage()

Vitest matcher for comparing images against reference snapshots.

await expect(imageData).toMatchImage(nameOrOptions?)

Parameters:

  • imageData: ImageData | Buffer - Image to compare
  • nameOrOptions?: string | MatchImageOptions - Snapshot name or options

Match Options:

interface MatchImageOptions {
  name?: string;                    // Snapshot name (default: auto-generated from test name)
  threshold?: number;               // Color difference threshold 0-1 (default: 0.1)
  allowedPixelRatio?: number;       // Max ratio of pixels allowed to differ 0-1 (default: 0)
  allowedPixels?: number;           // Max absolute pixels allowed to differ (default: 0)
  includeAA?: boolean;              // Disable AA detection if true (default: false)
}

How Comparison Works

Image comparison uses pixelmatch, which converts RGB to YIQ color space for perceptually-weighted comparison. YIQ separates luminance (Y) from chrominance (I, Q), making the comparison more aligned with human perception than raw RGB byte comparison.

The threshold option (0-1) controls sensitivity to color differences in YIQ space.

Color space note: Images are compared as raw RGBA bytes. If using display-p3 (supported in WebGPU via GPUCanvasConfiguration.colorSpace), ensure both reference and actual images use the same color space.

Examples

WebGPU Shaders

import { imageMatcher } from "vitest-image-snapshot";
import { testFragmentImage } from "wgsl-test";

imageMatcher();

test("shader output matches snapshot", async () => {
  const result = await testFragmentImage({
    projectDir: import.meta.url,
    device,
    src: `@fragment fn fs_main() -> @location(0) vec4f { return vec4f(1.0, 0.0, 0.0, 1.0); }`,
    size: [128, 128],
  });

  await expect(result).toMatchImage("red-output");
});

Canvas/DOM ImageData

import { imageMatcher } from "vitest-image-snapshot";

imageMatcher();

test("canvas output matches snapshot", async () => {
  const canvas = document.createElement('canvas');
  canvas.width = 128;
  canvas.height = 128;
  const ctx = canvas.getContext('2d')!;

  // Draw something
  ctx.fillStyle = 'red';
  ctx.fillRect(0, 0, 128, 128);

  const imageData = ctx.getImageData(0, 0, 128, 128);
  await expect(imageData).toMatchImage("red-canvas");
});

Troubleshooting

"No reference snapshot found"

First run: Snapshot created automatically CI: Run with -u locally first, then commit snapshots

Images don't match but look identical

  • threshold too strict - increase tolerance
  • GPU/driver differences - use allowedPixelRatio
  • Anti-aliasing differences - set includeAA: true

Build Version

vitest-image-snapshot is currently part of the wesl-js monorepo. (It'll eventually move to it's own repo).

Contributions

See Implementation.md for details and feature ideas.