Снимковое тестирование (snapshot testing) фиксирует текущее состояние
компонента и сравнивает его с сохранённым эталоном при последующих
запусках тестов. В экосистеме Vue основным инструментом для этого
выступает связка Vue Test Utils + Jest, где ключевую
роль играет матчер toMatchSnapshot.
Снимок представляет собой сериализованное описание результата: HTML-разметки, виртуального DOM, структуры данных или объекта. При первом запуске теста снимок сохраняется в файл. При следующих запусках результат теста сравнивается с сохранённой версией.
toMatchSnapshot предоставляется Jest и не требует
дополнительной настройки при стандартной конфигурации тестовой
среды.
Простейший пример:
import { mount } from '@vue/test-utils'
import Button from '@/components/Button.vue'
test('рендер кнопки соответствует снимку', () => {
const wrapper = mount(Button)
expect(wrapper.html()).toMatchSnapshot()
})
Алгоритм работы:
wrapper.html().Снимки сохраняются в директории __snapshots__, рядом с
файлом теста:
Button.spec.js
__snapshots__/
Button.spec.js.snap
Содержимое файла .snap:
exports[`рендер кнопки соответствует снимку 1`] = `
<button class="btn btn-primary">
Нажми меня
</button>
`
Каждый снимок связан с конкретным тестом и имеет уникальный ключ.
Наиболее распространённый вариант:
expect(wrapper.html()).toMatchSnapshot()
Преимущества:
Недостатки:
expect(wrapper.element).toMatchSnapshot()
или
expect(wrapper.vm.$.subTree).toMatchSnapshot()
Используется редко из-за сложности восприятия, но полезен при анализе низкоуровневых изменений.
Компоненты часто содержат нестабильные значения: id, даты, случайные числа. Такие данные делают снимки хрупкими.
Пример проблемы:
<span>{{ Date.now() }}</span>
Каждый запуск теста создаёт новый снимок.
Мокирование времени:
jest.useFakeTimers().setSystemTime(new Date('2024-01-01'))
Стабилизация данных через props:
mount(Component, {
props: {
timestamp: 1704067200000
}
})
Предобработка HTML:
expect(
wrapper.html().replace(/\d{13}/g, '[timestamp]')
).toMatchSnapshot()
По умолчанию Jest генерирует имя автоматически. Для сложных сценариев используется явное имя:
expect(wrapper.html()).toMatchSnapshot('кнопка в активном состоянии')
В файле снимков это отображается так:
exports[`кнопка в активном состоянии 1`] = `...`
Именованные снимки повышают читаемость и упрощают навигацию при ошибках.
Снимковое тестирование особенно эффективно при проверке различных состояний:
test('disabled состояние', () => {
const wrapper = mount(Button, {
props: { disabled: true }
})
expect(wrapper.html()).toMatchSnapshot()
})
test('loading состояние', () => {
const wrapper = mount(Button, {
props: { loading: true }
})
expect(wrapper.html()).toMatchSnapshot()
})
Каждое состояние фиксируется как отдельный эталон.
Vue Test Utils корректно сериализует слоты:
mount(Card, {
slots: {
default: '<p>Контент</p>',
footer: '<button>OK</button>'
}
})
Снимок отразит итоговую разметку с учётом всех слотов. Это позволяет отслеживать изменения в шаблонах-обёртках и layout-компонентах.
При осознанных изменениях интерфейса старые снимки перестают совпадать.
Команда обновления:
jest -u
или
npm test -- -u
Jest перезаписывает все несовпадающие снимки. Использовать следует только после проверки изменений, так как обновление происходит без анализа причин расхождений.
Снимок всего приложения
Снимки вместо логики
Частые автоматические обновления
expectexpect(wrapper.find('button').text()).toBe('Отправить')
expect(wrapper.html()).toMatchSnapshot()
Такой подход позволяет:
Снимки не предназначены для детального анализа бизнес-логики. Их задача — быстро выявлять визуальные и структурные регрессии. При правильном применении они сокращают объём ручных проверок и упрощают сопровождение UI-компонентов, оставаясь при этом прозрачными и управляемыми.