jest-image-snapshot: pixel-level visual regression testing inside Jest
✨ Jest matcher for image comparisons. Most commonly used for visual regression testing.
At a glance
- What is it?
- A Jest matcher that stores PNG baselines and compares later runs with pixelmatch or SSIM. It fits teams already running Jest and Playwright or Puppeteer screenshots, and it assumes you have somewhere to store baseline images.
- Who is it for?
- Adopt jest-image-snapshot if your test suite already runs under Jest and you can produce PNG buffers from a real browser or renderer. Do not adopt it if you need element-level DOM assertions, cross-browser coverage, or a hosted diff dashboard; it is a matcher, not a visual testing platform.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 57 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem jest-image-snapshot solves
Jest snapshots serialize values to text. That works for component trees and API payloads, and it fails the moment the thing you care about is what the page looks like. A CSS change that shifts a card by four pixels produces no text difference at all, so a standard Jest snapshot passes while the layout is visibly broken.
jest-image-snapshot closes that gap by extending Jest's expect with a matcher that takes a Buffer of PNG image data. The README describes the intended workflow: the first run writes a baseline image, later runs compare against it, and a mismatch fails the test with a diff image you can open. The audience is teams that already run Jest and already produce screenshots, typically through a browser automation tool. If you are not producing PNG buffers from something, this package has nothing to compare.
How the matcher stores and compares baselines
The mechanism is deliberately close to Jest's own snapshot system. On the first run, toMatchImageSnapshot() creates a __image_snapshots__ directory next to the test file and writes the baseline PNG there. The README notes that a customSnapshotsDir option overrides that location. On later runs the matcher loads the stored image and compares it against the buffer you passed in.
The comparison engine is selectable. comparisonMethod defaults to pixelmatch, which does a pixel by pixel comparison; the alternative is ssim, described in the README as a structural similarity comparison and as an experimental feature that may become the default in the future. Both accept a customDiffConfig object. For pixelmatch the default threshold is 0.01, and the README is explicit that this is per pixel sensitivity: at a threshold of 0, a white source pixel compared against #fcfcfc fails, while at 0.5 the difference would have to be far more extreme to trigger a failure. That single number decides whether your suite is noisy or blind, and the default is strict.
Failure output is configurable too. diffDirection chooses horizontal or vertical layout for the composed diff image, onlyDiff limits what the diff image contains, and storeReceivedOnFailure (default false) keeps the received image separately from the composed diff, which the README suggests is useful when updating baselines from CI. customDiffDir, customReceivedDir and customReceivedPostfix control where those artifacts land. customSnapshotIdentifier accepts either a string or a function that receives testPath, currentTestName, counter and defaultIdentifier and must return an identifier.
Installing it and writing a first failing test
Installation is a single npm command. The README marks Jest >=20 <=29 as a peerDependency and states plainly that the matcher will not work below Jest 20. Note the gap between that range and the repository's own devDependencies, which pin jest and jest-snapshot at ^30.0.5 for the project's self-tests; the peer range in the README is what applies to your project, so check it against your Jest version before you start.
npm i --save-dev jest-image-snapshotNext, extend Jest's expect. This goes in a setup file that runs before your tests, and the README shows it as a plain require plus expect.extend:
const { toMatchImageSnapshot } = require('jest-image-snapshot');
expect.extend({ toMatchImageSnapshot });The matcher is then used like any other Jest assertion. This example comes from the README and assumes a browser object exposing newPage(), goto() and screenshot():
it('renders correctly', async () => {
const page = await browser.newPage();
await page.goto('https://localhost:3000');
const image = await page.screenshot();
expect(image).toMatchImageSnapshot();
});On the first run there is no baseline, so the test writes one into __image_snapshots__ and passes. Change the page, run again, and the assertion fails with a diff image. To accept the new rendering, run Jest with --updateSnapshot or -u, exactly as you would for a text snapshot. The repository ships an examples/ directory with a jest-setup.js and an image-reporter.js if you want a worked reference rather than a minimal one.
Where the pixel comparison breaks down
The failure mode that bites hardest is environmental drift, and the README does not address it. A baseline captured on a developer's laptop and replayed on a CI runner will differ if fonts, antialiasing, GPU rendering or device pixel ratio differ between the two. Nothing in the matcher distinguishes a real regression from a rendering environment change; both arrive as a failed pixel comparison. Teams that adopt this end up pinning the browser version and often running the tests in a container that matches CI, which is work the package does not do for you.
The options that exist for softening this are blunt. Raising the pixelmatch threshold makes the test tolerate more difference everywhere, including the differences you wanted to catch. The README lists Gaussian blur as a feature for noise, which helps with minor antialiasing variation but also blurs real edges. storeReceivedOnFailure defaults to false, so unless you turn it on you get the composed diff image and not the raw received image, which is the artifact you actually want when you are deciding whether to update a baseline from CI.
The second limitation is architectural. This is a Jest matcher. The related searches around Vitest reflect a real question, but the package's documented peer dependency is Jest, and the README describes extending Jest's expect. If your suite runs on a different runner, the matcher is not the thing you install. And if what you need is to assert that a specific element has specific computed styles, you want a DOM assertion library, not a screenshot diff; a pixel comparison will tell you something changed but not which property caused it.
jest-image-snapshot compared with hosted visual testing services
The obvious alternative is a hosted visual regression service, and the difference is not feature count but where the baseline lives and who reviews the diff. With jest-image-snapshot the baseline is a PNG committed to your repository, the diff is a file on disk, and the approval step is running jest -u and committing the result. Review happens in a pull request alongside the code change.
A hosted service moves the baseline to its own storage, runs the comparison on its own infrastructure, and presents diffs in a web UI where a reviewer clicks to accept. That model solves the environment drift problem by controlling the rendering environment, and it gives non-engineers a way to approve visual changes. It also introduces a network dependency, an account, and a per-snapshot cost structure, and the baselines stop being part of your git history.
The trade-off is legibility versus control. Committed PNG baselines are reviewable in a diff, survive the vendor disappearing, and cost nothing per comparison. They also bloat the repository over time and give you no help when the baseline itself was captured in the wrong environment. For a small suite on a stable CI image, the matcher is the simpler choice. Past a few hundred screenshots, the manual approval loop in pull requests becomes the bottleneck.
Licence, maintenance and upgrade cost
The package is Apache-2.0, stated in both the README badge area and the LICENSE.txt file at the repository root. Apache-2.0 includes an express patent grant, which is a meaningful difference from MIT for corporate adoption reviews, though the practical obligations (retain notices, state changes) are similar. This is a description of the licence text, not legal advice; route it through whoever handles open source approval at your organisation.
Maintenance signals are mixed but readable. The repository is not archived, and the last push was on 2026-08-05. The most recent release listed is v6.5.2 on 2026-03-09, following v6.5.1 on 2025-05-20 and v6.5.0 on 2025-05-12. So there is commit activity after the last tagged release. The README also carries a hiring notice pointing contributors to a recruiting address, which tells you the project is sponsored rather than a solo side project.
Upgrade cost concentrates in the peer dependency. The README pins Jest >=20 <=29 while the project's own devDependencies use jest ^30.0.5, so a Jest major upgrade is the moment to check whether the peer range has moved. The engines field requires Node ^14.15.0 || ^16.10.0 || >=18.0.0, which means Node 15, 17 and anything below 14.15 are excluded. Committed baseline images are the other recurring cost: every accepted visual change adds or rewrites binary files in git, and those do not compress or diff usefully.
Editorial conclusion
Adopt jest-image-snapshot if your test suite already runs under Jest and you can produce PNG buffers from a real browser or renderer. Do not adopt it if you need element-level DOM assertions, cross-browser coverage, or a hosted diff dashboard; it is a matcher, not a visual testing platform. Before committing, verify that your baseline images render identically on the machine that will run CI, because a different font stack or device pixel ratio will fail every snapshot on the first run.
Frequently asked questions
What is a snapshot image in jest-image-snapshot?
It is the baseline PNG the matcher writes on the first run. Given a Buffer of PNG image data, toMatchImageSnapshot() stores that image in the __image_snapshots__ directory next to the test file and compares later runs against it.
How do I update a jest-image-snapshot baseline?
Run Jest with the --updateSnapshot or -u argument. The README states that this works exactly the same way as updating standard Jest snapshots, and it rewrites the stored baseline image rather than the received one.
Is there a difference between a snapshot and a screenshot in jest-image-snapshot?
In this package the snapshot is a PNG baseline file stored in __image_snapshots__, and the screenshot is the buffer your test produces from the page. The matcher writes that buffer as the baseline on the first run and compares against it afterwards.
What is Jest used for in testing with jest-image-snapshot?
Jest runs the test and provides the expect function that the matcher extends. jest-image-snapshot adds toMatchImageSnapshot() to that expect, so image comparisons run inside the same test suite and the same --updateSnapshot workflow as text snapshots.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/americanexpress-jest-image-snapshot)