• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/23/24

Allez plus loin dans vos tests

Allez plus loin dans vos tests

Qu'il s'agisse de Jest ou de React Testing Library, ces outils sont très puissants : ils permettent de simuler à peu près ce que l'on veut.

Dans notre application Shiny, la majeure partie de notre contenu vient des données que l'on récupère depuis une API (comme on aurait récupéré notre contenu depuis un CMS). Les calls API ne dérogent pas à la règle : les datas peuvent être simulées dans nos tests et on appelle ça des mocks (des simulations) ! Nous allons donc pouvoir tester nos autres composants. 🚀

Testez des composants qui font des calls API

Installez msw  pour faire vos simulations de calls API

Pour pouvoir simuler nos calls API, un peu de configuration s'impose à nous. Si, comme moi, vous n'aimez pas la config, ne vous inquiétez pas : je vous promets que ça ne durera pas trop longtemps !

Pour faire nos mocks, React Testing Library recommande d'utiliser une bibliothèque externe : MSW (pour Mock Service Worker), hébergée sur GitHub. On commence donc par installer la bibliothèque :

yarn add msw --dev

Pour faire simple, la bibliothèque msw  va permettre d'intercepter les calls API que font vos composants lors des tests. Et donc, elle permet de simuler ce qui aurait été retourné, sans même que votre application ait conscience de quoi que ce soit. Croyez-moi, c'est le 🔥.

Créez vos mocks

Pour cela, dans chacun de nos fichiers de test, on va devoir configurer un "server", qui va s'occuper de l'interception des calls API. Lançons-nous dès maintenant dans le test du composant de la page Freelances/index.jsx  . On crée donc un fichier dans /pages/Freelances  , qu'on appelle index.test.js  .

On va avoir besoin de rest  depuis msw  . On fait donc :

import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { render, waitFor, screen } from '@testing-library/react'
 
import Freelances from './'
 
const server = setupServer(
    // On précise ici l'url qu'il faudra "intercepter"
    rest.get('http://localhost:8000/freelances', (req, res, ctx) => {
        // Là on va pouvoir passer les datas mockées dans ce qui est retourné en json
        return res(ctx.json({}))
    })
)
 
// Active la simulation d'API avant les tests depuis server
beforeAll(() => server.listen())
// Réinitialise tout ce qu'on aurait pu ajouter en termes de durée pour nos tests avant chaque test
afterEach(() => server.resetHandlers())
// Ferme la simulation d'API une fois que les tests sont finis
afterAll(() => server.close())

Et voilà, c'est tout pour la configuration ! ✨

Mais… elle est où la data qu'on renvoie ?!

Très bien vu. Je ne l'avais pas encore mise. Il nous faut un format qui corresponde à ce que l'API nous renvoie. Si vous faites un console.log  de ce quehttp://localhost:8000/freelances  vous retourne, vous verrez que c'est une liste d'objets. On crée donc une liste d’objets pour notre mock :

const freelancersMockedData = [
    {
        name: 'Harry Potter',
        job: 'Magicien frontend',
        picture: '',
    },
    {
        name: 'Hermione Granger',
        job: 'Magicienne fullstack',
        picture: '',
    },
]

 ... qu'on retourne dans notre mock :

const server = setupServer(
    // On précise ici l'url qu'il faudra "intercepter"
    rest.get('http://localhost:8000/freelances', (req, res, ctx) => {
        // Là on va pouvoir passer les datas mockées dans ce qui est retourné en json
        return res(ctx.json({ freelancersList: freelancersMockedData }))
    })
)

Tout est prêt ! C'est maintenant le moment d'utiliser tout ça. 🔥

Exploitez vos mocks

Notre configuration est prête. On va pouvoir l'utiliser pour tester pages/Freelances/index.jsx  .

Mais avant de la tester, arrêtons-nous quelques instants sur notre stratégie de tests. Notre composant affiche un loader pendant qu'il fait la requête à l'API, puis affiche les données dans des composants Cards  . Dans un premier temps, on peut donc vérifier que : 

1- Le loader s'affiche bien pendant le call.

2- Notre première card  affiche bien les éléments récupérés dans le call avec le premier élément.

Commençons par nous occuper de la première étape. On sait que isLoading  est initialisé à true  , donc on peut tout simplement vérifier que notre Loader  apparaît bien.

Mais d'ailleurs, on fait comment ? Notre Loader  est une simple div  stylisée, il ne contient pas de texte ?

Je vous l'avais mentionné au chapitre précédent, c'est maintenant le moment d'utiliser data-testid  . On va tout simplement le préciser dans Freelances/index.jsx  :

<Loader theme={theme} data-testid="loader" />
```
Et dans notre test, on le récupère avec :
```
test('Should render without crash', async () => {
    render(
        <ThemeProvider>
            <Freelances />
        </ThemeProvider>
    )
    expect(screen.getByTestId('loader')).toBeTruthy()
})

Votre test se lance. Ça fonctionne. ✅

C'est bien beau, "ça fonctionne", mais qu'est-ce qui me dit que mon test n'est pas toujours bon ? Que ça fonctionne quoi qu'il arrive ?

Essayez de changer l' id  pour vous assurer que ça casse bien :

expect(screen.getByTestId('cetIdNeCorrespondÀRien')).toBeTruthy()

Notre test échoue bien.

On va maintenant tester avec nos datas. Pour cela, on va avoir besoin de waitFor  que je vous ai déjà fait importer juste avant depuis '@testing-library/react'  . Cette méthode permet de gérer du code asynchrone, comme pour un call API, par exemple. 😉 On n'oublie d'ailleurs pas d'ajouter un async devant le callback de notre test.

On va vérifier ici que notre code affiche bien les noms "Harry Potter" et "Hermione Granger". Pour cela, on a :

it('Should display freelancers names', async () => {
    render(
        <ThemeProvider>
            <Freelances />
        </ThemeProvider>
    )
    expect(screen.getByTestId('loader')).toBeTruthy()
    await waitFor(() => {
        expect(screen.getByText('Harry Potter')).toBeTruthy()
        expect(screen.getByText('Hermione Granger')).toBeTruthy()
    })
})

Encore une fois, vous pouvez modifier le texte, avec par exemple :

expect(screen.getByText('Harry PotDeBeurre')).toBeTruthy()

… et le test échoue ! 🔥

Maintenant que nous avons vu les mocks et une stratégie pour les tests, on se retrouve dans le screencast juste en dessous pour un autre exemple :

Personnalisez votre render

Bon, depuis tout à l'heure je vous fais utiliser votre Theme  directement dans vos tests. Ce n'est pas très propre. Surtout que si vous testez d'autres composants tels que Home  (comme je vous l'avais dit dans l'exercice du chapitre précédent), vous aurez aussi à le wrapper dans le router.

Mais ça tombe bien, puisque la fonction render de React Testing Library peut prendre en paramètre un wrapper.

Dans le test qu'on a fait juste au-dessus, on va donc déclarer un nouveau composant React, Wrapper  :

function Wrapper({ children }) {
    return <ThemeProvider>{children}</ThemeProvider>
}

Et on le réutilise en le passant en paramètre de notre render :

render(<Freelances />, { wrapper: Wrapper })

Et voilà ! 🎉

On peut même en faire un outil qu'on pourra réutiliser dans tous nos tests.

Pour cela, on crée un dossier /test  dans /utils  et on y met un fichier index.js  afin d'y mettre notre outil qui servira pour tous nos tests.

Ce qui nous donne :

import { render as rtlRender } from '@testing-library/react'
import { ThemeProvider } from '../../utils/context'
 
function Wrapper({ children }) {
    return <ThemeProvider>{children}</ThemeProvider>
}
 
export function render(ui) {
    rtlRender(ui, { wrapper: Wrapper })
}

Il ne nous reste plus qu'à importer notre nouveau render  dans notre /pages/Freelances/index.test.js  , et à supprimer render  des imports depuis '@testing-library/react'  .

…Et ça fonctionne comme on le souhaite ! 🎉

Puisqu'on en est là, autant en profiter pour gérer notre Router  et notre SurveyProvider  aussi. Si vous voulez explorer différentes options (et si vous avez besoin de faire des tests en ayant accès à votre history  ), vous pouvez regarder la documentation de React Testing Library (en anglais).

Mais dans notre cas, on veut juste que nos tests fonctionnent, même lorsqu'il y a des Link  dans nos composants. On transforme donc notre fichier pour ajouter notre Router  et  SurveyProvider  :

import { render as rtlRender } from '@testing-library/react'
import { ThemeProvider, SurveyProvider } from '../../utils/context'
import { MemoryRouter } from 'react-router-dom'
 
function Wrapper({ children }) {
    return (
        <MemoryRouter>
            <ThemeProvider>
                <SurveyProvider>{children}</SurveyProvider>
            </ThemeProvider>
        </MemoryRouter>
    )
}
 
export function render(ui) {
    rtlRender(ui, { wrapper: Wrapper })
}

En lançant le test, tout fonctionne comme prévu ! ✨

Découvrez d'autres types de tests

Vous avez appris à créer des tests unitaires avec Jest et à tester vos composants avec React Testing Library. Vous avez testé vos interactions et pu simuler des appels API. Mais vous vous en doutez peut-être : le sujet des tests est très vaste. Il existe de nombreux outils et de nombreuses approches.

Dans le screencast ci-dessous, je vous fais la démo d'une autre approche que nous n'avons pas vue ensemble. 👇

Je vous ai également mentionné les tests end-to-end. Nous ne les avons pas vus ensemble, mais ils constituent un outil très puissant. À l'heure actuelle, j'aurais tendance à vous conseiller d'utiliser la bibliothèque Cypress .

Comme pour tout le reste en JavaScript, les outils de tests évoluent rapidement. Pour rester à la page, je vous conseille de faire une veille, puis d'explorer la documentation des nouveaux outils.

Exercez-vous

C'est le moment de mettre en pratique ce que vous venez d'apprendre dans cette partie. Pour cela, vous allez devoir créer les tests pour Results/index.jsx  . Il vous faudra également mocker les données comme vous l'avez vu dans ce chapitre.

Comme d'habitude, le code pour commencer se trouve sur la branche P3C3-begin et la solution sur P3C3-solution.

En résumé

  • La bibliothèquemsw  facilite la simulation d'appels API depuis les tests, en permettant de configurer un server  qui nous permettra de retourner les datas "mockées" que l'on souhaite.

  • React Testing Library met à notre disposition des outils tels que waitFor  ,  qui permettent de tester nos composants après des calls API.

  • Il est possible de personnaliser le render  pour y inclure le Router  et des Providers  de Contexte.

  • Il existe d'autres types de tests, comme les tests end-to-end.

Bravo à vous ! Vous avez fini la partie de ce cours React sur les tests. 💪 C'est maintenant le moment de tester vos nouvelles connaissances avec un quiz. Bonne chance à vous, et on se retrouve très vite pour la quatrième et dernière partie de ce cours !

Example of certificate of achievement
Example of certificate of achievement