Test par instantanés
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Les tests par instantanés sont un outil très utile lorsque vous souhaitez vous assurer que votre interface utilisateur ne change pas de manière inattendue.
Un scénario typique de test par instantanés consiste à :
- Rendre un composant d'interface
- Prendre un instantané
- Le comparer à un fichier de référence stocké avec le test. Le test échouera si les deux instantanés ne correspondent pas : soit le changement est inattendu, soit l'instantané de référence doit être mis à jour vers la nouvelle version du composant.
Test par instantanés avec Jest
Cette approche peut être adaptée pour tester vos composants React. Plutôt que de rendre l'interface graphique (ce qui nécessiterait de construire toute l'application), vous pouvez utiliser un moteur de rendu de test pour générer rapidement une valeur sérialisable de votre arbre React. Consultez cet exemple de test pour un composant Link :
import renderer from 'react-test-renderer';
import Link from '../Link';
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
Lors du premier exécution, Jest crée un fichier d'instantané ressemblant à ceci :
exports[`renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;
L'artefact d'instantané doit être versionné avec les modifications de code et examiné pendant la revue de code. Jest utilise pretty-format pour rendre les instantanés lisibles pendant les revues. Lors des exécutions suivantes, Jest compare le rendu avec l'instantané précédent. S'ils correspondent, le test réussit. Sinon, soit le test a détecté un bogue (dans le composant <Link> ici) à corriger, soit l'implémentation a changé et l'instantané doit être mis à jour.
L'instantané concerne uniquement les données que vous rendez – dans notre exemple le composant <Link> avec la prop page. Cela signifie que même si un autre fichier (comme App.js) utilise <Link> avec des props manquantes, le test réussira car il ne connaît pas l'usage du composant <Link> et se limite à Link.js. De plus, rendre le même composant avec différentes props dans d'autres tests n'affectera pas le premier, les tests étant isolés.
Plus d'informations sur le fonctionnement et la conception des tests par instantanés sont disponibles dans le billet de publication. Nous recommandons de lire cet article pour comprendre quand utiliser cette technique. Regardez aussi cette vidéo egghead sur les tests par instantanés avec Jest.
Mise à jour des instantanés
Il est facile de repérer un échec de test après l'introduction d'un bogue. Dans ce cas, corrigez le problème pour rétablir les tests. Voyons maintenant le cas où un test échoue suite à une modification intentionnelle de l'implémentation.
Cela peut se produire si nous modifions intentionnellement l'adresse ciblée par le composant Link dans notre exemple.
// Updated test case with a Link to a different address
it('renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.instagram.com">Instagram</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
Dans ce cas, Jest affichera ce résultat :

Puisque nous avons mis à jour notre composant pour pointer vers une adresse différente, il est normal que l'instantané change. Le test échoue car l'instantané du composant mis à jour ne correspond plus à l'artefact de référence.
Pour résoudre ceci, nous devons mettre à jour nos artefacts d'instantanés. Exécutez Jest avec un drapeau qui lui indique de régénérer les instantanés :
jest --updateSnapshot
Allez-y et acceptez les modifications en exécutant la commande ci-dessus. Vous pouvez également utiliser l'équivalent en version raccourcie avec le flag -u pour régénérer les snapshots si vous préférez. Cela régénérera les artefacts de snapshot pour tous les tests de snapshot en échec. Si vous aviez d'autres tests de snapshot en échec suite à un bogue non intentionnel, vous devriez corriger ce bogue avant de régénérer les snapshots pour éviter d'enregistrer des snapshots du comportement erroné.
Si vous souhaitez limiter les cas de test de snapshot à régénérer, vous pouvez passer un flag supplémentaire --testNamePattern pour réenregistrer les snapshots uniquement pour les tests correspondant au motif spécifié.
Vous pouvez tester cette fonctionnalité en clonant l'exemple de snapshot, en modifiant le composant Link et en exécutant Jest.
Mode interactif des snapshots
Les snapshots en échec peuvent également être mis à jour de manière interactive en mode watch :

Une fois entré dans le mode interactif des snapshots, Jest vous guidera à travers les snapshots en échec un test à la fois et vous donnera la possibilité d'examiner le résultat défaillant.
De là, vous pouvez choisir de mettre à jour ce snapshot ou passer au suivant :

Une fois terminé, Jest vous fournira un récapitulatif avant de revenir en mode watch :

Snapshots en ligne
Les snapshots en ligne fonctionnent de manière identique aux snapshots externes (fichiers .snap), sauf que les valeurs des snapshots sont écrites automatiquement dans le code source. Cela signifie que vous bénéficiez des avantages des snapshots générés automatiquement sans avoir à basculer vers un fichier externe pour vérifier que la valeur correcte a été écrite.
Exemple :
Commencez par écrire un test en appelant .toMatchInlineSnapshot() sans arguments :
it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://example.com">Example Site</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot();
});
Lors de la prochaine exécution de Jest, tree sera évalué et un snapshot sera écrit comme argument de toMatchInlineSnapshot :
it('renders correctly', () => {
const tree = renderer
.create(<Link page="https://example.com">Example Site</Link>)
.toJSON();
expect(tree).toMatchInlineSnapshot(`
<a
className="normal"
href="https://example.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Example Site
</a>
`);
});
C'est tout ! Vous pouvez même mettre à jour les snapshots avec --updateSnapshot ou en utilisant la touche u en mode --watch.
Par défaut, Jest gère l'écriture des snapshots dans votre code source. Cependant, si vous utilisez prettier dans votre projet, Jest le détectera et déléguera le travail à prettier (en respectant votre configuration).
Comparateurs de propriétés (Property Matchers)
Souvent, des champs dans l'objet que vous souhaitez snapshot sont générés dynamiquement (comme des ID ou des dates). Si vous essayez de snapshot ces objets, ils feront échouer le snapshot à chaque exécution :
it('will fail every time', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};
expect(user).toMatchSnapshot();
});
// Snapshot
exports[`will fail every time 1`] = `
{
"createdAt": 2018-05-19T23:36:09.816Z,
"id": 3,
"name": "LeBron James",
}
`;
Pour ces cas, Jest permet de fournir un comparateur asymétrique pour n'importe quelle propriété. Ces comparateurs sont vérifiés avant l'écriture ou le test du snapshot, puis enregistrés dans le fichier snapshot à la place de la valeur reçue :
it('will check the matchers and pass', () => {
const user = {
createdAt: new Date(),
id: Math.floor(Math.random() * 20),
name: 'LeBron James',
};
expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
id: expect.any(Number),
});
});
// Snapshot
exports[`will check the matchers and pass 1`] = `
{
"createdAt": Any<Date>,
"id": Any<Number>,
"name": "LeBron James",
}
`;
Toute valeur fournie qui n'est pas un comparateur sera vérifiée exactement et sauvegardée dans le snapshot :
it('will check the values and pass', () => {
const user = {
createdAt: new Date(),
name: 'Bond... James Bond',
};
expect(user).toMatchSnapshot({
createdAt: expect.any(Date),
name: 'Bond... James Bond',
});
});
// Snapshot
exports[`will check the values and pass 1`] = `
{
"createdAt": Any<Date>,
"name": 'Bond... James Bond',
}
`;
Si le cas concerne une chaîne de caractères plutôt qu'un objet, vous devez remplacer vous-même la partie aléatoire de cette chaîne avant de tester le snapshot.
Vous pouvez utiliser par exemple replace() et les expressions régulières.
const randomNumber = Math.round(Math.random() * 100);
const stringWithRandomData = `<div id="${randomNumber}">Lorem ipsum</div>`;
const stringWithConstantData = stringWithRandomData.replace(/id="\d+"/, 123);
expect(stringWithConstantData).toMatchSnapshot();
D'autres méthodes incluent l'utilisation d'un sérialiseur de snapshot ou le mock de la bibliothèque responsable de générer la partie aléatoire du code que vous snapshottez.
Bonnes pratiques
Les instantanés sont un outil fantastique pour détecter les modifications inattendues d'interface dans votre application – qu'il s'agisse d'une réponse d'API, d'UI, de logs ou de messages d'erreur. Comme pour toute stratégie de test, il existe des bonnes pratiques à connaître et des recommandations à suivre pour les utiliser efficacement.