Les tests de logiciels sont essentiels pour garantir que vos applications fonctionnent comme prévu, en particulier lorsque vous introduisez des changements. La détection et la correction des erreurs dès le début du développement sont cruciales pour maintenir un code résistant et de haute qualité.

Parmi les nombreux outils et frameworks disponibles pour les tests JavaScript, Jest est l’un des plus populaires. Produit par Meta, Jest offre des capacités de test étendues pour les applications JavaScript et celles construites avec des frameworks JavaScript.

Nous allons explorer le framework Jest, ses fonctionnalités et la meilleure façon de l’intégrer dans votre flux de développement.

Qu’est-ce que Jest ?

Jest est un framework flexible et simple à utiliser. En plus de ses fonctionnalités principales de test JavaScript, il offre des configurations et des extensions pour tester les applications Babel, webpack, Vite, Parcel ou TypeScript.

Jest a été largement adopté par les développeurs et dispose d’un large éventail d’extensions développées et maintenues par la communauté. Il se distingue par sa facilité d’utilisation : Les tests JavaScript ne nécessitent aucune configuration ou extension supplémentaire. Mais vous pouvez également effectuer des tests plus avancés – comme les tests de frameworks JavaScript – en utilisant quelques options de configuration supplémentaires.

Comment configurer Jest pour votre projet JavaScript

Voyons comment configurer Jest dans un projet JavaScript existant.

Pré-requis

Pour suivre ce tutoriel, assurez-vous d’avoir les éléments suivants :

  • Node.js est installé.
  • npm (qui fait déjà partie de Node.js) ou Yarn installé.
  • Le paquet Jest npm est installé.

Installer le paquet Jest

  1. Si vous n’avez pas encore de projet pour suivre ce tutoriel, utilisez ce dépôt comme point de départ.

La branche starter-files vous donne une base pour construire l’application au fur et à mesure que vous suivez le tutoriel. Référencez la branche main pour voir le code de ce tutoriel et vérifier votre code.

  1. Pour installer Jest avec npm, allez dans le répertoire du projet dans votre terminal et exécutez la commande suivante :
npm install --save-dev jest

L’option --save-dev indique à npm d’installer le paquet sous devDependencies, qui contient les dépendances dont vous avez besoin pour le développement.

Configurer Jest

Bien que Jest fonctionne généralement sans configuration supplémentaire, il existe deux façons d’étendre sa puissance : dans le fichier package.json et via un fichier de configuration Jest.

Configurer Jest dans package.json

Dans votre fichier package.json, ajoutez un objet nommé jest avec les propriétés indiquées ci-dessous :

{
  …
  "jest": {
    "displayName": "Ecommerce",
    "globals": {
      "PROJECT_NAME": "Ecommerce TD"
    },
    "bail": 20,
    "verbose": true
  },
}

Pendant le test, Jest recherche cet objet et applique ces configurations. Vous pouvez voir des options supplémentaires sur la page de configuration de Jest, mais les propriétés de cet objet sont les suivantes :

  • displayName – Jest ajoute la valeur de cette propriété en tant qu’étiquette à vos résultats de test.
  • globals – Détient une valeur d’objet pour définir les variables globales disponibles dans vos environnements de test.
  • bail – Par défaut, Jest exécute tous les tests et affiche les erreurs dans les résultats. bail indique à Jest d’arrêter l’exécution après un certain nombre d’échecs.
  • verbose – Lorsqu’il est défini sur true, il affiche les rapports de test individuels pendant l’exécution du test.

Configurer Jest dans un fichier de configuration

Vous pouvez également configurer Jest dans un fichier jest.config.js. Jest supporte également les extensions .ts, .mjs, .cjs et .json. Lors de l’exécution des tests, Jest recherche ces fichiers et applique les paramètres du fichier qu’il trouve.

Par exemple, considérez ce fichier jest.config.js:

const config = {
  displayName: "Ecommerce",
  globals: {
    "PROJECT_NAME": "Ecommerce TD"
  },
  bail: 20,
  verbose: true
}

module.exports = config;

Le code exporte un objet de configuration Jest avec les mêmes propriétés que dans l’exemple précédent.

Vous pouvez également utiliser un fichier personnalisé qui contient un objet de configuration sérialisable en JSON et transmettre le chemin du fichier à l’option --config lors de l’exécution de vos tests.

Créer un fichier de test de base

Une fois Jest configuré, créez vos fichiers de test. Jest examine les fichiers de test de votre projet, les exécute et fournit les résultats. Les fichiers de test suivent généralement un format tel que [nom].test.js ou [nom]-test.js. Ce modèle permet à Jest et à votre équipe d’identifier facilement vos fichiers de test.

Considérez un fichier string-format.js qui contient le code suivant :

function truncate(
  str,
  count,
  withEllipsis = true
) {
  if (str.length < = count)
    return str

  const substring = str.substr(0, count)

  if (!withEllipsis)
    return substring

  return substring + '...'
}

module.exports = { truncate }

La fonction truncate() tronque les chaînes de caractères à une longueur particulière avec la possibilité d’ajouter une ellipse.

Écrire le test

  1. Créez un fichier de test nommé string-format.test.js.
  1. Pour garder vos fichiers organisés, placez string-format.test.js dans le même répertoire que le fichier string-format.js ou dans un répertoire de test spécifique. Quel que soit l’emplacement de votre fichier de test dans le projet, Jest le trouve et l’exécute. Avec Jest, vous pouvez tester vos applications dans différents scénarios.
  2. Écrivez un test de base dans string-format.test.js comme suit :
const { truncate } = require('./string-format')

test('truncates a string correctly', () = > {
  expect(truncate("I am going home", 6)).toBe('I am g...')
})

Le cas de test a la description suivante : truncates a string correctly. Ce code utilise la fonction expect fournie par Jest, qui teste si une valeur correspond au résultat attendu.

Le code passe truncate("I am going home", 6) comme argument à expect. Ce code teste la valeur renvoyée par l’appel à truncate avec les arguments "I am going home" et 6. L’appel à expect renvoie un objet expectation, qui permet d’accéder aux correspondances de Jest.

Il contient également le matcheur toBe, qui a pour argument "I am g…". Le matcheur toBe teste l’égalité entre les valeurs attendues et les valeurs réelles.

Exécuter le test

Pour exécuter vos tests, définissez la commande jest.

  1. Dans le fichier package.json de votre projet, ajoutez ce script test:
"scripts": {
  "test": "jest"
}
  1. Exécutez maintenant npm run test, npm test, ou npm t dans votre terminal. Il exécute Jest pour le projet.

Lorsque vous exécutez les tests, voici le résultat :

Résultat positif du test Jest pour string-format.test.js.
Résultat positif du test Jest pour string-format.test.js.

Les résultats montrent une suite de tests (le fichier string-format.test.js), un test exécuté avec succès ("truncates a string correctly"), et le displayName (Ecommerce) que vous avez défini dans la configuration.

  1. Dans string-format.js, si vous ajoutez un point supplémentaire pour casser le code et exécuter le test, celui-ci échoue :
Le résultat du test Jest a échoué à cause d'une fonction truncate défectueuse.
Le résultat du test Jest a échoué à cause d’une fonction truncate défectueuse.

Ce résultat suggère que vous avez cassé la fonction truncate ou que vous avez fait des mises à jour qui nécessitent une mise à jour des tests.

Comment écrire des tests avec Jest

Syntaxe des tests Jest

La syntaxe propriétaire de Jest est simple à utiliser. Jest expose des méthodes et des objets globaux à votre projet pour écrire des tests. Certains de ses termes fondamentaux sont describe, test, expect, et matchers.

  • describe: Cette fonction regroupe les tests apparentés dans un fichier.
  • test: Cette fonction exécute le test. C’est un alias de it. Elle contient des assertions pour les valeurs que vous souhaitez tester.
  • expect: Cette fonction déclare les assertions pour diverses valeurs. Elle permet d’accéder à des outils d’appariement pour différentes formes d’assertions.
  • Correspondants : Ils vous permettent d’affirmer une valeur de différentes manières. Vous pouvez affirmer l’égalité des valeurs, l’égalité booléenne et l’égalité contextuelle (par exemple, si un tableau contient la valeur).

Pour les utiliser, considérez l’exemple suivant :

  1. Remplacez le test du fichier string-format.test.js par le code suivant :
describe("all string formats work as expected", () = > {
  test("truncates a string correctly", () = > {
    expect(
      truncate("I am going home", 6)
    ).toBe("I am g...")
  })
})
  1. Exécutez le code.

Le résultat ressemble à ce qui suit :

Résultat d'un test Jest réussi montrant la chaîne describe.
Résultat d’un test Jest réussi montrant la chaîne describe.

La capture d’écran montre que la chaîne de la fonction describe crée un bloc. Bien que describe soit facultatif, il est utile de regrouper les tests dans un fichier avec plus de contexte.

Organiser les tests en suites de tests

Dans Jest, un scénario de test se compose de la fonction test, de la fonction expect et d’un matcher. Une collection de cas de test apparentés constitue une suite de tests. Dans l’exemple précédent, string-format.test.js est une suite de tests comprenant un scénario de test pour tester le fichier string-format.js.

Supposons que vous ayez d’autres fichiers dans votre projet, comme file-operations.js, api-logger.js et number-format.js. Vous pouvez créer des suites de tests pour ces fichiers, comme file-operations.test.js, api-logger.test.js, et number-format.test.js.

Écrire des assertions simples avec Jest Matchers

Nous avons exploré un exemple d’utilisation du matcher toBe. Les assertions avec d ‘autres matchers Jest incluent :

  • toEqual – Pour tester l’égalité « profonde » dans les instances d’objets.
  • toBeTruthy – Pour tester si une valeur est true dans un contexte booléen.
  • toBeFalsy – Pour tester si une valeur est false dans un contexte booléen.
  • toContain – Pour tester qu’un tableau contient une valeur.
  • toThrow – Pour tester qu’une fonction invoquée provoque une erreur.
  • stringContaining – Pour tester qu’une chaîne de caractères contient une sous-chaîne.

Explorons des exemples utilisant certains de ces outils d’appariement.

Vous pouvez, par exemple, vous attendre à ce qu’une fonction ou un code renvoie un objet avec des propriétés et des valeurs spécifiques.

  1. Utilisez l’extrait de code ci-dessous pour tester cette fonctionnalité. Dans ce cas, vous souhaitez affirmer que l’objet retourné est égal à l’objet attendu.
expect({
  name: "Joe",
  age: 40
}).toBe({
  name: "Joe",
  age: 40
})

Cet exemple utilise toBe. Le test échoue car ce matcheur ne vérifie pas l’égalité en profondeur – il vérifie la valeur, et non toutes les propriétés.

  1. Utilisez l’outil de recherche toEqual pour vérifier l’égalité profonde :
expect({
  name: "Joe",
  age: 40
}).toEqual({
  name: "Joe",
  age: 40
})

Ce test est réussi car les deux objets sont « profondément égaux », ce qui signifie que toutes leurs propriétés sont égales.

  1. Essayez un autre exemple de matcher qui teste si le tableau défini contient un élément spécifique.
expect(["orange", "pear", "apple"]).toContain("mango")

Ce test échoue parce que toContain affirme que le tableau ["orange", "pear", "apple"] contient une valeur attendue "mango", mais le tableau n’en contient pas.

  1. Utilisez des variables pour le même test qu’avec le code ci-dessous :
const fruits = ["orange", "pear", "apple"];
const expectedFruit = "mango";

expect(fruits).toContain(expectedFruit)

Tester le code asynchrone

Jusqu’à présent, nous avons testé du code synchrone – des expressions qui renvoient une valeur avant que le code n’exécute la ligne suivante. Vous pouvez également utiliser Jest pour du code asynchrone avec async, await, ou Promises.

Par exemple, le fichier apis.js contient une fonction permettant d’effectuer une demande d’API:

function getTodos() {
  return fetch('https://jsonplaceholder.typicode.com/todos/1')
}

La fonction getTodos envoie une requête GET à https://jsonplaceholder.typicode.com/todos/1.

  1. Créez un fichier nommé apis.test.js avec le code suivant pour tester la fausse API:
const { getTodos } = require('./apis')

test("gets a todo object with the right properties", () = > {
  return getTodos()
    .then((response) = > {
      return response.json()
    })
    .then((data) = > {
      expect(data).toHaveProperty('userId')
      expect(data).toHaveProperty('id')
      expect(data).toHaveProperty('title')
      expect(data).toHaveProperty('completed')
      expect(data).toHaveProperty('description')
    })
})

Ce scénario de test invoque la fonction getTodos qui récupère un objet todo. Lorsqu’il résout la promesse, il utilise la méthode .then pour obtenir la valeur résolue.

Dans cette valeur, le code renvoie response.json(), qui est une autre promesse qui convertit la réponse au format JSON. Une autre méthode .then permet d’obtenir l’objet JSON contenant les expect et les matchers. Le code affirme que l’objet JSON comprend cinq propriétés : userId, id, title, completed, et description.

  1. Exécuter les tests :
Résultat du test Jest montrant l'échec du test pour le code asynchrone.
Résultat du test Jest montrant l’échec du test pour le code asynchrone.

Comme le montre la capture d’écran, le test pour getTodos() échoue. Il attend la propriété description, mais l’API ne la renvoie pas. Grâce à ces informations, vous pouvez maintenant demander à l’équipe de gestion de l’API de votre entreprise d’inclure cette propriété si l’application en a besoin ou de mettre à jour les tests pour qu’ils correspondent à la réponse de l’API.

  1. Supprimez l’assertion pour la propriété description et réexécutez les tests :
Résultat du test Jest montrant un test réussi pour le code asynchrone.
Résultat du test Jest montrant un test réussi pour le code asynchrone.

La capture d’écran montre que tout a passé le test.

  1. Essayez maintenant d’utiliser async/await au lieu de la gestion traditionnelle des promesses :
test("gets a todo object with the right properties", async () = > {
  const response = await getTodos()
  const data = await response.json()

  expect(data).toHaveProperty("userId")
  expect(data).toHaveProperty("id")
  expect(data).toHaveProperty("title")
  expect(data).toHaveProperty("completed")
})

Le mot-clé async est maintenant placé avant la fonction. Le code utilise await avant getTodos() et await avant response.json().

Fonctionnalités avancées de Jest

Fonctions et modules fictifs

Vous pouvez vouloir tester une expression avec des dépendances externes lorsque vous écrivez des tests. Dans certains cas, en particulier les tests unitaires, vos tests unitaires doivent être isolés des effets externes. Dans ce cas, vous pouvez simuler vos fonctions ou modules avec Jest pour mieux contrôler vos tests.

  1. Par exemple, considérez un fichier functions.js qui contient le code suivant :
function multipleCalls(count, callback) {
  if (count < 0) return;

  for (let counter = 1; counter <= count; counter++) {
    callback()
  }
}

La fonction multipleCalls est exécutée en fonction de la valeur de count. Elle dépend de la fonction de rappel – la dépendance externe. Son but est de savoir si multipleCalls exécute correctement la dépendance externe.

  1. Pour simuler la dépendance externe et suivre son état dans votre fichier de test, functions.test.js, utilisez ce code :
const { multipleCalls } = require('./functions')

test("functions are called multiple times correctly", () => {
  const mockFunction = jest.fn()

  multipleCalls(5, mockFunction)

  expect(
    mockFunction.mock.calls.length
  ).toBe(5)
})

Ici, la méthode fn de l’objet jest crée une fonction fictive. Ensuite, le code exécute multipleCalls en passant 5 et la fonction fictive comme arguments. Il affirme ensuite que la méthode mockFunction est appelée cinq fois. La propriété mock contient des informations sur la façon dont le code appelle la fonction et les valeurs renvoyées.

  1. Lorsque vous exécutez le test, le résultat attendu est le suivant :
Résultat d'un test Jest réussi avec une fonction fictive.
Résultat d’un test Jest réussi avec une fonction fictive.

Comme vous pouvez le constater, le code appelle le site mockFunction cinq fois.

Dans le code, la fonction fictive imite une dépendance externe. La nature de la dépendance externe importe peu lorsque l’application utilise multipleCalls en production. Votre test unitaire ne se préoccupe pas de la façon dont la dépendance externe fonctionne. Il vérifie simplement que multipleCalls fonctionne comme prévu.

  1. Pour simuler des modules, utilisez la méthode mock et passez un chemin de fichier, qui est le module :
const {
  truncate,
} = require("./string-format")

jest.mock("./string-format.js")

Ce code imite toutes les fonctions exportées par string-format.js et vérifie combien de fois il les appelle. L’adresse truncate du module devient une fonction fictive, ce qui fait perdre à la fonction sa logique d’origine. Vous pouvez savoir combien de fois truncate s’exécute dans vos tests dans la propriété truncate.mock.calls.length.

Si vous avez une erreur ou si votre code ne fonctionne pas, comparez votre code avec l’implémentation complète.

Tester les composants React avec Jest et la bibliothèque de test React

Si vous n’avez pas encore de projet pour suivre ce tutoriel, vous pouvez utiliser ce projet d’exemple React comme point de départ. La branche starter-files vous permet de commencer à composer le code au fur et à mesure que vous suivez le tutoriel. Utilisez la branche main comme référence pour vérifier votre code par rapport au code complet de ce tutoriel.

Vous pouvez utiliser Jest pour tester des frameworks JavaScript tels que React. Lorsque vous créez des projets React à l’aide de Create React App, ils prennent en charge la React Testing Library et Jest dès le départ. Si vous créez un projet React sans Create React App, installez Jest pour tester React avec Babel et la bibliothèque de test React. Si vous clonez la branche starter-app, vous n’avez pas besoin d’installer des dépendances ou d’appliquer des configurations.

  1. Si vous utilisez le projet d’exemple, utilisez cette commande pour installer les dépendances nécessaires :
npm install --save-dev babel-jest @babel/preset-env @babel/preset-react react-testing-library

Vous pouvez également utiliser Enzyme à la place de React Testing Library.

  1. Mettez à jour vos configurations Babel dans babel.config.js ou créez ce fichier s’il n’existe pas :
module.exports = {
  presets: [
    '@babel/preset-env',
      ['@babel/preset-react', {runtime: 'automatic'}],
  ],
};
  1. Considérez le fichier src/SubmitButton.js qui contient le code suivant :
import React, { useState } from 'react'

export default function SubmitButton(props) {
  const {id, label, onSubmit} = props
  const [isLoading, setisLoading] = useState(false)

  const submit = () => {
    setisLoading(true)
    onSubmit()
  }

  return 

Ce composant SubmitButton reçoit trois accessoires :

  • id – L’identifiant du bouton.
  • label – Le texte à afficher dans le bouton.
  • onSubmit – La fonction à déclencher lorsque quelqu’un clique sur le bouton.

Le code attribue la propriété id à l’attribut data-testid, qui identifie un élément à tester.

Le composant suit également l’état isLoading et le met à jour à true lorsque quelqu’un clique sur le bouton.

  1. Créez le test pour ce composant. Placez le code suivant dans un fichier SubmitButton.test.js:
import {fireEvent, render, screen} from "@testing-library/react"
import "@testing-library/jest-dom"
import SubmitButton from "./SubmitButton"

test("SubmitButton becomes disabled after click", () => {
  const submitMock = jest.fn()

  render(
    <SubmitButton
      id="submit-details"
      label="Submit"
      onSubmit={submitMock}
    / >
  )

  expect(screen.getByTestId("submit-details")).not.toBeDisabled()

  fireEvent.submit(screen.getByTestId("submit-details"))

  expect(screen.getByTestId("submit-details")).toBeDisabled()
})

Le code ci-dessus rend le composant SubmitButton et utilise la méthode de requête screen.getByTestId pour obtenir le nœud du DOM par l’attribut data-testid.

Le premier expect est getByTestId("submit-details") et utilise le modificateur not et le comparateur toBeDisabled (exposé à partir de react-testing-library) pour affirmer que le bouton n’est pas désactivé. Utilisez le modificateur not avec tous les matcheurs pour affirmer l’opposé du matcheur.

Ensuite, le code déclenche l’événement submit sur le composant et vérifie que le bouton est désactivé. Vous pouvez trouver d’autres adaptateurs personnalisés dans la documentation de la bibliothèque de tests.

  1. Maintenant, exécutez les tests. Si vous avez cloné la branche starter-files, assurez-vous que toutes les dépendances du projet sont installées en exécutant npm install avant de lancer vos tests.

Résultat d'un test Jest montrant que le test d'un composant react a réussi.
Résultat d’un test Jest montrant que le test d’un composant react a réussi.

Exécuter des rapports de couverture de code

Jest propose également des rapports de couverture de code pour montrer la part de votre projet que vous testez.

  1. Passez l’option --coverage à Jest. Dans votre script Jest dans package.json (dans le projet JavaScript), mettez à jour la commande Jest avec cette option de couverture :
"scripts": {
  "test": "jest --coverage"
}
  1. Exécutez npm run test pour tester votre code. Vous obtenez un rapport comme le suivant :
Rapport de couverture Jest pour chaque combinaison de test.
Rapport de couverture Jest pour chaque combinaison de test.

Ce rapport montre que Jest a testé 100% des fonctions dans

SubmitButton.j s et string-format.js. Il indique également que Jest n’a pas testé de déclarations et de lignes dans string-format.js. La couverture des tests montre que les lignes non couvertes dans string-format.js sont 7 et 12.

À la ligne 7, return str dans la fonction truncate ne s’exécute pas parce que la condition if (str.length <= count) renvoie false.

À la ligne 12, toujours dans la fonction truncate, return substring ne s’exécute pas car la condition if (!withEllipsis) renvoie false.

Intégrer Jest à votre flux de développement

Voyons comment vous pouvez intégrer ces tests pour améliorer votre flux de développement.

Exécutez les tests en mode veille

Au lieu d’exécuter les tests manuellement, vous pouvez les exécuter automatiquement lorsque vous modifiez votre code en utilisant le mode de surveillance.

  1. Pour activer le mode veille, mettez à jour votre script de commande Jest dans package.json (dans le projet JavaScript) en ajoutant l’option --watchAll:
"scripts": {
  "test": "jest --coverage --watchAll"
}
  1. Exécutez npm run test. Il déclenche Jest en mode veille :
Exécution de Jest en mode veille.
Exécution de Jest en mode veille.

Les tests s’exécutent à chaque fois que vous modifiez votre projet. Cette approche favorise un retour d’information continu au fur et à mesure que vous construisez votre application.

Mettre en place des hooks de pré-commit

Dans les environnements Git, les hooks exécutent des scripts à chaque fois qu’un événement particulier se produit (comme pull, push ou commit). Les hooks de pré-commit définissent les scripts à exécuter pour l’évènement de pré-commit (que le code déclenche avant d’effectuer une validation).

La validation ne réussit que si le script ne génère pas d’erreur.

L’exécution de Jest avant le pre-commit garantit qu’aucun de vos tests n’échoue avant la validation.

Vous pouvez utiliser diverses bibliothèques pour mettre en place des hooks git dans votre projet, comme ghooks.

  1. Installez ghooks sous devDependencies:
npm install ghooks --save-dev
  1. Ajoutez un objet configs au niveau supérieur de votre fichier package.json (dans le projet JavaScript).
  2. Ajoutez un objet ghooks sous configs.
  1. Ajoutez une propriété dont la clé est pre-commit et la valeur jest.
{
  …
  "config": {
    "ghooks": {
      "pre-commit": "jest"
    }
  },
}
  1. Validez le code. Le code déclenche le hook pre-commit, qui exécute Jest :

Exécuter Jest pendant le pre-commit en utilisant les ghooks.
Exécuter Jest pendant le pre-commit en utilisant les ghooks.

Résumé

Vous savez maintenant comment intégrer Jest dans votre flux de développement pour qu’il s’exécute automatiquement chaque fois que vous effectuez une modification. Cette approche permet un retour d’information continu afin que vous puissiez corriger rapidement tout problème de code avant de mettre vos modifications en production.

En hébergeant votre application chez Kinsta, vous bénéficiez d’une infrastructure rapide et sécurisée, déployant vos projets sur une infrastructure construite sur le réseau Premium Tier et les machines C2 de Google Cloud Platform. Choisissez entre les 37 centres de données et un CDN compatible HTTP/3 avec 260+ PoP.

Restez en sécurité grâce à la technologie des conteneurs isolés, à deux pare-feu puissants et à une protection DDoS avancée alimentée par Cloudflare. Et vous pouvez intégrer des applications ou automatiser des flux de travail avec l’API Kinsta.

Configurez Jest et parcourez les ressources de Kinsta dès aujourd’hui pour améliorer vos applications JavaScript.

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.