Снапшоты
Изучите снапшоты на видеоуроке от Vue SchoolСнапшот-тесты — это полезный инструмент для проверки стабильности вывода функций.
При использовании снапшотов Vitest создает снимок (snapshot) заданного значения и сравнивает его с эталонным снапшот-файлом, который хранится рядом с тестом. Тест завершится неудачей, если два снапшота не совпадают: это может означать, что изменение является неожиданным, или что эталонный снапшот необходимо обновить до новой версии результата.
Использование снапшотов
Чтобы создать снапшот значения, используйте метод toMatchSnapshot()
из API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
При первом запуске этого теста Vitest создаст файл снапшота, который будет выглядеть следующим образом:
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports['toUpperCase 1'] = '"FOOBAR"';
Файл снапшота следует зафиксировать (commit) вместе с изменениями кода и проверить при ревью. При последующих запусках тестов Vitest будет сравнивать вывод с сохраненным снапшотом. Если они совпадают, тест пройдет успешно. Если они не совпадают, это означает, что Vitest обнаружил ошибку в вашем коде, которую следует исправить, или что реализация изменилась, и снапшот необходимо обновить.
WARNING
При использовании снапшотов с асинхронными параллельными тестами необходимо использовать expect
из локального контекста теста, чтобы гарантировать корректное определение теста.
Встроенные снапшоты
Вы также можете использовать toMatchInlineSnapshot()
для хранения снапшота непосредственно в файле теста.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Вместо создания отдельного файла снапшота Vitest изменит файл теста, обновив снапшот непосредственно в виде строки:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Это позволяет увидеть ожидаемый вывод непосредственно в коде теста, без необходимости переключаться между файлами.
WARNING
При использовании снапшотов с асинхронными параллельными тестами необходимо использовать expect
из локального контекста теста, чтобы гарантировать корректное определение теста.
Обновление снапшотов
Когда полученное значение не соответствует существующему снапшоту, тест завершается с ошибкой и показывает разницу между ними. Если изменение снапшота ожидаемо, его можно обновить до текущего состояния.
В режиме наблюдения (watch mode) можно нажать клавишу u
в терминале, чтобы обновить все неудачные снапшоты.
Также можно использовать флаг --update
или -u
в CLI, чтобы Vitest обновил снапшоты.
vitest -u
Файловые снапшоты
При использовании toMatchSnapshot()
все снапшоты сохраняются в отформатированном файле .snap
. Это означает, что некоторые символы, такие как двойные кавычки "
и обратные апострофы ```, должны быть экранированы в строке снапшота. Кроме того, может быть потеряна подсветка синтаксиса для содержимого снапшота (если оно написано на каком-либо языке).
Для решения этой проблемы рекомендуется использовать toMatchFileSnapshot()
для сохранения снапшотов непосредственно в отдельных файлах. Это позволяет использовать любые расширения файлов для снапшотов, что делает их более читаемыми и удобными для редактирования.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Результат будет сравниваться с содержимым файла ./test/basic.output.html
. Файл может быть перезаписан с помощью флага --update
.
Снапшоты изображений
Также возможно создавать снапшоты изображений с помощью jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Более подробную информацию можно найти в примере examples/image-snapshot
.
Пользовательский сериализатор
Вы можете добавить собственную логику для изменения способа сериализации ваших снапшотов. Как и Jest, Vitest имеет сериализаторы по умолчанию для встроенных типов JavaScript, элементов HTML, ImmutableJS и элементов React.
Пример модуля сериализатора:
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` - это функция, которая сериализует значение с использованием существующих плагинов.
return `Pretty foo: ${printer(val.foo)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
После добавления теста, подобного этому:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Вы получите следующий снапшот:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Для сериализации снапшотов используется библиотека pretty-format
от Jest. Подробнее об этом можно прочитать здесь: pretty-format.
Отличия от Jest
Vitest предоставляет почти полностью совместимую функциональность снапшотов с Jest с несколькими исключениями:
1. Заголовок комментария в файле снапшота отличается {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
Это не влияет на функциональность, но может отразиться на diff коммита при переходе с Jest.
2. printBasicPrototype
по умолчанию имеет значение false
{#_2-printbasicprototype-is-default-to-false}
Снапшоты Jest и Vitest основаны на pretty-format
. В Vitest значение printBasicPrototype
по умолчанию установлено в false
, чтобы обеспечить более чистый вывод снапшота, в то время как в Jest <29.0.0 по умолчанию установлено значение true
.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// in Jest
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// in Vitest
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Мы считаем, что это более удобное значение по умолчанию для удобочитаемости и улучшения DX (опыта разработчика). Если вы предпочитаете поведение Jest, вы можете изменить конфигурацию:
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. Угловая скобка >
используется как разделитель вместо двоеточия :
для пользовательских сообщений {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest использует знак 'больше' >
как разделитель вместо двоеточия :
для повышения удобочитаемости, когда передается пользовательское сообщение во время создания файла снапшота.
Для следующего примера кода теста:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
В Jest снапшот будет:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
В Vitest эквивалентный снапшот будет:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `"error"`;