close
  • English
  • 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