Snímky
Naučte se pracovat se snímky pomocí videa z Vue SchoolTestování pomocí snímků je velmi užitečný nástroj, kdykoliv chcete mít jistotu, že se výstup vašich funkcí neočekávaně nezmění.
Při použití snímků Vitest vytvoří snímek dané hodnoty a poté jej porovná s referenčním souborem snímků uloženým vedle testu. Test selže, pokud se snímky neshodují: buď je změna neočekávaná, nebo je třeba referenční snímek aktualizovat na novou verzi výsledku.
Použití snímků
Pro pořízení snímku hodnoty můžete použít toMatchSnapshot()
z API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Při prvním spuštění tohoto testu Vitest vytvoří soubor snímku, který vypadá takto:
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports['toUpperCase 1'] = '"FOOBAR"';
Soubor se snímkem by měl být odevzdán spolu se změnami kódu a zkontrolován v rámci vašeho procesu revize kódu. Při následných spuštěních testů Vitest porovná vykreslený výstup s předchozím snímkem. Pokud se shodují, test projde. Pokud se neshodují, buď testovací nástroj našel chybu ve vašem kódu, která by měla být opravena, nebo se implementace změnila a snímek je třeba aktualizovat.
WARNING
Při použití snímků s asynchronními souběžnými testy musí být použito expect
z lokálního Testovacího kontextu, aby bylo zajištěno, že je detekován správný test.
Inline snímky
Podobně můžete použít toMatchInlineSnapshot()
k uložení snímku přímo v testovacím souboru.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Vitest místo vytvoření samostatného souboru snímku přímo upraví testovací soubor a aktualizuje snímek jako řetězec:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
To vám umožní vidět očekávaný výstup přímo, aniž byste museli přecházet mezi různými soubory.
WARNING
Při použití snímků s asynchronními souběžnými testy musí být použito expect
z lokálního Testovacího kontextu, aby bylo zajištěno, že je detekován správný test.
Aktualizace snímků
Když se přijatá hodnota neshoduje se snímkem, test selže a ukáže vám rozdíl mezi nimi. Pokud je změna snímku očekávaná, můžete chtít snímek aktualizovat z aktuálního stavu.
V režimu sledování můžete v terminálu stisknout klávesu u
pro přímou aktualizaci selhaného snímku.
Nebo můžete použít příznak --update
nebo -u
v CLI pro aktualizaci snímků ve Vitestu.
vitest -u
Souborové snímky
Při volání toMatchSnapshot()
ukládáme všechny snímky do formátovaného souboru snímků. To znamená, že musíme v řetězci snímku uniknout některé znaky (konkrétně dvojité uvozovky "
a zpětný apostrof `
). Zároveň můžete ztratit zvýraznění syntaxe pro obsah snímku (pokud je v nějakém programovacím jazyce).
S ohledem na to jsme zavedli toMatchFileSnapshot()
pro explicitní porovnání se souborem. To vám umožňuje přiřadit souboru snímku libovolnou příponu souboru a zlepšit tak jejich čitelnost.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Porovná se s obsahem souboru ./test/basic.output.html
. A může být zapsán zpět s příznakem --update
.
Snímky obrázků
Lze také vytvářet snímky obrázků pomocí jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Vlastní serializátor
Můžete přidat vlastní logiku pro změnu způsobu serializace vašich snímků. Stejně jako Jest, Vitest má výchozí serializátory pro vestavěné typy JavaScriptu, HTML elementy, ImmutableJS a pro React elementy.
Můžete explicitně přidat vlastní serializátor pomocí API expect.addSnapshotSerializer
.
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` je funkce, která serializuje hodnotu pomocí existujících pluginů.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
Podporujeme také možnost snapshotSerializers pro implicitní přidání vlastních serializátorů.
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` je funkce, která serializuje hodnotu pomocí existujících pluginů.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
} satisfies SnapshotSerializer;
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});
Po přidání testu jako je tento:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Získáte následující snímek:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Pro serializaci snímků se používá Jestův pretty-format
. Více si o tom můžete přečíst zde: pretty-format.
Rozdíly oproti Jestu
Vitest poskytuje téměř kompatibilní funkci Snapshot s Jestem s několika výjimkami:
1. Hlavička komentáře v souboru snímku je odlišná {#_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
To ve skutečnosti neovlivňuje funkčnost, ale může ovlivnit váš commit diff při migraci z Jestu.
2. printBasicPrototype
je ve výchozím nastavení false
{#_2-printbasicprototype-is-default-to-false}
Snímky Jestu i Vitestu jsou poháněny pretty-format
. Ve Vitestu nastavujeme printBasicPrototype
ve výchozím nastavení na false
, abychom poskytli čistší výstup snímku, zatímco v Jestu <29.0.0 je ve výchozím nastavení true
.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// v Jestu
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// ve Vitestu
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Věříme, že toto je rozumnější výchozí nastavení pro čitelnost a celkovou zkušenost vývojáře. Pokud stále preferujete chování Jestu, můžete změnit svou konfiguraci:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. Znak >
je použit jako oddělovač místo dvojtečky :
pro vlastní zprávy {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest používá znak >
jako oddělovač místo dvojtečky :
pro lepší čitelnost, když je při vytváření souboru snímku předána vlastní zpráva.
Pro následující příklad testovacího kódu:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
V Jestu bude snímek:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
Ve Vitestu bude ekvivalentní snímek:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. Výchozí snímek Error
je odlišný pro toThrowErrorMatchingSnapshot
a toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest'
test('snapshot', () => {
// v Jestu a Vitestu
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`)
// Jest zachycuje `Error.message` pro instanci `Error`
// Vitest tiskne stejnou hodnotu jako toMatchInlineSnapshot
expect(() => {
throw new Error('error')
}).toThrowErrorMatchingInlineSnapshot(`"error"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`)
})