Open-source project
jest-community/snapshot-diff avatar
jest-community/snapshot-diff

snapshot-diff: a diff you can snapshot in Jest

Diffing snapshot utility for Jest

604 stars23 forksJavaScriptMIT

At a glance

What is it?
snapshot-diff takes two values and returns their difference as a string, so a Jest snapshot records the change between two states instead of two separate snapshots that both have to be read and mentally subtracted. The library ships a default matcher, a custom matcher, pluggable serializers and a snapshot serializer that removes the extra quotes Jest adds around strings, and its last published release is from 2022.
Who is it for?
Adopt snapshot-diff if your Jest suite snapshots React component states and you want a single artefact that shows what changed between two of them, since reading two large snapshots side by side is exactly the pain the library removes.
Can I use it commercially?
Yes. MIT 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 2 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 October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Snapshot the difference, not the two states

The idea is one line: snapshot-diff takes two values and returns their difference as a string, ready to be snapshotted with toMatchSnapshot(). The README says it is especially helpful when testing the difference between different React component states.

That last clause is the reason the library exists. The usual approach is to snapshot each state separately, which gives you two large blobs whose difference you have to work out by eye, and the failure message when they diverge is two mismatched snapshots rather than a line that says what changed.

With snapshot-diff there is one artefact, and it looks like this:

diff
exports[`snapshot difference between 2 strings 1`] = `
"- First value
+ Second value


-  abcx
+  abcy
   "
`;

The minus lines come from the first value and the plus lines from the second, with the annotation saying which is which. When the test fails, the snapshot output tells you the specific text that changed, which is the thing a human actually wants to read.

The React variant produces a proper patch hunk in the middle of the same format, so the snapshot shows the changed element in the context of the surrounding markup:

diff
exports[`snapshot difference between 2 React components state 1`] = `
"- <Component test=\\"say\\" />
+ <Component test=\\"my name\\" />

@@ -27,11 +27,11 @@
   <span />
   <span />
   <span />
   <span />
   <span>
-    say
+    my name
   </span>
   <span />
   <span />
   <span />
   <span />"
`;

The library is published on npm as snapshot-diff, under the MIT licence, and the repository is now hosted by the jest-community organisation, though the package metadata still points its repository field at the original thymikee/snapshot-diff.

Two ways to call it, and where to put them

There are two calling conventions, and the difference is whether you want the diff as a value or as an assertion.

The default form uses the plain Jest matcher. You require the package, call snapshotDiff with the two values, and pass the result to toMatchSnapshot():

js
const snapshotDiff = require('snapshot-diff');

test('snapshot difference between 2 strings', () => {
  expect(snapshotDiff(a, b)).toMatchSnapshot();
});

const React = require('react');
const Component = require('./Component');

test('snapshot difference between 2 React components state', () => {
  expect(
    snapshotDiff(<Component test="say" />, <Component test="my name" />)
  ).toMatchSnapshot();
});

The custom matcher form registers an extra matcher named toMatchDiffSnapshot and then reads more naturally, with the expected value second:

js
const { toMatchDiffSnapshot } = require('snapshot-diff');

expect.extend({ toMatchDiffSnapshot });

test('snapshot difference between 2 strings', () => {
  expect(a).toMatchDiffSnapshot(b);
});

const React = require('react');
const Component = require('./Component');

test('snapshot difference between 2 React components state', () => {
  expect(<Component test="say" />).toMatchDiffSnapshot(
    <Component test="my name" />
  );
});

The catch with the custom matcher is that someone has to call expect.extend. The README points at the alternative of importing it once in the tests setup file, and the package ships extend-expect.js at the repository root for exactly that:

js
require('snapshot-diff/extend-expect');

In a Jest configuration that file goes into setupFilesAfterEnv, and doing it there is the difference between a matcher that works in one test file and a matcher that works in the whole suite.

Serializers decide what actually gets diffed

Underneath, snapshot-diff works on serialized text, and the serializer is what decides what that text looks like. This is the part that decides whether the library is useful for your data.

By default it uses a built in React serializer based on react-test-renderer, and the serializers can be changed by calling setSerializers with an array. The README is precise about the semantics: the order of the serializers in that array may be important, because serializers are tested in order until a match is found.

That ordering detail has a practical consequence. If you add a serializer for a data type the default does not handle, you have to keep the default React serializer in your list, and the README says so in as many words: if you want to keep the default React serializer in place, do not forget to add the default serializers to your list of serializers.

The idiom for that is to spread the defaults:

js
const snapshotDiff = require('snapshot-diff');
const myCustomSerializer = require('./my-custom-serializer');

snapshotDiff.setSerializers([
  ...snapshotDiff.defaultSerializers, // use default React serializer - add this if you want to serialise React components!
  myCustomSerializer
]);

If you would rather use a different React serializer, you omit the default instead. The README shows the enzyme-to-json serializer taking its place:

js
const snapshotDiff = require('snapshot-diff');
const enzymeToJson = require('enzyme-to-json/serializer');
const myCustomSerializer = require('./my-custom-serializer');

snapshotDiff.setSerializers([
  enzymeToJson, // using enzymes serializer instead
  myCustomSerializer
]);

So the library is not React only. It is a diffing tool that happens to ship with a React serializer as its default, and the setSerializers hook is what makes it usable for plain objects, arrays or your own domain types.

The snapshot serializer that stops Jest quoting your strings

There is a second, separate mechanism in the package, and it addresses a different problem. By default Jest adds extra quotes around strings, which makes diff snapshots of objects too noisy. The package ships a custom snapshot serializer that removes them, and you can add it directly in your tests or in a setupFiles script:

js
const snapshotDiff = require('snapshot-diff');

expect.addSnapshotSerializer(snapshotDiff.getSnapshotDiffSerializer());

test('snapshot difference between 2 objects', () => {
  expect(snapshotDiff({ foo: 'bar' }, { foo: 'baz' })).toMatchSnapshot();
});

Or you can register it globally in the Jest configuration, which is the better place for it since it changes how every snapshot in the project is rendered:

js
// jest.config.js
module.exports = {
  snapshotSerializers: [
    require.resolve('snapshot-diff/serializer.js'),
  ],
};

Note that this is a Jest snapshot serializer, the mechanism Jest uses to decide how a value is rendered inside a snapshot file, and it is distinct from the serializers that snapshot-diff uses internally to produce the diff. The first controls how your snapshot file looks, the second controls what text is being compared. The repository layout reflects the split, with a top level serializer.js file for the Jest side and extend-expect.js for the matcher side.

The README does not discuss when to use one rather than the other, and the practical answer is that you want the Jest serializer when your snapshots are noisy with quotes, and the internal serializers when the content of the diff is wrong rather than its formatting.

The Options type does not list every documented option

The API section gives the shape of the call:

js
type Options = {
  expand?: boolean,
  colors?: boolean,
  contextLines?: number
};

// default export
snapshotDiff(valueA: any, valueB: any, options?: Options) => string
// custom matcher
expect(valueA: any).toMatchDiffSnapshot(valueB: any, options?: Options, testName?: string) => void

The options list below it is longer than the type. expand, defaulting to false, expands the diff so the whole information is preserved. colors, also defaulting to false, preserves color information from the Jest diff. contextLines, defaulting to 5, is the number of context lines shown at the beginning and at the end of a snapshot.

Then there are three more that the type does not mention: stablePatchmarks, defaulting to false, prevents line number patch marks from appearing in diffs, which the README notes can be helpful when diffs are breaking only because of the patch marks, and changes a hunk header such as @@ -1,1 +1,2 @@ to @@ --- --- @@. And aAnnotation, defaulting to 'First Value', and bAnnotation, defaulting to 'Second Value', set the annotations that mark which side of the diff a line came from.

So the TypeScript type in the README is narrower than the option set the same document describes. The repository does ship a type definition, index.d.ts, and the package manifest points typings at it, so the real question is whether that file lists the three extra options. If it does not, TypeScript users will need a cast to set them, which is a small thing to know before you start using stablePatchmarks in a project with strict types.

The stablePatchmarks option deserves a mention on its own. It exists because snapshot diffs are brittle in a specific way: a change near the top of a file shifts every line number below it, so an unrelated change can break a snapshot that differs only in its hunk headers. Turning the headers into a stable form removes that class of noise.

A project that moved organisations, with a release from 2022

The maintenance picture needs stating precisely, because the two signals point in different directions.

The published releases are v0.10.0 from 2022-09-05, v0.9.0 from 2021-06-17 and v0.8.1 from 2020-06-28. So the npm version has not moved in roughly four years. The repository, however, is not archived and the last push was on 2026-10-20, so commits are still landing even though no new version has been published from them.

There is a structural reason to read that gap carefully. The package depends on jest-diff, jest-snapshot and pretty-format, all at the 29 line, and declares jest itself as a peer dependency of 16 or later. Jest moves quickly, and a diffing library built against a particular version of the diff and format packages can produce output that no longer matches what the installed Jest writes into the snapshot file. The practical symptom would be snapshots that fail to match for reasons unrelated to your code.

The build is Babel, with the manifest scripting babel src --out-dir build, and the tooling around it is Flow rather than TypeScript for the source, with a flow check script and a flow-typed directory, while the published type definition is a hand written index.d.ts. The test suite is Jest itself, run against a __tests__ directory, and the repository carries an eslint configuration, a prettier configuration and a babel config.

For a package this small and this focused, the sensible adoption is to pin the version, run it against the Jest version you already have, and treat it as a vendored convenience rather than as a dependency that will follow your Jest upgrades.

Editorial conclusion

Adopt snapshot-diff if your Jest suite snapshots React component states and you want a single artefact that shows what changed between two of them, since reading two large snapshots side by side is exactly the pain the library removes. Do not adopt it for plain scalar comparisons, where a direct equality assertion is clearer and cheaper, and do not expect new features, because the last published release is v0.10.0 from 2022-09-05 even though the repository is still receiving commits. Verify first that the version of jest-diff, jest-snapshot and pretty-format your project resolves matches what snapshot-diff expects, since it declares them as peer style dependencies in the 29 line, and check the Options type against the documented option list, because the type in the README omits several options the same document describes.

Frequently asked questions

What does snapshot-diff do?

It takes two values and returns their difference as a string, ready to be snapshotted with toMatchSnapshot(). The README says it is especially helpful when testing the difference between different React component states, because one snapshot shows the change instead of two snapshots you have to compare by eye.

How do I install snapshot-diff?

Add it as a development dependency with yarn add --dev snapshot-diff. The package declares Node 14 or later as the engine requirement and Jest 16 or later as a peer dependency, with jest-diff, jest-snapshot and pretty-format in the 29 line as runtime dependencies.

How do I use the toMatchDiffSnapshot matcher?

Import toMatchDiffSnapshot from the package and register it with expect.extend, or import snapshot-diff/extend-expect once in your Jest setupFilesAfterEnv file. Then call expect(valueA).toMatchDiffSnapshot(valueB).

Can snapshot-diff diff something other than React components?

Yes. By default it uses a React serializer based on react-test-renderer, but setSerializers takes an array of serializers that are tried in order until a match is found, so you can add one for another data type. If you replace the React serializer, the README notes the order of the list matters.

What is the purpose of the snapshot serializer in snapshot-diff?

By default Jest adds extra quotes around strings, which makes diff snapshots of objects noisy. The package ships a snapshot serializer, getSnapshotDiffSerializer(), that you can add with expect.addSnapshotSerializer in a test or globally through the snapshotSerializers array in your jest.config.js.

Official sources

  1. Issues
  2. jest-community/snapshot-diff on GitHub
  3. License: MIT
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jest-community-snapshot-diff.svg)](https://hysenlabs.com/projects/jest-community-snapshot-diff)

Was this useful?