Vue 3 Snapshot Serializer
Vue 3 Snapshot Serializer is a library designed to enhance snapshot testing for Vue 3 components within Vitest and Jest environments. It is currently at version 2.13.2 and actively maintained, with frequent minor releases incorporating bug fixes and new features. The library focuses on providing cleaner, more readable snapshots by intelligently handling Vue-specific elements like scoped styles, dynamic attributes, and prop serialization. A key differentiator is its explicit support for both `@vue/test-utils` and `@testing-library/vue`, offering flexible testing approaches. It directly addresses common snapshot noise, making tests more robust and less prone to irrelevant failures. This package is exclusively for Vue 3 projects, with a separate serializer available for Vue 2.
Common errors
-
SnapshotMismatchError: Snapshots do not match
cause A recent update to the serializer or changes in Vue components altered the rendered output, or configuration defaults changed (e.g., attribute stringification, `attributesNotToStringify` default).fixReview the diff in your test runner output. If the change is intended, update your snapshots by running your test command with the `--updateSnapshot` flag (e.g., `vitest --updateSnapshot` or `jest --updateSnapshot`). -
TypeError: Cannot read properties of undefined (reading 'addSnapshotSerializer')
cause The serializer is not being added correctly to the test runner's `expect` object, likely due to incorrect setup file configuration or not using a setup file at all.fixEnsure your `vitest.config.js` or `jest.config.js` correctly points to a setup file, and that setup file contains `expect.addSnapshotSerializer(vue3SnapshotSerializer);` before any tests run. For Vitest, this is typically `setupFiles: ['./vitest.setup.ts']`. -
Unexpected token 'export' or 'import' in serializer module
cause Your test environment is configured for CommonJS modules but is trying to load an ESM module directly, or vice-versa, when configuring the serializer path in `snapshotSerializers`.fixWhen specifying the serializer path in your `jest.config.js` or `vitest.config.js`, ensure you point to the correct module type based on your test runner's configuration: `./node_modules/vue3-snapshot-serializer/index.js` for CommonJS or `./node_modules/vue3-snapshot-serializer/index.mjs` for ESM. For `expect.addSnapshotSerializer`, use `require('vue3-snapshot-serializer')` for CJS or `import * as serializer from 'vue3-snapshot-serializer'` for ESM.
Warnings
- breaking The default value for `global.vueSnapshots.attributesNotToStringify` changed from `['style']` to `['class', 'style', 'value', 'type']` in v2.13.0, and `v-bind` camelCase props are now stringified. This can cause existing snapshots to differ and require updates.
- breaking Version 2.9.0 changed the default behavior for stringifying `style` attributes. Previously, object-based `style` attributes were stringified as objects; now they are converted to DOM-valid CSS strings by default.
- gotcha This library is exclusively for Vue 3 components. Attempting to use it with Vue 2 projects will lead to incorrect serialization or runtime errors due to fundamental differences in Vue's virtual DOM structure.
- gotcha After a `types.js` file restructuring in v2.13.0, there's a possibility of TypeScript-related issues. While tested, unexpected edge cases might exist.
- gotcha The `global.vueSnapshots.regexToRemoveAttributes` feature (v2.11.0) and `global.vueSnapshots.renameScopedVBindStyles` feature (v2.12.0) can significantly alter snapshot output if enabled. Be aware of their effects when debugging snapshot failures.
Install
-
npm install vue3-snapshot-serializer -
yarn add vue3-snapshot-serializer -
pnpm add vue3-snapshot-serializer
Imports
- serializer
const serializer = require('vue3-snapshot-serializer');import * as serializer from 'vue3-snapshot-serializer';
- global.vueSnapshots
global.vueSnapshots = { removeComments: true, sortAttributes: true }; - snapshotSerializers
import serializer from 'vue3-snapshot-serializer'; // This is not how serializers are added to config
// vitest.config.js or jest.config.js export default defineConfig({ test: { snapshotSerializers: ['./node_modules/vue3-snapshot-serializer/index.js'] } });
Quickstart
/* vitest.setup.ts */
import { expect } from 'vitest';
import * as vue3SnapshotSerializer from 'vue3-snapshot-serializer';
// Add the serializer
expect.addSnapshotSerializer(vue3SnapshotSerializer);
// Configure global settings for cleaner snapshots
global.vueSnapshots = {
removeComments: true, // Remove HTML comments
removeDataTest: true, // Remove 'data-test' attributes
removeDataTestid: true, // Remove 'data-testid' attributes
removeDataVId: true, // Remove Vue's data-v-xxx attributes from scoped styles
sortAttributes: true, // Sort attributes alphabetically for consistent snapshots
formatter: 'diffable', // Use the 'diffable' formatter for improved readability
};
/* MyComponent.vue */
<template>
<div class="container" data-test="my-container">
<!-- My comment -->
<p :style="{ color: dynamicColor }" data-testid="content">Hello {{ name }}!</p>
<ChildComponent :value="{ a: 1, b: 'test' }" some-prop="static" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const name = ref('World');
const dynamicColor = ref('red');
</script>
/* ChildComponent.vue */
<template>
<span class="child">{{ value.b }}</span>
</template>
<script setup lang="ts">
defineProps({
value: Object,
someProp: String,
});
</script>
/* MyComponent.test.ts */
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import MyComponent from './MyComponent.vue';
describe('MyComponent', () => {
it('renders correctly', () => {
const wrapper = mount(MyComponent);
expect(wrapper.html()).toMatchSnapshot();
});
});