Instantanés
Apprenez à utiliser les instantanés en vidéo avec Vue SchoolLes tests d'instantanés sont un outil très utile pour garantir que la sortie de vos fonctions ne change pas de manière inattendue.
Lors de l'utilisation d'un instantané, Vitest capture la valeur donnée et la compare à un fichier d'instantané de référence stocké à côté du test. Le test échoue si les deux instantanés ne correspondent pas : cela indique soit un changement inattendu, soit la nécessité de mettre à jour l'instantané de référence avec la nouvelle version du résultat.
Utiliser les instantanés
Pour créer un instantané d'une valeur, vous pouvez utiliser la méthode toMatchSnapshot()
de l'API expect()
:
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchSnapshot();
});
Lors de la première exécution de ce test, Vitest crée un fichier d'instantané qui ressemble à ceci :
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports['toUpperCase 1'] = '"FOOBAR"';
Le fichier d'instantané doit être commité avec les modifications de code et examiné dans le cadre de votre processus de révision de code. Lors des exécutions de tests ultérieures, Vitest comparera la sortie générée avec l'instantané précédent. S'ils correspondent, le test réussira. S'ils ne correspondent pas, cela signifie soit que l'exécuteur de tests a détecté un bug dans votre code qui doit être corrigé, soit que l'implémentation a changé et que l'instantané doit être mis à jour.
WARNING
Lors de l'utilisation d'instantanés avec des tests concurrents asynchrones, l'objet expect
du contexte de test local doit être utilisé pour s'assurer que le test correct est détecté.
Instantanés en ligne
De même, vous pouvez utiliser la méthode toMatchInlineSnapshot()
pour stocker l'instantané 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 d'instantané séparé, Vitest modifiera directement le fichier de test pour y insérer l'instantané sous forme de chaîne de caractères :
import { expect, it } from 'vitest';
it('toUpperCase', () => {
const result = toUpperCase('foobar');
expect(result).toMatchInlineSnapshot('"FOOBAR"');
});
Cela vous permet de visualiser directement la sortie attendue sans avoir à naviguer entre plusieurs fichiers.
WARNING
Lors de l'utilisation d'instantanés avec des tests concurrents asynchrones, l'objet expect
du contexte de test local doit être utilisé pour s'assurer que le test correct est détecté.
Mise à jour des instantanés
Lorsque la valeur reçue ne correspond pas à l'instantané, le test échoue et vous montre la différence entre les deux. Si le changement d'instantané est intentionnel, vous pouvez souhaiter mettre à jour l'instantané à partir de l'état actuel.
En mode surveillance, vous pouvez appuyer sur la touche u
dans le terminal pour mettre à jour directement l'instantané échoué.
Alternativement, vous pouvez utiliser l'option --update
ou -u
dans la CLI pour que Vitest mette à jour les instantanés.
vitest -u
Instantanés de fichiers
Lorsque toMatchSnapshot()
est appelé, tous les instantanés sont stockés dans un fichier .snap
formaté. Cela implique que certains caractères (notamment le guillemet double "
et l'apostrophe `
) doivent être échappés dans la chaîne de l'instantané. De plus, vous risquez de perdre la coloration syntaxique du contenu de l'instantané (s'il est dans une langue spécifique).
C'est pourquoi nous avons introduit toMatchFileSnapshot()
pour permettre une correspondance explicite avec un fichier. Cela vous permet d'attribuer n'importe quelle extension de fichier à l'instantané, 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');
});
Cette méthode comparera le résultat avec le contenu de ./test/basic.output.html
. Le fichier peut être réécrit avec l'option --update
.
Instantanés d'images
Il est également possible de prendre des instantanés 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 instantanés 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 ajouter explicitement un sérialiseur personnalisé en utilisant 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 supportons également 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 'vitest/config';
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 l'instantané suivant :
Pretty foo: Object {
"x": 1,
"y": 2,
}
Vitest utilise le module pretty-format
de Jest pour sérialiser les instantanés. Vous pouvez en savoir plus ici : pretty-format.
Différence avec Jest
Vitest offre une fonctionnalité d'instantané presque compatible avec celle de Jest à quelques exceptions près :
1. L'en-tête de commentaire dans le fichier d'instantané est différent {#_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
Cela n'impacte pas la fonctionnalité, mais pourrait affecter votre diff
de commit lors de la migration depuis Jest.
2. printBasicPrototype
est par défaut à false
{#_2-printbasicprototype-is-default-to-false}
Les instantanés de Jest et de Vitest sont générés par pretty-format
. Dans Vitest, nous avons défini printBasicPrototype
par défaut à false
pour offrir une sortie d'instantané plus claire, 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 estimons que ce comportement par défaut est plus approprié pour la lisibilité et l'expérience développeur globale. Si vous préférez toujours le comportement de Jest, vous pouvez modifier votre configuration :
import { defineConfig } from 'vitest/config';
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 {#_3-chevron-is-used-as-a-separator-instead-of-colon-for-custom-messages}
Vitest utilise le chevron >
comme séparateur au lieu du deux-points :
pour améliorer la lisibilité lorsque vous passez un message personnalisé lors de la création d'un fichier d'instantané.
Pour l'exemple de code de test suivant :
test('toThrowErrorMatchingSnapshot', () => {
expect(() => {
throw new Error('error');
}).toThrowErrorMatchingSnapshot('hint');
});
Dans Jest, l'instantané sera :
exports[`toThrowErrorMatchingSnapshot: hint 1`] = `"error"`;
Dans Vitest, l'instantané équivalent sera :
exports[`toThrowErrorMatchingSnapshot > hint 1`] = `[Error: error]`;
4. L'instantané d'erreur par défaut est différent pour toThrowErrorMatchingSnapshot
et toThrowErrorMatchingInlineSnapshot
{#_4-default-error-snapshot-is-different-for-tothrowerrormatchingsnapshot-and-tothrowerrormatchinginlinesnapshot}
import { expect, test } from 'vitest'
test('snapshot', () => {
// dans Jest et Vitest
expect(new Error('error')).toMatchInlineSnapshot(`[Error: error]`)
// Jest capture le `Error.message` dans l'instantané pour l'instance `Error`
// Vitest affiche la même valeur que toMatchInlineSnapshot
expect(() => {
throw new Error('error')
}).toThrowErrorMatchingInlineSnapshot(`"error"`)
}).toThrowErrorMatchingInlineSnapshot(`[Error: error]`)
})