Découverte
Notions avancées
Les hooks
Notions avancées
TP
TP Recettes: AuthentificationRéservé aux membres premiums
30 min
TP Recettes: Récupération des ingrédientsRéservé aux membres premiums
38 min
TP Recettes: Gestion des ingrédientsRéservé aux membres premiums
29 min
TP Recettes: Gestion des recettesRéservé aux membres premiums
39 min
TP Recettes: Création d'une recetteRéservé aux membres premiums
47 min
TP Recettes: Edition d'une recetteRéservé aux membres premiums
25 min
Conclusion
Conclusion
04 min

Dans ce chapitre je vous propose de découvrir ensemble comment tester vos composants React à l'aide de la librairie Jest et de Testing Library. Tester permet de s'assurer que les composants fonctionnent comme attendu et permet aussi d'éviter d'introduire des bugs lors que l'on effectue un refactoring.

Environnement de test

Avec create-react-app

Si vous utilisez le template create-react-app vous n'avez pas grand chose à faire étant donné que l'environnement de test est déjà configuré pour vous. Il vous suffit de lancer la commande npm run test pour lancer les tests. Vous pouvez vous inspirer du fichier App.test.js pour voir à quoi ressemble un test par défaut.

Sans create-react-app

Cependant si on utilise react dans un projet qui n'utilise pas ce template il est important d'être en mesure de configurer les choses soi-même. Pour tester le code nous allons avoir besoin de plusieurs éléments

  • Jest, qui servira de framework de test (test runner + assertions)
  • Babel, qui permettra de convertir le code JSX en code JavaScript qui pourra être compris par Node (via les presets @babel/preset-env et @babel/preset-react).
  • Testing Library, qui nous offrira des helpers pour monter / démonter facilement nos éléments et qui ajoutera des assertions sur le DOM.

On commence donc par installer les différentes librairies

npm i jest  @types/jest babel-jest @babel/preset-env @babel/preset-react @testing-library/dom @testing-library/jest-dom @testing-library/react --save-dev 

On crée ensuite notre configuration babel via un fichier babel.config.js à la racine de notre projet :

module.exports = {
    presets: ['@babel/preset-env', '@babel/preset-react']
}

On configure aussi jest via un fichier jest.config.js pour ajouter les assertions du DOM

module.exports = {
    setupFilesAfterEnv: [
        './src/setupTest.js'
    ]
}

Et dans le fichier setupTest.js on charge étend expect

import '@testing-library/jest-dom/extend-expect'

Maintenant vous pouvez lancer vos tests en utilisant la commande npx jest.

Ecrire son premier test

Tester un composant

Pour écrire un test il suffit de monter un composant puis de voir que la structure est bien celle attendue (on testera souvent la présence d'un élément ou de texte). Même si on manipule le DOM il n'est pas nécessaire d'avoir recours à un navigateur car nos tests vont se reposer sur jsdom une implémentation des standards qui fonctionne directement sur NodeJS. Cependant, pour des cas plus spécifiques vous pourriez avoir besoin d'outil comme jest-puppeteer pour intéragir avec un environnement plus réel.

import { Modal } from './Modal'
import { render, fireEvent } from '@testing-library/react'
import React from 'react'
import { screen } from '@testing-library/dom'

test("Le titre devrait s'afficher", function () {
    render(<Modal title="Bonjour les gens" onClose={() => null}>Bonjour</Modal>)
    const title = screen.getByText('Bonjour les gens')
    expect(title).toBeInTheDocument()
})

test('Le callback de fermeture est appelé lors du clic sur x', function () {
    const mockClose = jest.fn()
    render(<Modal title="Bonjour les gens" onClose={mockClose}>Bonjour</Modal>)
    const close = document.body.querySelector("[aria-label='Fermer']")
    fireEvent.click(close)
    expect(mockClose.mock.calls.length).toBe(1)
})

test('Le callback de fermeture est appelé avec échap', function () {
    const mockClose = jest.fn()
    render(<Modal title="Bonjour les gens" onClose={mockClose}>Bonjour</Modal>)
    fireEvent.keyDown(document, { key: 'Escape' })
    expect(mockClose.mock.calls.length).toBe(1)
})

test("Le callback de fermeture n'est pas appelé avec une autre touché qu'échap", function () {
    const mockClose = jest.fn()
    render(<Modal title="Bonjour les gens" onClose={mockClose}>Bonjour</Modal>)
    fireEvent.keyDown(document, { key: 'Enter' })
    expect(mockClose.mock.calls.length).toBe(0)
})

Tester un hook

Les hooks permettent de représenter les changements d'états et peuvent parfois contenir une logique que l'on va souhaiter tester. Malheureusement, un hook ne peut pas être appelé directement et il nous faudra un environnement spécial pour pouvoir les éxécuter. Vous pouvez utiliser @testing-library/react-hooks pour cela.

npm i @testing-library/react-hooks react-test-renderer --save-dev

Ensuite il vous suffit d'utiliser les méthodes renderHook() et act() lorsque vous interagissez avec votre hook personnalisé.

import { useToggle } from "./hooks"
import { renderHook, act } from '@testing-library/react-hooks'

// Le hook fonctionne comme cela
// const [visible, toggleVisible] = useToggle(false)
test('toggleHook', function () {
    const { result } = renderHook(() => useToggle(false))
    // result.current contiendra le retour du hook
    expect(result.current[0]).toBeFalsy()
    act(() => result.current[1]())
    expect(result.current[0]).toBeTruthy()
    act(() => result.current[1]())
    expect(result.current[0]).toBeFalsy()
})