
Rendu de composants (`render`)
Apprenez comment utiliser la fonction `render` de React Testing Library (RTL) pour monter vos composants React dans un environnement de test et démarrer vos assertions.
Le point d'entrée : La fonction `render`
Au coeur de React Testing Library (RTL) se trouve la fonction `render`. C'est la toute première étape dans la plupart de vos tests de composants React. Son rôle principal est simple mais fondamental : prendre un élément React (généralement votre composant avec ses props) et le monter dans un environnement DOM simulé (fourni par jsdom lorsque vous utilisez Jest) afin que vous puissiez ensuite interagir avec lui et vérifier son comportement.
Sans `render`, vous n'auriez aucun moyen d'inspecter le résultat DOM de votre composant ni de simuler des interactions utilisateur. C'est donc la porte d'entrée indispensable pour appliquer la philosophie de RTL et tester vos composants tels qu'ils apparaissent et se comportent pour l'utilisateur final.
L'utilisation la plus basique est directe : vous importez `render` depuis `@testing-library/react` et vous l'appelez en lui passant le JSX de votre composant.
import React from 'react';
import { render } from '@testing-library/react';
import Greeting from './Greeting';
test('renders the greeting message', () => {
// On appelle render avec le composant Greeting et ses props
render( );
// A partir d'ici, le composant est rendu dans le DOM virtuel
// et nous pouvons commencer à utiliser les requêtes (queries)
// pour trouver des éléments et faire des assertions.
});Que retourne la fonction `render` ?
La fonction `render` retourne un objet contenant plusieurs propriétés et fonctions utiles pour interagir avec le composant rendu. Voici les plus importantes :
- Les Fonctions de Requête (Queries) : L'objet retourné inclut toutes les fonctions de requête de RTL (`getByText`, `queryByRole`, `findByAltText`, `getAllByTestId`, etc.) pré-liées au conteneur (`container`) du composant rendu. Par exemple, `const { getByText } = render(
); const element = getByText('Hello');`. Cependant, comme nous le verrons, l'utilisation de l'objet global `screen` est aujourd'hui la pratique recommandée. - `container` : Le noeud DOM racine (`HTMLDivElement`) dans lequel votre composant a été rendu. Vous pourriez l'utiliser pour des requêtes DOM très spécifiques ou pour des tests de snapshots, mais RTL encourage à éviter autant que possible les interactions directes avec `container`.
- `baseElement` : L'élément `` du DOM virtuel. Utile principalement si votre composant utilise des Portails React pour rendre des éléments en dehors de son `container` direct.
- `rerender` : Une fonction qui permet de mettre à jour le composant rendu avec de nouvelles props. Très utile pour tester comment un composant réagit aux changements de props. Exemple : `const { rerender } = render(
); rerender( );`. - `unmount` : Une fonction pour démonter le composant de l'arbre DOM. Utile pour tester la logique de nettoyage dans les `useEffect` (par exemple, désabonner des écouteurs d'événements).
- `asFragment` : Retourne un `DocumentFragment` contenant le DOM rendu. Principalement utilisé pour les tests de snapshots, offrant une alternative plus ciblée que le snapshot du `container` entier.
La meilleure pratique : Utiliser l'objet `screen`
Bien que `render` retourne les fonctions de requête, la manière moderne et recommandée d'interroger le DOM dans vos tests RTL est d'utiliser l'objet global `screen`, également importé depuis `@testing-library/react`. Cet objet expose les mêmes fonctions de requête (`screen.getByText`, `screen.queryByRole`, etc.), mais elles opèrent sur l'ensemble du `document.body` du DOM virtuel.
Pourquoi préférer `screen` ?
- Alignement avec la philosophie : Cela renforce l'idée de tester comme un utilisateur, qui voit l'ensemble de l'écran (le `body`) et non juste un conteneur spécifique.
- Moins de code répétitif : Vous n'avez pas besoin de déstructurer les fonctions de requête depuis le retour de `render` dans chaque test. Importez `screen` une fois et utilisez-le partout.
- Tests plus robustes : Vos requêtes ne sont pas liées à la structure interne du `container` retourné par `render`, ce qui peut changer.
Voici l'exemple précédent réécrit avec `screen` :
import React from 'react';
import { render, screen } from '@testing-library/react'; // Importer screen
import Greeting from './Greeting';
test('renders the greeting message using screen', () => {
render( ); // On appelle toujours render
// On utilise screen pour trouver l'élément
const greetingElement = screen.getByText(/hello, world/i); // Recherche insensible à la casse
expect(greetingElement).toBeInTheDocument();
});En résumé : appelez `render()` pour monter votre composant, puis utilisez `screen` pour toutes vos requêtes d'éléments.
Options de `render` : Le `wrapper`
La fonction `render` accepte un deuxième argument optionnel : un objet d'options. L'option la plus fréquemment utilisée est `wrapper`. Elle vous permet de fournir un composant qui enveloppera le composant que vous testez lors du rendu.
C'est essentiel lorsque votre composant testé dépend d'un contexte fourni par un Provider plus haut dans l'arbre (comme un `ThemeProvider`, un `Provider` Redux, ou le `Router` de React Router). Sans ce wrapper, le composant planterait car le contexte requis serait manquant.
Exemple avec un `ThemeProvider` :
import React from 'react';
import { render, screen } from '@testing-library/react';
import { ThemeProvider, useTheme } from './ThemeContext'; // Votre contexte de thème
import ThemedButton from './ThemedButton';
// Le composant à tester qui consomme le contexte
function ThemedButton() {
const { theme } = useTheme();
return ;
}
// Le test
test('renders button with theme class', () => {
// On définit le wrapper qui fournira le contexte
const AllTheProviders = ({ children }) => {
return (
{children}
);
};
// On passe le wrapper dans les options de render
render( , { wrapper: AllTheProviders });
const button = screen.getByRole('button');
expect(button).toHaveClass('dark');
});Créer des wrappers personnalisés pour chaque test peut être répétitif. Il est courant de créer une fonction `renderWithProviders` réutilisable dans vos utilitaires de test qui inclut tous les providers communs de votre application.
Nettoyage automatique (Automatic Cleanup)
Une chose importante à savoir est que React Testing Library, lorsqu'elle est utilisée avec des frameworks comme Jest, Mocha ou Vitest et correctement configurée (ce qui est le cas par défaut avec CRA ou Vite), effectue un nettoyage automatique après chaque test (`afterEach`).
Ce nettoyage appelle la fonction `cleanup` de RTL, qui démonte tous les composants qui ont été rendus avec `render` pendant le test. Cela garantit que chaque test s'exécute dans un environnement DOM propre, sans interférence des rendus des tests précédents. Vous n'avez donc généralement pas besoin d'appeler `cleanup` manuellement.