Comment démarrer avec Jest pour les tests unitaires JavaScript

Jest est un framework pour exécuter des tests unitaires, un moyen pour vous de tester les fonctions et composants individuels de votre base de code pour vous assurer que les futurs commits ne cassent pas quelque chose d'inattendu. Nous allons vous montrer comment le configurer et l'utiliser avec un framework frontal comme React.
Qu'est-ce que les tests unitaires ?
Les tests sont très importants lorsque vous travaillez avec une équipe de programmeurs - tous les commits poussés vers votre contrôle de source doivent être automatiquement construits et testés pour vous assurer de ne rien casser accidentellement. Pour garder tout le monde sain d'esprit, l'ensemble du pipeline peut être automatisé avec un logiciel comme Jenkins, mais pour exécuter les tests réels, vous devrez utiliser un framework de test unitaire comme Jest.
Jest est un framework pour exécuter des tests unitaires. Une unité peut être n'importe quel nombre de choses - une fonction, une classe ou un composant - elle représente simplement la plus petite unité de code que vous devriez tester, pour vous assurer que les futures mises à jour de code ne cassent rien. Si vous écrivez une fonction qui récupère des données à partir d'un point de terminaison et renvoie une sortie, vous écrirez un test unitaire correspondant qui prendra cette fonction, l'appellera et enregistrera la sortie. Ensuite, vous pouvez faire des affirmations en fonction de ce qu'il a renvoyé. Est-il correctement formaté ? Certaines valeurs sont-elles indéfinies ? Fonctionne-t-il comme prévu ? Si l'un de ces tests échoue, quelque chose ne va pas dans votre code.
Jest peut également être utilisé pour exécuter des tests sur des applications Web. Il est couramment utilisé avec des frameworks basés sur les données comme React pour s'assurer que les composants ont l'état et les accessoires appropriés pour une entrée donnée.
Alors que les tests unitaires peuvent sembler fastidieux à écrire, et c'est certainement plus de travail, cela conduit généralement à de meilleures bases de code à la fin. Traiter avec du code hérité est un problème pour cette raison précise : laisser des commentaires appropriés aide, mais écrire un test unitaire revient à écrire de la documentation pour vos fonctions. Vous définissez quelle entrée entre, comment l'utiliser et quelle entrée doit être attendue.
Premiers pas avec Jest
Pour configurer un environnement de test simple, créez un nouveau projet avec npm init -y
et installez Jest en tant que dépendance de développement à partir de npm
:
npm install --save-dev jest
Pour exécuter des tests à partir de la ligne de commande, vous devrez ajouter un script simple dans package.json
qui appelle Jest :
"scripts": {
"test": "jest"
}
Vous aurez besoin d'une fonction à tester, alors créez un nouveau fichier sous src/doSomeMath.js
, et configurez-le pour exporter une fonction :
function doSomeMath(a, b) {
return a + b;
}
module.exports = doSomeMath;
Enregistrez ce fichier et ouvrez tests/doSomeMath.test.js
. Jest cherchera automatiquement dans le répertoire test/
pour trouver les tests à exécuter. Ce fichier agit comme un fichier compagnon de doSomeMath.js
et définit une suite de tests pour vérifier que toutes les fonctions fonctionnent correctement. Un test Jest de base ressemble à ceci :
test('Description', () => {
expect(functionName(args)).toBe(result);
});
Fondamentalement, une fonction test()
encapsule tout le code du test. Chaque bloc expect()
appelle une fonction (c'est-à-dire une unité), puis transmet la valeur au matcher. Dans ce cas, il s'agit de la fonction toBe()
, qui vérifie l'égalité simple.
Jest a beaucoup de matchers différents, que vous pouvez lire dans leurs docs. Pour n'en nommer que quelques-uns :
.not.matcher()
gère l'inversion de n'importe quel matcher.toBe()
vérifie l'égalité exacte (Object.is) mais ne gère notamment pas les objets.toEqual()
vérifie l'égalité profonde des objets.toStrictEqual()
est identique àtoEqual
mais s'assure également qu'aucun objet n'a de propriétés non définies supplémentaires.toBeTruthy()
ettoBeFalsy()
vérifient tout ce qui est évalué àtrue
oufalse
dans un < instructionif
.-
toBeNull()
,toBeUndefined()
ettoBeDefined()
vérifient tous les différents états des objets. toContain()
vérifie le contenu du tableau.toMatch()
fait correspondre une expression régulière à une chaîne.toThrow()
s'assure que le code générera une erreur (généralement pour tester une entrée incorrecte).
Pour cette suite de tests, vous devrez importer votre fonction et transmettre certains arguments et résultats. Vous pouvez et devez généralement inclure plusieurs blocs expect
dans un seul test pour couvrir plusieurs scénarios.
const doSomeMath = require('../src/doSomeMath');
test('adds 2 + 2 to equal 4', () => {
expect(doSomeMath(1, 1)).toBe(2);
expect(doSomeMath(2, 2)).toBe(4);
});
Enregistrez ce fichier, puis exécutez :
npm run test
Cela exécutera toutes vos suites de tests et affichera les résultats pour chacune d'entre elles.

Tout devrait passer, à condition que les mathématiques fonctionnent correctement. En cas d'échec, Jest vous donnera une description détaillée de ce qui s'est passé, vous aidant à localiser le problème.
Parce que le code Jest n'est que du JavaScript, vous pouvez scripter vos tests assez facilement. Par exemple, vous pouvez utiliser une boucle for et appeler expect
plusieurs fois avec une entrée itérative. Si une exécution de expect
échoue, le test lui-même échouera.
test('adds 2 + 2 to equal 4', () => {
for (let a = 1; a < 10; a++) {
expect(doSomeMath(a, 5)).toBe(a + 5)
}
});
Vous pouvez utiliser cette fonctionnalité pour beaucoup de choses, mais la plupart des tests feront généralement trois choses principales :
- Organiser, où les données sont préparées pour l'unité
- Act, où l'unité est appelée, transmet les données arrangées et la sortie est enregistrée
- Assert, où vous exécutez tous vos matchers pour vous assurer que tout fonctionne comme prévu
Tester avec React
S'assurer que les mathématiques fonctionnent est cool et tout, mais vous n'avez probablement pas l'intention d'utiliser Jest pour quelque chose d'aussi simple que cela. Vous êtes probablement intéressé par l'utilisation de Jest pour automatiser les tests d'une application JavaScript, peut-être construite avec un framework comme React. Bien que vous deviez toujours effectuer des tests complets de l'interface utilisateur avec un examen manuel, Jest peut toujours être utilisé pour tester les composants React de manière isolée. Après tout, les composants React ne sont en réalité que des fonctions qui renvoient une sortie JSX, qui peut être comparée et testée.
Pour commencer, configurez un nouveau projet React avec create-react-app
:
npx create-react-app jest-react
Create React App installe Jest par défaut, ainsi que React Testing Library, qui contient des gestionnaires utiles pour travailler avec React dans Jest.
Modifiez le composant par défaut App.js
comme suit :
import React, {useState} from 'react';
import './App.css';
function App() {
const [disabled, setDisabled] = useState(false);
function handleClick() {
setDisabled(!disabled);
}
return (
<button data-testid="useless-button" disabled={disabled} onClick={handleClick}>
Click Me
</button>
);
}
export default App;
Ce morceau de code absolument inutile définit un bouton qui, une fois cliqué, définit une variable d'état qui est utilisée pour désactiver tous les clics ultérieurs sur ce bouton.
Ouvrez App.test.js
, qui est déjà créé par Create React App pour contenir un test pour le logo React par défaut. À la place, modifiez le test par défaut comme suit :
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import App from './App';
test('disabled button on click', () => {
const button = render(<App />).getByTestId('useless-button');
expect(button.disabled).toBeFalsy();
fireEvent.click(button, {button: 1});
expect(button.disabled).toBeTruthy();
});
Ce test rend le composant à l'aide des rendus de React Testing Library et trouve le bouton en fonction de l'ID de test que nous lui avons donné (bien qu'il existe de nombreux sélecteurs différents qui n'encombreront pas le code de votre composant). Il s'assure que le bouton n'est pas désactivé dès le départ, puis déclenche un événement de clic. (Notez que {button : 1}
est simplement le code pour le clic gauche.) L'état est mis à jour, ce qui déclenche un nouveau rendu, et nous vérifions à nouveau que le bouton est maintenant désactivé.
Il est important de toujours tester la sortie des fonctions. La plupart du temps, vous ne vous souciez pas exactement de la façon dont la fonction est implémentée sous le capot, juste qu'elle renvoie la sortie correcte. Ce composant est juste une fonction qui renvoie un bouton qui peut ou non être désactivé. Peu nous importe que le bouton utilise l'API d'état de React sous le capot, nous testons donc si le code HTML renvoyé contient ou non un bouton désactivé. Cela ne veut pas dire que vous ne pouvez pas tester l'état, mais vous devez déterminer si cela est nécessaire ou non.