close

Snapshot testing

Snapshot Testing is a powerful testing method used to capture and compare serialized representations of component output. When your UI or data structures change, snapshot testing helps you detect these changes promptly.

Basic usage

Rstest provides a simple snapshot testing API that allows you to easily create and use snapshots.

Creating snapshots

import { test, expect } from '@rstest/core';

test('component snapshot', () => {
  const user = { name: 'Alice', age: 25 };
  expect(user).toMatchSnapshot();
});

Inline snapshots

For simple values, you can use inline snapshots:

test('inline snapshot', () => {
  const message = 'Hello World';
  expect(message).toMatchInlineSnapshot('"Hello World"');
});

File snapshots

By default, Rstest stores all snapshots for the current test in .snap files with the format exports['testName index'] = ${snapshotContent}.

You can also use the toMatchFileSnapshot method to store snapshots in separate files, which makes them more readable.

test('file snapshot', async () => {
  const result = renderHTML(h('div', { class: 'foo' }));
  await expect(result).toMatchFileSnapshot('./basic.output.html');
});

Configuration options

Rstest provides various snapshot-related configuration options that allow you to customize snapshot behavior.

Updating snapshots

When test runs encounter snapshot mismatches, Rstest will mark the test as failed and output difference information.

If these changes are expected, you can update snapshots using the command line argument -u or the configuration option update.

CLI
rstest.config.ts
npx rstest -u

Serialization output

Rstest supports adding custom serialization tools for snapshot testing via the addSnapshotSerializer method to handle specific types of data structures.

This is especially useful when your snapshots contain local paths, sensitive data, or other non-serializable objects.

expect.addSnapshotSerializer({
  test: (val) => typeof val === 'string' && val.startsWith('secret:'),
  print: (val) => '***MASKED***',
});
expect('secret:123').toMatchSnapshot(); // Secret information in snapshot output will be masked

Using path-serializer can convert local paths to paths relative to the project root, which is very useful in cross-platform testing.

import { createSnapshotSerializer } from 'path-serializer';

expect.addSnapshotSerializer(
  createSnapshotSerializer({
    root: path.join(__dirname, '..'),
  }),
);

test('serialized snapshot', () => {
  const filePath = path.join(__dirname, '../data/file.txt');
  expect({ filePath }).toMatchSnapshot();
  // before: "/Users/aaa/Desktop/projects/rstest/examples/node/data/file.txt"
  // after: "<ROOT>/examples/node/data/file.txt"
});

Snapshot output path

Snapshot files are saved with the .snap extension by default, in the __snapshots__ folder in the same directory as the test file.

src/
├── components/
│   ├── button.test.ts
│   └── __snapshots__/
│       └── button.test.ts.snap

You can customize snapshot file paths through the resolveSnapshotPath configuration option.

import { defineConfig } from '@rstest/core';

export default defineConfig({
  resolveSnapshotPath: (testPath, snapExtension) => {
    // Store snapshots at the same level as test files
    return `${testPath}${snapExtension}`;
  },
});

Best practices

Keep snapshots concise

Snapshots should be readable and easy to understand, avoiding containing too much irrelevant information:

// ✅ Good practice - only include necessary information
test('user info snapshot', () => {
  const userInfo = {
    name: 'Alice',
    role: 'admin',
    permissions: ['read', 'write'],
  };
  expect(userInfo).toMatchSnapshot();
});

// ❌ Avoid - includes too much irrelevant information
test('complete user object snapshot', () => {
  const fullUser = {
    ...user,
    lastLogin: new Date(),
    sessionId: 'abc123',
    userAgent: 'Mozilla/5.0...',
  };
  expect(fullUser).toMatchSnapshot();
});

Use descriptive snapshot names

When using multiple snapshots, provide descriptive names for each snapshot:

test('component state changes', () => {
  const component = new MyComponent();

  expect(component.initialState).toMatchSnapshot('initial state');

  component.update();
  expect(component.updatedState).toMatchSnapshot('updated state');
});

Regularly review snapshots

As code evolves, snapshots may become outdated. Regularly reviewing and updating snapshots is necessary:

  • Update relevant snapshots when refactoring UI
  • Delete snapshots that are no longer needed
  • Reasonably use inline snapshots for small-scale testing