Snapshots
Découvrez les Snapshots en vidéo avec Vue SchoolLes tests de snapshot sont un outil très utile pour s'assurer que la sortie de vos fonctions ne change pas de manière inattendue.
Lors de l'utilisation de snapshots, Vitest capture un instantané de la valeur donnée, puis le compare à un fichier de snapshot de référence stocké à côté du test. Le test échouera si les deux snapshots ne correspondent pas : soit le changement est inattendu, soit le snapshot de référence doit être mis à jour pour refléter la nouvelle version du résultat.
Utilisation des Snapshots
Pour prendre un snapshot d'une valeur, vous pouvez utiliser la fonction toMatchSnapshot()
de l'API expect
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
La première fois que ce test est exécuté, Vitest crée un fichier de snapshot qui ressemble à ceci :
// Vitest Snapshot v1, https://www.getbook.com/fr/book/vitest-1/guide/snapshot
exports['toUpperCase 1'] = '"FOOBAR"';
L'artefact de snapshot doit être validé avec les modifications de code et examiné dans le cadre de votre processus de revue de code. Lors des exécutions de tests ultérieures, Vitest comparera la sortie générée avec le snapshot précédent. S'ils correspondent, le test sera réussi. S'ils ne correspondent pas, soit le runner de tests a détecté un bug dans votre code à corriger, soit l'implémentation a changé et le snapshot doit être mis à jour.
WARNING
Lorsque vous utilisez des Snapshots avec des tests concurrents asynchrones, l'objet expect
du Contexte de Test local doit être utilisé afin de garantir la détection du test approprié.
Snapshots en ligne
De même, vous pouvez utiliser toMatchInlineSnapshot()
pour stocker le snapshot directement dans le fichier de test.
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot();
});
Au lieu de créer un fichier de snapshot, Vitest modifiera directement le fichier de test pour mettre à jour le snapshot en tant que chaîne de caractères :
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Cela vous permet de voir directement la sortie attendue, sans avoir à naviguer entre différents fichiers.
WARNING
Lorsque vous utilisez des Snapshots avec des tests concurrents asynchrones, l'objet expect
du Contexte de Test local doit être utilisé afin de garantir la détection du test approprié.
Mise à jour des Snapshots
Lorsque la valeur reçue ne correspond pas au snapshot, le test échoue et vous montre la différence. Lorsque le changement de snapshot est attendu, vous pouvez mettre à jour le snapshot à partir de son état actuel.
En mode watch
(surveillance), vous pouvez appuyer sur la touche u
dans le terminal pour mettre à jour directement le snapshot échoué.
Ou vous pouvez utiliser l'option --update
ou -u
dans la CLI pour forcer Vitest à mettre à jour les snapshots.
vitest -u
Snapshots de fichiers
Lors de l'appel de toMatchSnapshot()
, tous les snapshots sont stockés dans un fichier .snap
formaté. Cela signifie que nous devons échapper certains caractères (notamment le guillemet double "
et l'apostrophe inversée `
) dans la chaîne de snapshot. De plus, vous risquez de perdre la coloration syntaxique du contenu du snapshot (s'il est dans un certain langage).
C'est pourquoi nous avons introduit toMatchFileSnapshot()
pour correspondre explicitement à un fichier. Cela vous permet d'attribuer n'importe quelle extension de fichier au fichier de snapshot, ce qui les rend plus lisibles.
import { expect, it } from 'vitest';
it('render basic', async () => {
const result = renderHTML(h('div', { class: 'foo' }));
await expect(result).toMatchFileSnapshot('./test/basic.output.html');
});
Il comparera le contenu avec ./test/basic.output.html
. Il peut également être réécrit avec l'option --update
.
Snapshots d'images
Il est également possible de prendre des snapshots d'images en utilisant jest-image-snapshot
.
npm i -D jest-image-snapshot
test('image snapshot', () => {
expect(readFileSync('./test/stubs/input-image.png')).toMatchImageSnapshot();
});
Sérialiseur personnalisé
Vous pouvez ajouter votre propre logique pour modifier la manière dont vos snapshots sont sérialisés. Comme Jest, Vitest dispose de sérialiseurs par défaut pour les types JavaScript intégrés, les éléments HTML, ImmutableJS et les éléments React.
Vous pouvez explicitement ajouter un sérialiseur personnalisé via l'API expect.addSnapshotSerializer
.
expect.addSnapshotSerializer({
serialize(val, config, indentation, depth, refs, printer) {
// `printer` est une fonction qui sérialise une valeur en utilisant les plugins existants.
return `Pretty foo: ${printer(val.foo, config, indentation, depth, refs)}`;
},
test(val) {
return val && Object.prototype.hasOwnProperty.call(val, 'foo');
},
});
Nous prenons également en charge l'option snapshotSerializers pour ajouter implicitement des sérialiseurs personnalisés.
import { SnapshotSerializer } from 'vitest';
export default {
serialize(val, config, indentation, depth, refs, printer) {
// `printer` est une fonction qui sérialise une valeur en utilisant les plugins existants.
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'],
},
});
Après avoir ajouté un test comme celui-ci :
test('foo snapshot test', () => {
const bar = {
foo: {
x: 1,
y: 2,
},
};
expect(bar).toMatchSnapshot();
});
Vous obtiendrez le snapshot suivant :
Pretty foo: Object {
"x": 1,
"y": 2,
}
Nous utilisons pretty-format
de Jest pour sérialiser les snapshots. Vous pouvez en savoir plus ici : pretty-format.
Différence avec Jest
Vitest offre une fonctionnalité de Snapshot presque compatible avec Jest, à quelques exceptions près :
1. L'en-tête de commentaire dans le fichier de snapshot est différent
- // Jest Snapshot v1, https://goo.gl/fbAQLP
+ // Vitest Snapshot v1, https://www.getbook.com/fr/book/vitest-1/guide/snapshot
Cela n'affecte pas la fonctionnalité, mais cela pourrait influencer votre différentiel de commit lors de la migration depuis Jest.
2. printBasicPrototype
est false
par défaut
Les snapshots de Jest et de Vitest sont gérés par pretty-format
. Dans Vitest, nous avons défini printBasicPrototype
par défaut sur false
pour fournir une sortie de snapshot plus propre, tandis que dans Jest <29.0.0, il est true
par défaut.
import { expect, test } from 'vitest';
test('snapshot', () => {
const bar = [
{
foo: 'bar',
},
];
// dans Jest
expect(bar).toMatchInlineSnapshot(`
Array [
Object {
"foo": "bar",
},
]
`);
// dans Vitest
expect(bar).toMatchInlineSnapshot(`
[
{
"foo": "bar",
},
]
`);
});
Nous pensons que c'est un comportement par défaut plus raisonnable pour la lisibilité et l'expérience développeur (DX) globale. Si vous préférez toujours le comportement de Jest, vous pouvez modifier votre configuration :
// vitest.config.js
export default defineConfig({
test: {
snapshotFormat: {
printBasicPrototype: true,
},
},
});
3. Le chevron >
est utilisé comme séparateur au lieu du deux-points :
pour les messages personnalisés
Vitest utilise le chevron >
comme séparateur au lieu du deux-points :
pour la lisibilité, lorsqu'un message personnalisé est fourni lors de la création d'un fichier de snapshot.
Pour l'exemple de code de test suivant :
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
Dans Jest, le snapshot sera :
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
Dans Vitest, le snapshot équivalent sera :
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. Le snapshot d'erreur par défaut est différent pour toThrowErrorMatchingSnapshot
et toThrowErrorMatchingInlineSnapshot
import { expect, test } from 'vitest';
test('snapshot', () => {
// dans Jest et Vitest
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`);
// Jest capture `Error.message` pour l'instance `Error`
// Vitest affiche la même valeur que toMatchInlineSnapshot
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingInlineSnapshot(`"error"`);
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`);
});