Tests
Génération des tests de vues
La génération de vues permet également de générer automatiquement des tests unitaires sur les fichiers JSX.
Ces tests sont générés à partir des données déclarées dans les fichiers de configuration YAML des vues. Ils permettent de vérifier le rendu des composants, le bon chargement des données et certaines interactions utilisateur.
Principe général
Pour chaque fichier de vue View.jsx, un fichier de test associé est généré.
Le fichier de test suit généralement le format suivant :
Ce fichier peut contenir tout ou partie des tests associés à la vue.
Il est également possible de découper les tests en plusieurs fichiers afin de les organiser par domaine fonctionnel, par exemple :
- tests dâaffichage ;
- tests dâactions utilisateur ;
- tests de mutations GraphQL ;
- tests spécifiques à un parcours métier.
Mise à jour des tests générés
Lorsquâun fichier .yml de configuration de vue est modifiĂ©, il est nĂ©cessaire de supprimer le fichier de test associĂ© avant de relancer la commande suivante :
Cette suppression permet de régénérer un fichier de test cohérent avec la nouvelle configuration de la vue.
Configuration utilisée
Les tests gĂ©nĂ©rĂ©s sâappuient sur les configurations de base prĂ©sentes dans le starter.
Ils utilisent notamment :
- un environnement GraphQL ;
- les providers de test du projet ;
- MSW pour intercepter et mocker les appels REST et GraphQL ;
- React Testing Library pour le rendu et les interactions avec le composant ;
- userEvent pour simuler les actions utilisateur.
Structure dâun fichier de test gĂ©nĂ©rĂ©
Les fichiers de tests générés comportent plusieurs éléments.
beforeAll
Le bloc beforeAll permet dâinitialiser lâenvironnement GraphQL.
Cet environnement est ensuite transmis aux providers de test, notamment au RelayEnvironmentProvider.
setupServer
La fonction setupServer permet de configurer les mocks nécessaires aux tests.
Elle sert notamment Ă mocker :
- les appels GraphQL ;
- les appels REST ;
- les queries utilisées par la vue ;
- les mutations déclenchées par les actions utilisateur.
La fonction setupServer peut recevoir un tableau de mocks complémentaires.
Ces mocks sont ajoutĂ©s aux mocks dĂ©finis par dĂ©faut. Sâils interceptent les mĂȘmes appels, ils peuvent Ă©galement les surcharger.
Exemple de mock GraphQL :
Les donnĂ©es retournĂ©es par les queries et mutations doivent ĂȘtre renseignĂ©es manuellement, car elles ne peuvent pas ĂȘtre dĂ©duites automatiquement Ă partir de la configuration de vue.
Tests générés par défaut
Plusieurs tests peuvent ĂȘtre gĂ©nĂ©rĂ©s par dĂ©faut.
Certains tests sont volontairement marquĂ©s comme skip afin de ne pas casser lâexistant lors de la gĂ©nĂ©ration.
Ces tests peuvent ensuite ĂȘtre activĂ©s, complĂ©tĂ©s ou adaptĂ©s par lâĂ©quipe projet selon les besoins.
Test dâaffichage
Un test dâaffichage permet de vĂ©rifier que la vue se rend correctement une fois les donnĂ©es chargĂ©es.
Le test suit généralement les étapes suivantes :
- exécution de setupServer pour mocker les appels externes ;
- rendu du composant ;
- attente du retour des appels API et des queries GraphQL interceptés via MSW ;
- vérification du rendu stabilisé via snapshot.
Exemple :
it('simple test - snapshot', async () => { setupServer(); const { container } = render(<Home />, { wrapper: ({ children }) => <TestsProviders environment=ï»ż>ï»ż</TestsProviders> });
await screen.findByRole('heading', { value: viewIds.HOME }); await screen.findByText('Is loaded GetProject: yes');
expect(container).toMatchSnapshot(); });
Test dâinteraction utilisateur
Un test dâinteraction permet de vĂ©rifier le comportement dâune vue lorsquâun utilisateur rĂ©alise une action, par exemple un clic sur un bouton.
Le test suit généralement les étapes suivantes :
- exécution de setupServer pour mocker les appels externes ;
- rendu du composant ;
- attente du chargement des données nécessaires ;
- interaction avec le DOM via userEvent, par exemple click, type ou dblClick ;
- attente du retour de lâaction effectuĂ©e ;
- vérification que la mutation GraphQL a été appelée avec les bonnes données.
Exemple :
it('userEvent - action - NEXT', async () => { const user = userEvent.setup(); let isMutationValid = new Promise((resolve, reject) => { setTimeout(() => reject('did not handle the request'), 1500); });
setupServer([ graphql.mutation('ProcessActionMutation', (req, res, ctx) => { const { input } = req.variables;
isMutationValid = Promise.resolve(equals(input, { action: 'HOME_NEXT', viewId: 'HOME' }));
return res( ctx.data({ processAction: { ok: true, error: null, process: { id: 'id', context: { projectId: 'projectId', viewId: 'HOME', actions: ['NEXT', '_DEFAULT_'] } } } }) ); }) ]);
render(<Home />, { wrapper: ({ children }) => <TestsProviders environment=ï»ż>ï»ż</TestsProviders> });
await screen.findByRole('heading', { value: viewIds.HOME }); await screen.findByText('Is loaded GetProject: yes');
const button = await screen.findByRole('button', { name: 'NEXT' });
await user.click(button);
await waitFor(() => expect(isMutationValid).toBeTruthy()); });
Exemple de test avec mutation GraphQL
Lâexemple suivant illustre un test dĂ©clenchant une mutation GraphQL Ă partir dâune action utilisateur dans la page.
import GQLEnvironment from '@@appGraphQL/Environment'; import Start from './Start'; import { beforeAll, describe, expect, it } from '@jest/globals'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { graphql } from 'msw'; import { equals } from 'ramda'; import { TestsProviders } from 'tests/__custom__/TestsProviders'; import { server } from 'tests/__utils__/init-app-after-env.mjs'; import { viewIds } from '@@app/withProcess'; describe('Test Start', () => { let environment;
beforeAll(async () => { environment = await GQLEnvironment(); });
const setupServer = (otherQuery = []) => { server.use( ...otherQuery, graphql.query('QProcessQuery', (req, res, ctx) => { return res( ctx.data({ process: { id: 'id', context: { projectId: 'projectId', viewId: 'START', actions: ['PREVIOUS'] }, userSession: null, tasks: null } }) ); }),
graphql.query('GetStartProjectQuery', (req, res, ctx) => { return res( ctx.data({ getStartProject_start: { id: 'String', externalId: 'String', name: 'String' } }) ); }),
graphql.query('GetCustomerQuery', (req, res, ctx) => { return res( ctx.data({ getCustomer_start: { email: 'String', firstName: 'String', lastName: 'String' } }) ); }) ); };
it('simple test - create a customer', async () => { const user = userEvent.setup();
let isMutationValid = new Promise((resolve, reject) => { setTimeout(() => reject('did not handle the request'), 1500); });
setupServer([ graphql.mutation('CreateCustomerMutation', (req, res, ctx) => { const { input } = req.variables;
isMutationValid = Promise.resolve( equals(input, { email: '[email protected]', firstName: 'starter', lastName: 'starter' }) );
return res(ctx.data({ createCustomer_M_start: { ok: true, error: null } })); }),
graphql.query('GetCustomerQuery', (req, res, ctx) => { return res( ctx.data({ getCustomer_start: { email: '[email protected]', firstName: 'starter', lastName: 'starter' } }) ); }) ]);
render(<Start />, { wrapper: ({ children }) => <TestsProviders environment=ï»ż>ï»ż</TestsProviders> });
await screen.findByRole('heading', { value: viewIds.START }); await screen.findByText('Is loaded GetStartProject: yes'); await screen.findByText('Is loaded GetCustomer: yes');
const button = await screen.findByRole('button', { name: 'Create Customer' });
await user.click(button);
await waitFor(() => expect(isMutationValid).toBeTruthy()); await screen.findByText(/\{ "email": "starter@mail\.com", "firstname": "starter", "lastname": "starter" \}/i); }); });
Désactiver la génération des tests
Ă partir de la version 2.1.0, il est possible de dĂ©sactiver la gĂ©nĂ©ration des fichiers de tests dâintĂ©gration.
Pour cela, il faut ajouter la clé testFile dans le fichier de configuration YAML de la vue et définir sa valeur à false.
Exemple :
Lorsque testFile est dĂ©fini Ă false, aucun fichier de test dâintĂ©gration nâest gĂ©nĂ©rĂ© pour la vue concernĂ©e.