Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to snapshot test Vue components

Snapshot tests capture the rendered output of components and alert you when it changes unexpectedly. As the creator of CoreUI with over 10 years of Vue.js experience since 2014, I’ve used snapshot testing to catch accidental regressions in UI components across hundreds of components. The standard approach uses @vue/test-utils to mount components and Vitest’s toMatchSnapshot to compare renders against stored snapshots. This provides an automatic safety net for your component’s output.

Create a snapshot test for a simple component.

// UserCard.vue
<template>
  <div class="user-card">
    <img :src="user.avatar" :alt="user.name" />
    <h3>{{ user.name }}</h3>
    <p>{{ user.email }}</p>
  </div>
</template>

<script setup>
defineProps({ user: Object })
</script>
// UserCard.spec.js
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import UserCard from './UserCard.vue'

describe('UserCard', () => {
  it('matches snapshot', () => {
    const wrapper = mount(UserCard, {
      props: {
        user: {
          name: 'John Doe',
          email: '[email protected]',
          avatar: '/avatar.jpg'
        }
      }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })
})

On first run Vitest creates a .snap file with the rendered HTML. On subsequent runs it compares output to the stored snapshot. Any change causes the test to fail. Commit snapshot files to version control.

Using Component Snapshot

Snapshot the component wrapper directly.

import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import ProductList from './ProductList.vue'

describe('ProductList', () => {
  it('renders product list snapshot', () => {
    const wrapper = shallowMount(ProductList, {
      props: {
        products: [
          { id: 1, name: 'Laptop', price: 999 },
          { id: 2, name: 'Mouse', price: 29 }
        ]
      }
    })

    expect(wrapper.element).toMatchSnapshot()
  })

  it('renders empty state snapshot', () => {
    const wrapper = shallowMount(ProductList, {
      props: { products: [] }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })
})

shallowMount stubs child components, making snapshots smaller and more focused. Testing both populated and empty states ensures both render paths are covered.

Updating Snapshots

Regenerate snapshots after intentional changes.

# Update all outdated snapshots
npx vitest --update-snapshots

# Update snapshot for specific file
npx vitest UserCard --update-snapshots

When you intentionally change a component’s output, run update to regenerate snapshots. Review the diff carefully before committing. Never update snapshots blindly without reviewing what changed.

Inline Snapshots

Embed snapshots directly in the test file.

import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Badge from './Badge.vue'

describe('Badge', () => {
  it('renders with correct class', () => {
    const wrapper = mount(Badge, {
      props: { label: 'New', variant: 'success' }
    })

    expect(wrapper.html()).toMatchInlineSnapshot(`
      "<span class="badge badge-success">New</span>"
    `)
  })
})

Inline snapshots store the expected output directly in the test file. Great for small components where seeing the expected output in context helps. Vitest auto-fills the value on first run.

Best Practice Note

This is the same snapshot testing approach we use across CoreUI Vue components to prevent UI regressions. Use snapshots for pure presentation components - they’re most valuable when a component’s only job is rendering. Avoid snapshotting components with dynamic data like timestamps or random IDs, as they always produce different output. Keep snapshots small and focused: prefer shallowMount over mount to avoid capturing child component internals. Treat a failing snapshot as a question: did this change on purpose? If yes, update. If no, fix the bug.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team