Snapshot
Scopri gli Snapshot tramite i video di Vue SchoolI test snapshot sono uno strumento estremamente utile ogni volta che si desidera garantire che l'output delle proprie funzioni rimanga invariato in modo imprevisto.
Quando si utilizzano gli snapshot, Vitest cattura un'istantanea del valore fornito e la confronta con un file snapshot di riferimento memorizzato accanto al test. Il test fallirà se i due snapshot non corrispondono: ciò indica che il cambiamento è inatteso, oppure che lo snapshot di riferimento deve essere aggiornato per riflettere la nuova versione del risultato.
Usare gli Snapshot
Per creare uno snapshot di un valore, è possibile utilizzare toMatchSnapshot()
dall'API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Alla prima esecuzione di questo test, Vitest crea un file snapshot simile al seguente:
// Vitest Snapshot v1, https://www.getbook.com/it/book/vitest-1/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
L'artefatto snapshot dovrebbe essere committato insieme alle modifiche al codice e revisionato come parte del processo di code review. Nelle esecuzioni successive dei test, Vitest confronterà l'output generato con lo snapshot precedente. Se corrispondono, il test passerà. Se non corrispondono, significa che il test runner ha rilevato un bug nel codice che necessita di correzione, oppure che l'implementazione è cambiata e lo snapshot deve essere aggiornato.
WARNING
Quando si utilizzano gli Snapshot con test asincroni concorrenti, è necessario usare expect
dal Contesto di Test locale per garantire che venga rilevato il test corretto.
Inline Snapshots
Allo stesso modo, è possibile utilizzare toMatchInlineSnapshot()
per salvare lo snapshot direttamente nel file di test.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Invece di creare un file snapshot separato, Vitest modificherà direttamente il file di test per aggiornare lo snapshot come stringa:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Questo consente di visualizzare direttamente l'output atteso senza dover navigare tra file diversi.
WARNING
Quando si utilizzano gli Snapshot con test asincroni concorrenti, è necessario usare expect
dal Contesto di Test locale per garantire che venga rilevato il test corretto.
Aggiornare gli Snapshot
Quando il valore ricevuto non corrisponde allo snapshot, il test fallisce e mostra la differenza tra i due. Se il cambiamento dello snapshot è intenzionale, è possibile aggiornare lo snapshot allo stato attuale.
In modalità watch, è possibile premere il tasto u
nel terminale per aggiornare direttamente lo snapshot che ha causato il fallimento.
In alternativa, è possibile utilizzare il flag --update
o -u
nella CLI per fare in modo che Vitest aggiorni gli snapshot.
vitest -u
Snapshot di File
Quando si invoca toMatchSnapshot()
, tutti gli snapshot vengono memorizzati in un file snapshot formattato. Ciò implica la necessità di effettuare l'escape di alcuni caratteri (ad esempio, le virgolette doppie "
e il backtick `
) all'interno della stringa dello snapshot. Inoltre, si potrebbe perdere l'evidenziazione della sintassi per il contenuto dello snapshot (se questo è in una lingua specifica).
In considerazione di ciò, è stato introdotto toMatchFileSnapshot()
per confrontare esplicitamente con un file. Questo consente di assegnare qualsiasi estensione di file allo snapshot, rendendolo più leggibile.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Verrà confrontato con il contenuto di ./test/basic.output.html
e potrà essere riscritto con il flag --update
.
Snapshot di Immagini
È anche possibile creare snapshot di immagini utilizzando jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Serializzatore Personalizzato
È possibile aggiungere una logica personalizzata per modificare il modo in cui i propri snapshot vengono serializzati. Come Jest, Vitest dispone di serializzatori predefiniti per i tipi JavaScript incorporati, gli elementi HTML, ImmutableJS e gli elementi React.
È possibile aggiungere esplicitamente un serializzatore personalizzato utilizzando l'API expect.addSnapshotSerializer
.
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` è una funzione che serializza un valore utilizzando i plugin esistenti.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
È supportata anche l'opzione snapshotSerializers per aggiungere implicitamente serializzatori personalizzati.
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` è una funzione che serializza un valore utilizzando i plugin esistenti.
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 'vite';
export default defineConfig({
test: {
snapshotSerializers: ['path/to/custom-serializer.ts'],
},
});
Dopo aver aggiunto un test come questo:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Si riceverà il seguente snapshot:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Stiamo utilizzando pretty-format
di Jest per serializzare gli snapshot. È possibile leggere ulteriori informazioni qui: pretty-format.
Differenze da Jest
Vitest offre una funzionalità Snapshot quasi compatibile con quella di Jest, con alcune eccezioni:
1. L'intestazione del commento nel file snapshot è diversa {#_1-comment-header-in-the-snapshot-file-is-different}
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://www.getbook.com/it/book/vitest-1/guide/snapshot
Questo non influisce sulla funzionalità, ma potrebbe influenzare il diff del commit durante la migrazione da Jest.
2. printBasicPrototype
è predefinito su false
{#_2-printbasicprototype-is-default-to-false}
Sia gli snapshot di Jest che quelli di Vitest si basano su pretty-format
. In Vitest, printBasicPrototype
è impostato su false
per impostazione predefinita per fornire un output snapshot più pulito, mentre in Jest <29.0.0 è true
per impostazione predefinita.
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",
},
]
`);
});
Consideriamo questa un'impostazione predefinita più ragionevole per la leggibilità e l'esperienza complessiva di sviluppo. Se si preferisce ancora il comportamento di Jest, è possibile modificare la propria configurazione:
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. Il chevron >
è usato come separatore invece dei due punti :
per i messaggi personalizzati {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest utilizza il chevron >
come separatore invece dei due punti :
per migliorare la leggibilità, quando si passa un messaggio personalizzato durante la creazione di un file snapshot.
Per il seguente codice di test di esempio:
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
In Jest, lo snapshot sarà:
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
In Vitest, lo snapshot equivalente sarà:
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. Lo snapshot Error
predefinito è diverso per toThrowErrorMatchingSnapshot
e toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest';
test('snapshot', () => {
// in Jest e Vitest
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`);
// Jest acquisisce lo snapshot di `Error.message` per l'istanza `Error`
// Vitest produce lo stesso output di toMatchInlineSnapshot
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingInlineSnapshot(`"error"`);
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`);
});