Test des composants dans React: quoi et comment tester avec Jest et Enzyme.

Cet article sur le test des composants de réaction est écrit par Alona Pysarenko - Ingénieur Frontend chez Django Stars.
Lisez l'article original sur le blog Django Stars.

Tester les composants React peut être un défi pour les débutants ainsi que pour les développeurs expérimentés qui ont déjà travaillé avec des tests. Il peut être intéressant de comparer vos propres approches avec celles que nous utilisons dans notre projet. Afin de couvrir la base de code, vous devez savoir quels composants doivent être testés et quel code doit figurer exactement dans le composant.

Au cours de cet article, je traiterai des sujets suivants:

  • Définir le bon ordre de test des composants en fonction de la structure du projet
  • Trouver ce qu'il faut omettre dans la couverture du test (quoi ne pas tester)
  • Identifier la nécessité de tester les instantanés
  • Définit ce qu'il faut tester dans le composant et dans quel ordre
  • Fournir des exemples de code personnalisés détaillés

Cet article nécessite que vous maîtrisiez la configuration de Jest and Enzyme. Des informations sur l'installation et la configuration peuvent être facilement trouvées sur leurs sites Web officiels.

Supposons le cas suivant: Vous devez couvrir la base de code du projet avec des tests. Par quoi devez-vous commencer et que devriez-vous obtenir à la fin des tests? Couverture de test de 100%? C’est la référence à laquelle vous devriez aspirer, mais dans la plupart des situations, vous ne l’obtiendrez pas.

Pourquoi? Parce que vous ne devriez pas tester tout le code. Nous découvrirons pourquoi et ce qui devrait être omis des tests. De plus, une couverture de test de 100% ne garantit pas toujours que le composant est entièrement testé. Il n'y a également aucune garantie qu'il vous avertisse si quelque chose a été changé. Ne cherchez pas les pourcentages, évitez d’écrire de faux tests et essayez simplement de ne pas perdre les détails des composants principaux.

Définition du bon ordre de test des composants en fonction de la structure du projet

Discutons de cette question dans la partie suivante de la structure du projet:

J'ai pris le répertoire partagé parce que c'est le plus important. Il comprend les composants utilisés dans plusieurs pages différentes du projet. Ils sont réutilisables et, normalement, ils sont petits et non complexes. Si l’un ou l’autre des composants échoue, cela entraînera une défaillance ailleurs. C’est pourquoi nous devons nous assurer qu’ils ont été écrits correctement. La structure de ce répertoire est divisée en plusieurs dossiers, chacun contenant des composants.

Comment définir le bon ordre de test des composants dans le répertoire partagé:

  • Suivez toujours la règle d'aller du simple au complexe. Analysez chaque répertoire et définissez les composants qui sont indépendants. En d'autres termes, leur rendu ne dépend pas des autres composants. Ils sont complétés et peuvent être utilisés séparément comme une seule unité. Dans la structure ci-dessus, il s’agit du répertoire input du dossier formulaires. Il contient des composants d'entrée pour les formulaires redux, tels que TextInput, SelectInput, CheckboxInput, DateInput, etc.
  • Ensuite, nous devons définir les composants auxiliaires qui sont souvent utilisés dans les composants d’entrée, mais qui doivent être testés indépendamment d’eux. C'est le répertoire utils. Les composants de ce dossier ne sont pas compliqués, mais très importants. Ils sont souvent réutilisables et aident à effectuer des actions répétées.
  • L'étape suivante consiste à définir quels composants peuvent être utilisés indépendamment. S'il y en a, prenez-les pour les tester. De notre structure, ce sont les widgets, les petits composants avec une fonctionnalité simple. Ils seront le troisième élément de la file d'attente pour la couverture de test.
  • En outre, analysez le reste des répertoires et définissez des composants plus complexes, qui peuvent être utilisés indépendamment ou conjointement avec d'autres composants. C'est le répertoire des modaux dans notre cas. Ces composants seront expliqués en détail ci-dessous.
  • Les composants les plus complexes sont laissés à la fin. Ce sont le répertoire et les champs du dossier formulaires. Comment définissez-vous lequel doit être testé en premier? Je prends le répertoire à partir duquel des composants ont déjà été utilisés dans des composants testés. Ainsi, le composant du répertoire hoc était présent dans le composant widgets. C’est pourquoi je sais déjà où et dans quel but ce répertoire et ses composants sont utilisés.
  • Le dernier est le dossier des champs. Il contient des composants liés aux formulaires redux.

L'ordre final des composants (basé sur notre exemple) ressemblera à ceci:

Suite à cette commande, vous augmentez progressivement la complexité des composants testés. Ainsi, s’agissant des composants les plus complexes, vous savez déjà comment se comportent les plus petits.

Ne prenez pas pour tester, par exemple, le champ ‘array’, si vous ne savez pas comment tester le champ ‘text’. Ne prenez pas de composants décorés avec la forme redux si vous n’avez pas testé le champ "forme" lui-même.

Soyez cohérent dans vos choix, ne prenez pas le premier élément qui vous vient à l’esprit et changez de logique. Bien entendu, la structure de votre projet peut différer. Il peut avoir d'autres noms de répertoire ou des composants, actions et réducteurs supplémentaires, mais la logique de définition de l'ordre de test des composants est identique.

Définissons ce qui doit être omis dans la couverture de test:

  • Bibliothèques tierces. Ne testez pas les fonctionnalités extraites d’une autre bibliothèque. Vous n'êtes pas responsable de ce code. Ignorez-le ou imitez-le si vous en avez besoin pour tester votre code.
  • Constantes Le nom parle de lui-même. Ils ne sont pas changeables. Ce sont des ensembles de code statique qui ne sont pas destinés à varier.
  • Styles en ligne (si vous les utilisez dans votre composant). Afin de tester les styles en ligne, vous devez dupliquer un objet avec des styles dans votre test. Si les styles d'objet changent, vous devez également les modifier dans le test. Ne dupliquez pas le code d’un composant dans les tests. Vous ne garderez jamais à l'esprit de le changer dans les tests. De plus, votre collègue ne réalisera jamais qu’il ya duplication. Dans la plupart des cas, les styles en ligne ne modifient pas le comportement du composant, ils ne doivent donc pas être testés. Il peut y avoir une exception si vos styles changent de manière dynamique.
  • Choses non liées au composant testé. Ignorer la couverture avec les composants de test importés dans le composant testé. Faites attention si elle est emballée dans une autre. Ne testez pas le wrapper, analysez-le et testez-le séparément.

Alors, comment écrivez-vous réellement des tests? Je combine deux approches de test:

  • Test de capture instantanée
  • Test de la logique des composants

Je vais en discuter tous les deux maintenant.

Comment tester avec des instantanés

Snapshot Testing est un outil de test utile si vous voulez vous assurer que l’interface utilisateur n’a pas changé. Lorsque vous rencontrez cet outil de test pour la première fois, vous pouvez avoir des questions concernant l'organisation et la gestion des instantanés. Le principe est très simple, mais malheureusement, il n’a pas été décrit en détail nulle part.

Étape 1. Ecrivez le test pour le composant et, dans le bloc expect, utilisez la méthode .toMatchSnapshot () qui crée l’instantané lui-même:

it ('rend correctement le composant textuel', () => {
    const TextInputComponent = renderer.create (). toJSON ();
    expect (TextInputComponent) .toMatchSnapshot ();
});

Étape 2. Lorsque vous exécuterez le test pour la première fois à un niveau donné, un répertoire sera créé, appelé __snapshots__, avec le fichier généré automatiquement à l'intérieur avec l'extension.snap.

L'instantané ressemble à ceci:

// Jest Snapshot v1, https://goo.gl/fbAQLP
exports [`Render TextInput correctement le composant 1`] =`

`;

Étape 3. Placez l’instantané dans le référentiel et stockez-le avec le test.

Si le composant a été modifié, il vous suffit de mettre à jour l'instantané avec l'indicateur —updateSnapshot ou d'utiliser l'indicateur u abrégé.

Donc, l'instantané est créé - comment ça marche?

Considérons deux cas:

1. Le composant a changé

  • Exécuter des tests
  • Un nouveau cliché est créé, il se compare au cliché généré automatiquement stocké dans le répertoire __snapshots__
  • Les tests ont échoué parce que l'instantané est différent

2. Le composant n'a pas changé

  • Exécuter des tests
  • Un nouveau cliché est créé, il se compare au cliché généré automatiquement stocké dans le répertoire __snapshots__
  • Tests réussis car l'instantané est identique

Tout va bien lorsque nous testons un petit composant sans logique (uniquement le rendu d'interface utilisateur). Mais comme le montre la pratique, de tels composants n'existent pas dans les projets réels. S'ils existent, ils sont peu nombreux.

Y a-t-il assez d'instantanés pour le test complet des composants?

Principales instructions pour le test des composants

1. Un composant doit avoir un seul instantané.

Si un instantané échoue, il est fort probable que les autres échoueront également. Ne créez pas et ne stockez pas d'instantanés inutiles qui encombrent l'espace et déroutent les développeurs qui liront vos tests après vous.

Bien entendu, il existe des exceptions lorsque vous devez tester le comportement d'un composant dans deux états: par exemple, dans l'état du composant avant d'ouvrir la fenêtre contextuelle et après l'ouverture.

Cependant, même une telle variante peut toujours être remplacée par celle-ci: le premier test enregistre l’état par défaut du composant sans la fenêtre contextuelle dans la capture instantanée, et le second test simule l’événement et vérifie la présence d’une classe particulière. De cette manière, vous pouvez facilement éviter la création de plusieurs instantanés.

2. Test des accessoires

En règle générale, je divise le test des accessoires en deux:

  • Tout d'abord, vérifiez le rendu des valeurs prop par défaut. Lorsque le composant est rendu, je m'attends à ce qu'une valeur soit égale à defaultProps au cas où cet accessoire aurait defaultProps.
  • Deuxièmement, vérifiez la valeur personnalisée de l'accessoire. J'ai défini ma propre valeur et je m'attends à ce qu'elle soit reçue après le rendu du composant.

3. Test des types de données

Afin de tester quel type de données entre dans les accessoires ou quel type de données est obtenu après certaines actions, nous pouvons utiliser la bibliothèque spéciale jest-extended (Additional Jest matchers), qui contient un ensemble étendu de correspondances qui sont absentes de la liste. Plaisanter. Avec cette bibliothèque, tester les types de données est beaucoup plus facile et plus agréable.

Tester les propriétés, en revanche, est une question contradictoire. Certains développeurs peuvent s'opposer aux tests de proptypes car il s'agit d'un package tiers et ne doivent pas être testés. Néanmoins, j’insiste pour tester les propriétés des composants car je ne teste pas la fonctionnalité du package elle-même. Au lieu de cela, je m'assure simplement que les proptypes sont corrects. Le type de données est un élément de programmation très important et ne doit pas être ignoré.

4. Test de l'événement

Après avoir créé un instantané et recouvert les accessoires de tests, vous pouvez être sûr que le rendu du composant sera correct. Mais cela ne suffit pas pour une couverture complète au cas où vous auriez des événements dans le composant.

Vous pouvez vérifier l'événement de plusieurs manières. Les plus utilisés sont:

  • événement simulé => simulez-le => l'événement attendu a été appelé
  • événement simulé => événement simuler avec params => appel attendu avec les paramètres passés
  • transmet les propriétés nécessaires => composant de rendu => simule un événement => attend un certain comportement sur l'événement appelé

5. Conditions d'essai

Très souvent, vous pouvez avoir des conditions pour la sortie d'une classe particulière, le rendu d'une certaine section du code, le transfert des accessoires requis, etc. N'oubliez pas cela car avec les valeurs par défaut, une seule branche réussira le test, tandis que la seconde restera non testée.

Dans les composants complexes avec des calculs et de nombreuses conditions, vous pouvez rater certaines branches. Pour vous assurer que toutes les parties du code sont couvertes par des tests, utilisez un outil de couverture de test et vérifiez visuellement les branches couvertes et celles qui ne le sont pas.

6. Etat de test

Pour vérifier l'état, dans la plupart des cas, il est nécessaire d'écrire deux tests:

  • Le premier vérifie l'état actuel.
  • Le second vérifie l'état après avoir appelé un événement. Le composant de rendu => appelle la fonction directement dans le test => vérifie comment l'état a changé. Pour appeler la fonction du composant, vous devez obtenir une instance du composant et ensuite uniquement appeler ses méthodes (un exemple est présenté dans le test suivant).

Après avoir parcouru cette liste d'instructions, votre composant sera couvert de 90 à 100%. Je laisse 10% pour les cas spéciaux qui n'étaient pas décrits dans l'article, mais qui peuvent apparaître dans le code.

Exemples d'essais

Passons maintenant aux exemples et couvrons les composants avec des tests comme nous l'avons décrit ci-dessus, étape par étape.

1. Tester un composant à partir de formulaires / entrées.

Prenez un composant du répertoire forms / input. Il s’agit de DateInput.js, composant du champ datepicker.

Liste de codes pour le composant testé: DateInput.js
Ressemble à:

Le composant DateInput utilise la bibliothèque react-datepicker, avec deux utilitaires:

  • valueToDate (convertit la valeur en date)
  • dateToValue (convertit date en valeur)

Le paquet est pour manipuler avec la date et PropTypes est pour vérifier les props de React.

Selon le code du composant, nous pouvons voir la liste des accessoires par défaut qui aident le composant à être rendu:

const defaultProps = {
    inputClassName: 'input-custom',
    moisVue: 1,
    dateFormat: 'JJ.MM.AAAA',
    showMonthYearsDropdowns: false,
    minDate: moment ()
};

Tous les accessoires sont appropriés pour créer l’instantané, sauf un: minDate: moment (). moment () nous donnera la date actuelle à chaque fois que nous exécutons le test et l'instantané échouera car il stockera la date obsolète. La solution est de se moquer de cette valeur:

const defaultProps = {
    minDate: moment (0)
}

Nous avons besoin de minDate prop dans chaque composant rendu. Pour éviter la duplication des accessoires, je crée HOC qui reçoit defaultProps et retourne un joli composant:

importer TestDateInput de '../DateInput';
const DateInput = (props) =>
    

N’oubliez pas le fuseau horaire, en particulier si vos tests sont exécutés par des développeurs d’un autre pays situés dans un fuseau horaire différent. Ils recevront la valeur simulée, mais avec un décalage de fuseau horaire. La solution consiste à définir un fuseau horaire par défaut:

const moment = require.requireActual ('moment-timezone'). tz.setDefault ('America / Los_Angeles')

Le composant d'entrée de date est maintenant prêt pour le test:

1.Créer un instantané en premier:

it ('rend correctement le composant de date', () => {
    const DateInputComponent = renderer.create (). toJSON ();
    expect (DateInputComponent) .toMatchSnapshot ();
});

2. accessoires de test:

Regardez à travers les accessoires et trouvez les plus importants. Le premier accessoire à tester est showMonthYearsDropdowns. Si elle est définie sur true, la liste déroulante des mois et des années est affichée:

it ('vérifier les listes déroulantes des mois et des années affichés', () => {
    const props = {
            showMonthYearsDropdowns: true
        },
        DateInputComponent = mount ().find('.datepicker ');
    expect (DateInputComponent.hasClass ('réagir-date-sélecteur-mois-masqué')). toEqual (true);
});

Testez la valeur de prop nulle. Cette vérification est nécessaire pour garantir que le composant est rendu sans valeur définie:

it ('rend la date correctement avec une valeur nulle', () => {
    const props = {
            valeur: null
        },
        DateInputComponent = mount ();
    expect ((DateInputComponent) .prop ('valeur')). toEqual (null);
});

3.Tester les types de propriété pour value, date prévue pour être une chaîne:

it ('vérifie le type de valeur', () => {
    const props = {
            valeur: '10 .03.2018 '
        },
        DateInputComponent = mount ();
    expect (DateInputComponent.prop ('valeur')). toBeString ();
});

Événements 4.Test:

Tout d’abord, vérifiez l’événement onChange.

  • rappel simulé onChange
  • rendre le composant d'entrée de date
  • simuler un événement de changement avec une nouvelle valeur cible
  • et enfin, vérifiez que l'événement onChange a été appelé avec une nouvelle valeur.
it ('vérifie le rappel onChange', () => {
    const onChange = jest.fn (),
        props = {
            valeur: '20 .01.2018 ',
            sur le changement
        },
        DateInputComponent = mount ().find('input ');
    DateInputComponent.simulate ('change', {cible: {valeur: moment ('2018-01-22')}});
    expect (onChange) .toHaveBeenCalledWith ('22 .01.2018 ');
});

Ensuite, assurez-vous que la fenêtre contextuelle Datepicker s'ouvre après un clic sur l'entrée de date. Pour cela, recherchez la date entrée => simulez un événement clic => et attendez-vous à l'affichage d'une fenêtre contextuelle lorsque la classe .react-datepicker est présente.

it ('check DatePicker popup open', () => {
    const DateComponent = mount (),
        dateInput = DateComponent.find ("input [type = 'text']");
    dateInput.simulate ('clic');
    expect (DateComponent.find ('. react-datepicker')). toHaveLength (1);
});

Liste complète des tests: DateInput.test.js

2. Test d'utilité:

Liste de codes pour l'utilitaire testé: valueToDate.js

Le but de cet utilitaire est de transformer une valeur en date avec un format personnalisé.

Tout d’abord, analysons l’utilitaire donné et définissons les principaux cas à tester:

  1. Selon l'objectif de cet utilitaire, il transforme la valeur. Nous devons donc vérifier cette valeur:
  • Si la valeur n'est pas définie, nous devons nous assurer que l'utilitaire ne renverra pas d'exception (erreur).
  • Si la valeur est définie: nous devons vérifier que l'utilitaire renvoie la date du moment.

2. La valeur renvoyée doit appartenir à la classe moment. C’est pourquoi cela devrait être une instance de moment.

3. Le deuxième argument est dateFormat. Définissez-le comme constant avant les tests. C’est pourquoi il sera passé à chaque test et renverra une valeur en fonction du format de la date. Devrions-nous tester dateFormat séparément? Je suppose que non. Cet argument est facultatif - si nous ne définissons pas dateFormat, l’utilitaire ne fonctionnera pas et il retournera simplement la date au format par défaut. C’est un travail temporaire, nous ne devrions pas tester les bibliothèques tierces. Comme je l’ai déjà mentionné, nous ne devrions pas oublier le moment-fuseau horaire; c'est un point très important, en particulier pour les développeurs de différents fuseaux horaires.

Voyons le code:

  1. Ecrivez le test pour le premier cas. Lorsque nous n’avons pas de valeur, elle est vide.
const format = 'JJ.MM.AAAA';
it ('Utilitaire de rendu de la valeur à la date] avec valeur vide', () => {
    const value = valueToDate ('', format);
    expect (valeur) .toEqual (null);
});

2. Vérifiez si la valeur est définie.

const date = '21 .11.2015 ',
      format = 'JJ.MM.AAAA';
it ('Utilitaire de rendu de la valeur avec valeur définie', () => {
    valeur const = valeurVersDate (date, format);
    expect (valeur) .toEqual (moment (date, format));
});

3. Vérifiez si la valeur appartient à la classe moment.

const date = '21 .11.2015 ',
    format = 'JJ.MM.AAAA';
it ('check value is instanceof moment', () => {
    valeur const = valeurVersDate (date, format);
    expect (valeur instanceof moment) .toBeTruthy ();
});

Liste complète des tests: valueToDate.test.js

3. Test des widgets

Pour tester les widgets, j'ai pris un composant spinner.

Liste de codes pour le widget testé: Spinner.js

Ressemble à ça:

L'explication n'est pas nécessaire dans l'explication, car presque toutes les ressources Web ont ce composant.

Donc, si nous allons écrire des tests:

  1. Première étape - créer un instantané:
it ('rend correctement le composant Spinner', () => {
   const SpinnerComponent = mount ();
   expect (SpinnerComponent) .toMatchSnapshot ();
});

2. Test des accessoires:

Tout d’abord, examinons le titre par défaut et vérifions si le rendu est correct.

it ('vérifier le titre de la propriété par défaut', () => {
 const SpinnerComponent = mount ();
    expect (SpinnerComponent.find ('p'). text ()). toEqual ('Please wait');
});

Ensuite, nous vérifions le titre personnalisé. Nous devons vérifier que cela retourne le prop correctement défini. Examinez le code, le titre est encapsulé dans rawMarkup util et est généré à l'aide de la propriété dangerouslySetInnerHTML.

Liste de code pour rawMarkup util:

fonction d'exportation par défaut rawMarkup (template) {
    return {__html: template};
}

Avons-nous besoin d'inclure des tests pour rawMarkup dans le composant spinner? Non, c'est un utilitaire séparé et il devrait être testé en dehors du disque. Nous ne nous soucions pas de la façon dont cela fonctionne - nous avons juste besoin de savoir que l’accessoire en titre renvoie le résultat correct

Précision: la raison de l’utilisation de la propriété dangerouslySetInnerHTML est la suivante. Notre site est multilingue, sous la responsabilité de l’équipe marketing des traductions. Ils peuvent le traduire simplement avec une combinaison de mots ou même décorer avec les balises HTML, comme , , ou même couper le texte avec les listes

    ,
      . Nous ne savons pas avec certitude comment ils traduisent et décorent le texte. Nous avons juste besoin de rendre correctement tout ça.

      J'ai combiné deux tests principaux dans un test:

      • retourne le titre de propriété personnalisé correct
      • restituer correctement le titre de propriété avec les balises HTML
      it ('vérifier le titre de propriété avec les balises html', () => {
          const props = {
                  titre: ' Veuillez patienter '
              },
              SpinnerComponent = mount ();
          expect (SpinnerComponent.find ('p'). text ()). toEqual ('Please wait');
      });

      Prenez le prochain sous-titre. C’est facultatif et c’est pourquoi il n’a pas d’accessoire par défaut. Ignorez donc l’étape avec les accessoires par défaut et testez les accessoires personnalisés:

      • Vérifiez que le texte dans subTitle prop s'affiche correctement:
      const props = {
              sous-titre: 'laissé 1 minute'
          },
          SpinnerComponent = mount ();
      it ('rendre le texte correct', () => {
          expect (SpinnerComponent.find ('p'). at (1) .text ()). toEqual (props.subTitle);
      });

      Nous savons que le sous-titre est facultatif. C’est pourquoi nous devons vérifier si le rendu n’est pas rendu avec les accessoires par défaut, conformément au balisage de découpage. Il suffit de vérifier le nombre de tags

      :

      it ('check subTitle is not render', () => {
        const SpinnerComponent = mount ();
          expect (SpinnerComponent.find ('p'). length) .toEqual (1);
      });

      Types de prop 3.Testing:

      • Pour le titre prop prévu à être string:
      it ('vérifier que le type de titre pour title est string', () => {
          const props = {
                  titre: 'Wait'
              },
              SpinnerComponent = mount ();
          expect (SpinnerComponent.find ('p'). text ()). toBeString ();
      });
      • Pour subTitle prop devrait également être string:
      const props = {
              sous-titre: 'laissé 1 minute'
          },
          SpinnerComponent = mount ();
      it ('type pour subTitle is string', () => {
          attendre (SpinnerComponent.find ('p'). at (1) .text ()). toBeString ();
      });

      Liste complète des tests: Spinner.test.js

      4. Test des modaux (ModalWrapper.js et ModalTrigger.js)

      Ressemble à:

      Comment tester les modaux

      Tout d'abord, je veux expliquer comment les modaux sont organisés sur notre projet. Nous avons deux composants: ModalWrapper.js et ModalTrigger.js.

      ModalWrapper est responsable de la mise en page contextuelle. Il contient le conteneur modal, le bouton ‘fermer’, le titre et le corps modaux.

      ModalTrigger est responsable de la gestion modale. Il inclut la disposition ModalWrapper et contient des événements pour le contrôle de disposition de modal (actions d'ouverture et de fermeture).

      Je vais passer en revue chaque composant séparément:

      1. Liste des codes du composant testé: ModalWrapper.js

      Voyons le code:

      Tout d'abord, ModalWrapper reçoit le composant et le restitue à l'intérieur. Tout d’abord, vérifiez que ModalWrapper n’échouera pas sans le composant. Créez un instantané avec les accessoires par défaut:

      it ('sans composant', () => {
          const ModalWrapperComponent = shallow ();
          expect (ModalWrapperComponent) .toMatchSnapshot ();
      });

      L'étape suivante consiste à simuler son état réel avec le rendu du composant transmis via les accessoires:

      it ('avec composant', () => {
         const props = {
                 composant: () => {}
              },
              ModalWrapperComponent = shallow ();
          expect (ModalWrapperComponent) .toMatchSnapshot ();
      });

      Test des accessoires

      Réception du nom de classe personnalisé prop:

      it ('rend le nom de classe correct', () => {
          const props = {
                  modalClassName: 'nom-classe-personnalisé'
              },
              ModalWrapperComponent = shallow ().find('Modal ');
              expect (ModalWrapperComponent.hasClass ('nom de classe personnalisé')). toEqual (true);
      });

      Recevoir un titre personnalisé:

      it ('rendre le titre correct', () => {
          const props = {
                 titre: 'Titre modal'
             },
             ModalWrapperComponent = shallow ().find('ModalTitle ');
          expect (ModalWrapperComponent.props (). children) .toEqual ('Titre modal');
      });

      Recevoir le bon spectacle:

      it ('vérifier la valeur de la propriété', () => {
              const props = {
                     montrer: vrai
                 },
                 ModalWrapperComponent = shallow ().find('Modal ');
              expect (ModalWrapperComponent.props (). show) .toEqual (true);
          });

      Test de types

      • Pour le spectacle
      it ('check prop type', () => {
          const props = {
                 montrer: vrai
              },
              ModalWrapperComponent = shallow ().find('Modal ');
          expect (ModalWrapperComponent.props (). show) .toBeBoolean ();
      });
      • Pour onHide prop
      it ('rend correct onHide prop type', () => {
          const props = {
                  onHide: () => {}
              },
              ModalWrapperComponent = shallow ().find('Modal ');
          expect (ModalWrapperComponent.props (). onHide) .toBeFunction ();
      });
      • Pour le composant prop
      it ('rendre le type de composant correct ", () => {
         const props = {
                 composant: () => {}
             },
             ModalWrapperComponent = mount ();
         expect (composant ModalWrapperComponent.props ().) .toBeFunction ();
      });

      Liste complète des tests: ModalWrapper.test.js

      Liste de codes pour le composant testé: ModalTrigger.js

      L'emballage modal a été recouvert d'un test. La deuxième partie consiste à couvrir le composant déclencheur modal.

      Vue d'ensemble des composants: il est basé sur l'état basculé qui indique la visibilité de ModalWrapper. Si basculé: faux, la fenêtre contextuelle est masquée, sinon elle est visible. La fonction open () ouvre la fenêtre contextuelle sur l'élément enfant. L'événement click et la fonction close () masquent la fenêtre contextuelle du bouton affiché dans ModalWrapper.

      Création d'instantané:

      it ('rend le composant ModalTrigger correctement', () => {
          const ModalTriggerComponent = shallow ( 
      );     expect (ModalTriggerComponent) .toMatchSnapshot (); });

      Devrions-nous tester ModalTrigger avec un rendu de composant prop? Non - car le composant sera rendu dans le composant ModalWrapper. Cela ne dépend pas du composant testé. Il était déjà couvert de tests dans les tests de ModalWrapper.

      Test des accessoires:

      Nous avons des enfants avec un accessoire et nous voulons être sûrs que nous n’avons qu’un enfant.

      it ('veille à n'avoir qu'un seul enfant (élément de contrôle)', () => {
          expect (ModalTriggerComponent.findWhere (node ​​=> node.key () === 'modal-control'). length) .toEqual (1);
      });

      Test de types:

      Le prop enfant doit être un objet, alors vérifiez ceci lors du prochain test:

      const ModalTriggerComponent = mount ( 
      );
      it ('vérifie le type de prop des enfants', () => {
            expect (ModalTriggerComponent.props (). enfants) .toBeObject ();
      });

      Une partie importante du composant ModalTrigger consiste à vérifier les états.

      Nous avons deux états:

      • Popup est ouvert. Pour savoir que le modal est ouvert, nous devons vérifier son état. Pour cela, appelez la fonction open depuis l'instance du composant et attendez-vous à ce que l'état basculé à l'état soit vrai.
      it ('vérifie que le modal est ouvert', () => {
          événement const = {
              preventDefault: () => {},
              stopPropagation: () => {}
          };
          ModalTriggerComponent.instance (). Open (événement);
          attendez (ModalTriggerComponent.state (). basculé) .toBeTruthy ();
      });
      • Popup est fermé. Il est testé inversement, basculé dans l'état devrait être faux.
      it ('vérifie que le modal est fermé', () => {
         ModalTriggerComponent.instance (). Close ();
         attendez (ModalTriggerComponent.state (). basculé) .toBeFalsy ();
      });

      Liste complète des tests: ModalTrigger.test.js

      Maintenant, les modaux sont entièrement testés. Un conseil pour tester les composants qui dépendent les uns des autres: examinez d'abord les composants et écrivez le plan de test, définissez ce que vous souhaitez tester dans chaque composant, vérifiez les scénarios de test de chaque composant et veillez à ne pas le faire. répéter le même cas de test dans les deux composants. Analysez soigneusement les variantes possibles et optimales pour la couverture du test.

      5. Test HOC (composant d'ordre supérieur)

      Les deux dernières parties (test des HOC et des champs de formulaire) sont interconnectées. Je voudrais partager avec vous comment tester la mise en page sur le terrain avec son HOC.

      Voici une explication de BaseFieldLayout, pourquoi nous avons besoin de ce composant et à quel endroit nous l’utilisons:

      • BaseFieldLayout.js est l'encapsuleur pour les composants d'entrée de formulaire tels que TextInput, CheckboxInput, DateInput, SelectInput, etc. Leurs noms se terminent par -Input car nous utilisons le paquetage redux-form et que ces composants sont les composants d'entrée servant à la logique de formulaire redux.
      • Nous avons besoin de BaseFieldLayout pour créer la présentation des composants de champs de formulaire, c'est-à-dire une étiquette de rendu, des info-bulles, des préfixes (devise, abréviations de mètres carrés, etc.), des icônes, des erreurs, etc.
      • Nous l'utilisons dans BaseFieldHOC.js pour envelopper le inputComponent dans la présentation du champ et le connecter au formulaire redux à l'aide du composant .

      Liste de codes pour le composant testé: BaseFieldHOC.js

      C'est un HOC qui reçoit le composant d'entrée de formulaire et renvoie le composant, connecté à redux-form.

      Analyse du HOC:

      • Ce composant reçoit un seul accessoire, composant. Tout d’abord, je dois créer ce composant et l’envelopper dans BaseFieldHOC.
      • Ensuite, je dois décorer le HOC enveloppé avec redux-form afin que le champ soit connecté à redux-form.
      • Rendez ce champ dans le composant React Redux pour rendre le magasin disponible au composant testé. Pour se moquer du magasin, il suffit de faire:
      const store = createStore (() => ({}));

      Maintenant, avant chaque test, je dois effectuer les tâches suivantes:

      laisser BaseFieldHOCComponent;
      beforeEach (() => {
          const TextInput = () => {return 'saisie de texte'; },
              BaseFieldHOCWrapper = BaseFieldHOC (TextInput),
              TextField = reduxForm ({form: 'testForm'}) (BaseFieldHOCWrapper);
          BaseFieldHOCComponent = renderer.create (
              
                  
              
          ) .toJSON ();
      });

      Après cela, le composant est prêt à être testé:

      1. Créer un instantané:
      it ('rend correctement le composant', () => {
          expect (BaseFieldHOCComponent) .toMatchSnapshot ();
      });

      2. Assurez-vous que le composant d'entrée est encapsulé dans BaseFieldLayout après le rendu:

      it ('vérifier que le composant d’entrée est encapsulé dans BaseFieldLayout', () => {
          expect (BaseFieldHOCComponent.props.className) .toEqual ('groupe de formulaires');
      });

      C’est tout, le HOC est couvert. La partie la plus compliquée du test des composants liés à redux-form consiste à préparer le terrain (décorer avec redux form et setup store). Le reste est facile, il suffit de suivre les instructions et rien d’autre.

      Liste complète des tests: BaseFieldHOC.test.js

      6. Tests de formulaires / champs

      Le champ HOC est couvert de tests afin que nous puissions passer au composant BaseFieldLayout.

      Liste de codes pour le composant testé: BaseFieldLayout.js

      Codons BaseFieldLayout.js et écrivons les tests conformément aux instructions ci-dessus:

      1. Tout d'abord, créez un instantané.

      Ce composant ne sera pas rendu sans defaultProps:

      • inputComponent
      • Les accessoires fournis par redux-form: input et meta objects. Entrée avec nom de propriété et méta avec erreur de propriété et touché:
      const defaultProps = {
         méta: {
              touché: null,
              erreur: null
          },
          contribution: {
              nom: 'nom de champ'
          },
          inputComponent: () => {return 'test case'; }
      }

      Pour utiliser defaultProps dans chaque wrapper testé, procédez comme suit:

      importer TestBaseFieldLayout de '../BaseFieldLayout';
      const BaseFieldLayout = (props) => ;

      Nous sommes maintenant prêts à créer un instantané:

      it ('rend correctement le composant BaseFieldLayout', () => {
          const BaseFieldLayoutComponent = renderer.create (). toJSON ();
          expect (BaseFieldLayoutComponent) .toMatchSnapshot ();
      });

      2. Test des accessoires:

      Ce composant a de nombreux accessoires. Je montrerai plusieurs exemples et le reste sera testé par analogie.

      • Assurez-vous que l'icône est bien rendue
      it ('rend correctement l'icône prop', () => {
          const props = {
                  icon: 
              },
              BaseFieldLayoutComponent = mount ();
              expect (BaseFieldLayoutComponent.find ('span'). hasClass ('icon-exclamation')). ​​toBeTruthy ();
      });
      • Assurez-vous que le contenu de l'info-bulle s'affiche en regard de l'étiquette.
      const props = {
              labelTooltipContent: 'info-bulle pour label'
          },
          BaseFieldLayoutComponent = mount ();
      it ('check prop est rendu', () => {
         expect (BaseFieldLayoutComponent.find ('span'). hasClass ('tooltip-icon')). ​​toBeTruthy ();
      });
      • Test de prop FieldLink
      • Assurez-vous que fieldLink est null par défaut
      it ('check prop est null par défaut', () => {
          const BaseFieldLayoutComponent = shallow ();
          expect (BaseFieldLayoutComponent.props (). fieldLink) .toBe (null);
      });
      • Assurez-vous que fieldLink s'affiche correctement avec une valeur personnalisée.

      3. Erreurs de test:

      it ('vérifie si le champ a une erreur', () => {
          const props = {
                  méta: {
                      touché: vrai,
                      erreur: 'Ce champ est obligatoire'
                  }
              },
              BaseFieldLayoutComponent = mount ();
          expect (BaseFieldLayoutComponent.find ('. error')). toHaveLength (1);
      });

      Liste complète des tests: BaseFieldLayout.test.js

      Ligne de fond

      Vous savez maintenant comment effectuer des tests de couverture complète des composants en fonction de la structure du projet. De par ma propre expérience, j’ai essayé d’expliquer ce qui est nécessaire pour tester, dans quel ordre, et ce que vous pouvez omettre dans la couverture de test. En outre, j'ai présenté des exemples de plusieurs composants de test et repéré la séquence de couverture de la base de code.

      J'espère que vous trouverez cet article utile et que vous partagerez vos réponses. Merci pour la lecture.

      Si vous trouvez ce message utile, appuyez sur le bouton ci-dessous :)