READ-ONLY PACKAGE PREVIEW

vitest/references/features-snapshots.md

Version e53a142a2420 · MIT. This preview displays packaged text and does not execute code. Treat the contents as untrusted instructions.

← Return to resource and package checksum


name: snapshot-testing description: Snapshot testing with file, inline, and file snapshots


Snapshot Testing

Snapshot tests capture output and compare against stored references.

Basic Snapshot

import { expect, test } from 'vitest'

test('snapshot', () => {
  const result = generateOutput()
  expect(result).toMatchSnapshot()
})

First run creates .snap file:

// __snapshots__/test.spec.ts.snap
exports['snapshot 1'] = `
{
  "id": 1,
  "name": "test"
}
`

Inline Snapshots

Stored directly in test file:

test('inline snapshot', () => {
  const data = { foo: 'bar' }
  expect(data).toMatchInlineSnapshot()
})

Vitest updates the test file:

test('inline snapshot', () => {
  const data = { foo: 'bar' }
  expect(data).toMatchInlineSnapshot(`
    {
      "foo": "bar",
    }
  `)
})

File Snapshots

Compare against explicit file:

test('render html', async () => {
  const html = renderComponent()
  await expect(html).toMatchFileSnapshot('./expected/component.html')
})

Snapshot Hints

Add descriptive hints:

test('multiple snapshots', () => {
  expect(header).toMatchSnapshot('header')
  expect(body).toMatchSnapshot('body content')
  expect(footer).toMatchSnapshot('footer')
})

Object Shape Matching

Match partial structure:

test('shape snapshot', () => {
  const data = { 
    id: Math.random(), 
    created: new Date(),
    name: 'test' 
  }

  expect(data).toMatchSnapshot({
    id: expect.any(Number),
    created: expect.any(Date),
  })
})

Error Snapshots

test('error message', () => {
  expect(() => {
    throw new Error('Something went wrong')
  }).toThrowErrorMatchingSnapshot()
})

test('inline error', () => {
  expect(() => {
    throw new Error('Bad input')
  }).toThrowErrorMatchingInlineSnapshot(`[Error: Bad input]`)
})

Updating Snapshots

# Update all snapshots
vitest -u
vitest --update

# In watch mode, press 'u' to update failed snapshots

In CI (process.env.CI), Vitest never writes snapshots: mismatches, missing snapshots, and obsolete snapshots (entries no longer matching any test) all fail the run.

Visual & ARIA Snapshots (Browser Mode)

import { expect, test } from 'vitest'
import { page } from 'vitest/browser' // v4: import from 'vitest/browser'

test('button looks correct', async () => {
  await expect(page.getByRole('button')).toMatchScreenshot('primary-button')
})

// ARIA snapshot — assert the accessibility tree (4.1+, experimental)
test('nav structure', async () => {
  await expect.element(page.getByRole('navigation')).toMatchAriaInlineSnapshot(`
    - navigation "Main":
      - link "Home"
  `)
})

Custom Snapshot Matchers (4.1+)

Build matchers on the composable Snapshots helpers from vitest (replaces importing from jest-snapshot):

import { expect, Snapshots } from 'vitest'

const { toMatchSnapshot, toMatchInlineSnapshot } = Snapshots

expect.extend({
  toMatchTrimmedSnapshot(received: string, length: number) {
    return toMatchSnapshot.call(this, received.slice(0, length))
  },
  toMatchTrimmedInlineSnapshot(received: string, inlineSnapshot?: string) {
    return toMatchInlineSnapshot.call(this, received.slice(0, 10), inlineSnapshot)
  },
})

The inline snapshot string must be the last argument. File snapshot matchers must be async.

Custom Serializers

Add custom snapshot formatting:

expect.addSnapshotSerializer({
  test(val) {
    return val && typeof val.toJSON === 'function'
  },
  serialize(val, config, indentation, depth, refs, printer) {
    return printer(val.toJSON(), config, indentation, depth, refs)
  },
})

Or via config:

// vitest.config.ts
defineConfig({
  test: {
    snapshotSerializers: ['./my-serializer.ts'],
  },
})

Snapshot Format Options

defineConfig({
  test: {
    snapshotFormat: {
      printBasicPrototype: false, // Don't print Array/Object prototypes (Vitest default)
      escapeString: false,
      printShadowRoot: true,      // v4 default: custom elements print their shadow root
    },
  },
})

Concurrent Test Snapshots

Use context's expect:

test.concurrent('concurrent 1', async ({ expect }) => {
  expect(await getData()).toMatchSnapshot()
})

test.concurrent('concurrent 2', async ({ expect }) => {
  expect(await getOther()).toMatchSnapshot()
})

Snapshot File Location

Default: __snapshots__/<test-file>.snap

Customize:

defineConfig({
  test: {
    resolveSnapshotPath: (testPath, snapExtension) => {
      return testPath.replace('__tests__', '__snapshots__') + snapExtension
    },
  },
})

Key Points

  • Commit snapshot files to version control
  • Review snapshot changes in code review
  • Use hints for multiple snapshots in one test
  • Use toMatchFileSnapshot for large outputs (HTML, JSON)
  • Inline snapshots auto-update in test file
  • Use context's expect for concurrent tests
  • CI fails on obsolete snapshots; clean them with --update
  • v4 prints custom-element shadow roots; disable via snapshotFormat.printShadowRoot: false