Snapshot
Impara gli Snapshot tramite video da Vue SchoolI test snapshot sono uno strumento molto utile quando si vuole assicurarsi che l'output delle funzioni non cambi inaspettatamente.
Quando si utilizza uno snapshot, Vitest crea un'istantanea del valore fornito e la confronta con un file di snapshot di riferimento memorizzato insieme al test. Il test fallisce se i due snapshot non corrispondono: questo indica che la modifica è inaspettata, oppure che lo snapshot di riferimento deve essere aggiornato alla nuova versione del risultato.
Utilizzare gli Snapshot
Per creare uno snapshot di un valore, si può utilizzare toMatchSnapshot()
dall'API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
La prima volta che questo test viene eseguito, Vitest crea un file snapshot simile a questo:
// Vitest Snapshot v1, https://www.getbook.com/it/book/vitest-0/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
Il file snapshot deve essere incluso nel commit insieme alle modifiche del codice e rivisto come parte del processo di code review. Nelle esecuzioni successive, Vitest confronta l'output generato con lo snapshot precedente. Se corrispondono, il test ha successo. In caso contrario, o il test runner ha trovato un bug nel codice che deve essere corretto, oppure l'implementazione è cambiata e lo snapshot deve essere aggiornato.
WARNING
Quando si utilizzano gli Snapshot con test asincroni concorrenti, è necessario utilizzare expect
dal Contesto di Test locale per garantire che venga rilevato il test corretto.
Snapshot Inline
Allo stesso modo, si può utilizzare toMatchInlineSnapshot()
per memorizzare lo snapshot direttamente all'interno del 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 modifica 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 permette di visualizzare l'output previsto direttamente senza dover passare da un file all'altro.
WARNING
Quando si utilizzano gli Snapshot con test asincroni concorrenti, è necessario utilizzare 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 viene mostrata la differenza tra i due. Se la modifica dello snapshot è intenzionale, si può aggiornare lo snapshot allo stato corrente.
In modalità watch, si può premere il tasto u
nel terminale per aggiornare direttamente lo snapshot fallito.
In alternativa, si può utilizzare il flag --update
o -u
nella CLI per fare in modo che Vitest aggiorni gli snapshot.
vitest -u
Snapshot di File
Quando si chiama toMatchSnapshot()
, tutti gli snapshot vengono memorizzati in un file di snapshot formattato. Questo significa che è necessario eseguire l'escape di alcuni caratteri, come le virgolette doppie "
e il backtick ``` nella stringa dello snapshot. Inoltre, si potrebbe perdere la colorazione della sintassi per il contenuto dello snapshot se il contenuto è in un linguaggio specifico.
Per migliorare questa situazione, introduciamo toMatchFileSnapshot()
per creare esplicitamente snapshot in un file. Questo permette di assegnare qualsiasi estensione di file al file snapshot, rendendoli più leggibili.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Confronta il contenuto di ./test/basic.output.html
e può essere sovrascritto 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();
});
Si può vedere un esempio in examples/image-snapshot
.
Serializzatore Personalizzato
Si può aggiungere la propria logica per modificare il modo in cui gli snapshot vengono serializzati. Come Jest, Vitest ha serializzatori predefiniti per i tipi JavaScript integrati, gli elementi HTML, ImmutableJS e per gli elementi React.
Esempio di un modulo serializzatore:
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)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
Dopo aver aggiunto un test come questo:
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Si otterrà il seguente snapshot:
Pretty foo: Object {
"x": 1,
"y": 2,
}
Stiamo usando pretty-format
di Jest per serializzare gli snapshot. Si può leggere di più qui: pretty-format.
Differenze da Jest
Vitest offre una funzionalità Snapshot quasi completamente compatibile con 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-0/guide/snapshot
Questo non influisce sulla funzionalità, ma potrebbe influire sulla diff di commit quando si migra da Jest.
2. printBasicPrototype
è impostato di default su false
{#_2-printbasicprototype-is-default-to-false}
Sia gli snapshot di Jest che quelli di Vitest sono gestiti da pretty-format
. In Vitest impostiamo printBasicPrototype
di default su false
per fornire un output snapshot più pulito, mentre in Jest <29.0.0 è true
di default.
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",
},
]
`);
});
Crediamo che questa sia un'impostazione predefinita più ragionevole per la leggibilità e l'esperienza complessiva dello sviluppatore. Se si preferisce il comportamento di Jest, si può modificare la 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à. Questo avviene quando viene fornito un messaggio personalizzato durante la creazione di uno 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"`;