Snapshots and Inline Snapshots

Snapshots and Inline Snapshots in Testing

In this lesson, we will cover how to use snapshots in Jest and Vitest.

Snapshots let you capture the exact structure of an object, and with very little effort you can insert that into your test, and also just as easily update it when there is a change.

There are two main types of snapshots that you can use in Jest and Vitest:

  • Regular Snapshots (snapshots stored in separate files)
  • Inline Snapshots (inline in your test file)

Basically you add expect(someVar).toMatchSnapshot() and when you run Jest or Vitest, it will create a snapshot file on your file system (that you can add to git)

Or, you can use expect(someVar).toMatchInlineSnapshot() and, when you run it for the first time it will update your actual test file by putting a serialised string value inside it.

Snapshots are useful when you need to capture complex objects. They also work when rendering with React Testing Library (you will get the DOM output as the serialised snapshot).

Example:

it('renders correctly', () => {
  const { container } = render(
    <MyComponent />
  );
  expect(container).toMatchSnapshot();
});

When you run it in Jest or Vitest (e.g. with your test script), the first run creates a snapshot in the __snapshots__ directory next to the test file. On subsequent runs, the current serialised value is compared against the stored snapshot.

Inline Snapshots

Inline snapshots are similar to regular snapshots, but the expected output is stored directly in the test file.

Example:

it('generates correct object', () => {
  const result = processData(input);
  expect(
    result
  ).toMatchInlineSnapshot(); // << after first  run this code will be updated by jest/vitest
});

Tips

Use snapshots for complex objects or complex UI components.

Snapshots are also very good as a temporary test during refactors, as you can quickly write some basic checks, do your refactor, and check the output stayed exactly the same.

However, long term snapshots (either type) are brittle and end up being a code smell. You shouldn't default to using snapshots.

They are (especially inline snapshots) very useful if you are writing tests for something that already exists. You can add expect(result).toMatchInlineSnapshot() to quickly debug what the current returned value is.

Snapshots are not suitable (or just won't work) when:

  • values are non-deterministic (for example, timestamps/dates when not using fake system timer)
  • test names are generated (for example, with .each())
  • values are not able to be serialised

Tip: Always aim for small snapshots (sometimes just a subset of an object), or they quickly become hard to maintain. One of the biggest issues is it isn't clear what the test is even meant to be testing, and engineers can be quick to just update a snapshot without understanding why it needs updating.

Updating Snapshots

When your code changes legitimately, you can update snapshots using:

  • Jest:
    • npm test -- -u
    • yarn test -u
    • pnpm test -u
  • npx vitest run -u (Vitest)

toMatchInlineSnapshot() and toMatchSnapshot() is not supported in our in-browser test runner

The code use the tabs above is for demonstration purposes only - we will try to get our in-browser test runner supporting this feature soon.

If you want to test this out, I recommend running Jest or Vitest locally!

Lesson Task

Sorry but due to limitations in our test runner simulation in the browser, running these tests will not pass in the browser. However you could copy/paste this to your local machine to run it, where it will pass in a real Jest or Vitest environment.

Ready to try running tests for this lesson?