On a déjà beaucoup écrit sur les tests unitaires des composants React, des réducteurs Redux et autres, mais nous avons eu beaucoup de mal à trouver des articles approfondis sur la mise en place de tests d'intégration « full-stack » adaptés à la pile JavaScript moderne.
Voici le premier article d'une série en quatre parties :
- Nightwatch et les appels API pour des tests « full stack » propres, rigoureux et isolés
- Gulp, AWS et Terraform pour une livraison continue sans effort
- Circle CI et Saucelabs pour tout automatiser
Notre configuration était particulièrement complexe, car nous disposons de plusieurs services backend totalement découplés et de deux applications React partageant une grande partie de leur code. Si vous vous lancez dans une démarche similaire, j'espère que cette série d'articles vous permettra de gagner un peu de temps.
Nightwatch et les appels API pour des tests « full stack » propres, rigoureux et isolés
L'objectif est de rédiger une série de tests permettant de vérifier de manière rigoureuse la façon dont les applications front-end et les services back-end fonctionnent ensemble. De plus, comme nos utilisateurs sont répartis dans le monde entier et utilisent Chrome, Firefox et IE sur Windows et Mac, nous voulons nous assurer que nos applications fonctionnent correctement quelle que soit la combinaison de navigateur, de système d'exploitation et de taille d'écran que nous nous engageons à prendre en charge.
Voici un aperçu de débogage de ce que nous exécutons via l'intégration continue (CI) à chaque push sur GitHub, pour chaque branche :
Remarque importante : les tests ci-dessus s'exécutent sans simulacres. Tous les services backend sont disponibles pour ces tests.
Piège n° 1 : J’ai souvent vu des « tests de fumée » full stack écrits pour des wrappers Phantom ou Selenium qui exécutent en série une longue chaîne de commandes, chacune s’appuyant sur la précédente, en se connectant puis en parcourant l’ensemble des fonctionnalités d’une application pour s’assurer que tout fonctionne. Chaque fois qu’il faut modifier ou ajouter quelque chose, cela provoque une défaillance en aval. Non merci.
Piège B : De la même manière, j'ai vu des ingénieurs créer des sortes de macros qui exécutent des actions courantes, lesquelles sont ensuite répétées dans le navigateur pour reproduire des états courants. C'est efficace, mais lent, surtout si ces étapes impliquent beaucoup d'interactions avec l'interface utilisateur.
Cette fois-ci, nous avons évité ces deux problèmes en nous appuyant sur des utilitaires d'API pour configurer les tests exactement comme nous en avions besoin :
Ces premières Promises recèlent quelques astuces utiles. La fonction `helpers.createTeam` utilise notre API pour créer une nouvelle équipe et un nouvel utilisateur (merci à faker.js), puis utilise les identifiants générés pour se connecter à Nightwatch…
… puis, séparément, pour récupérer un jeton API qu'il pourra utiliser pour les requêtes suivantes :
La fonction simple `assign() ` stocke les objets renvoyés en vue d'une utilisation ultérieure.
Cela signifie que , pour chaque série de tests, nous créons une nouvelle équipe et un nouvel utilisateur, ainsi que tous les objets de données dont nous aurons besoin pour les tests. Cela peut sembler excessif, mais nous disposons désormais de tests automatisés dont nous sommes sûrs qu’ils sont isolés… ce qui signifie également qu’ils peuvent être exécutés en parallèle. Nous y reviendrons plus en détail.
Alignement des objets de page Nightwatch avec React Router
Les « objets de page » de Nightwatch mettent en œuvre une idée proposée par Martin Fowler ici, selon laquelle il est possible de séparer le code qui s'intègre à une page donnée des tests qui vérifient son fonctionnement.
Nous avons constaté que cela jouait un rôle essentiel dans la réutilisation du code de test, et cela nous aide à réfléchir de manière logique aux fonctionnalités que nous développons, en particulier lorsqu’il s’agit de fonctionnalités complexes.
Cet avantage est particulièrement évident lorsqu'on examine une pull request plus volumineuse. D'un simple coup d'œil, on comprend tout de suite de quoi il s'agit :
Vous pouvez ensuite consulter l'objet de page pour vous faire une idée de la manière dont nous utilisons l'interface utilisateur pour répondre aux exigences des tests :
Vous remarquerez peut-être que l'archivage d'un modèle nécessite d'accepter une boîte de dialogue de confirmation SweetAlert . Nous avons défini des concepts tels que les modaux et SweetAlert en tant qu'objets de page Nightwatch distincts ; il est donc très simple de prendre en compte cette étape. De plus, comme celle-ci est intégrée à la commande de l'objet de page, le test n'a pas besoin de savoir qu'une confirmation est requise.
Une fois que vous avez fini de passer en revue les tests et les objets de page, il n’y a qu’un pas à franchir pour examiner les composants React qui implémentent l’objet de page, ainsi que l’infrastructure Redux/Thrift qui gère les besoins de ces composants React. Si vous avez déjà eu les yeux qui se brouillent en essayant de parcourir une pull request volumineuse, croyez-moi, c’est un formidable pas en avant.
Comme React Router nous offre une vue d'ensemble très claire de notre plan du site, nous pouvons nous assurer que les objets de page restent synchronisés avec nos routes pour les deux applications, et tout est prêt.
Améliorez Nightwatch grâce à des outils puissants tels que le glisser-déposer
NightwatchJS est une couche d'abstraction Selenium qui offre d'emblée la plupart des fonctionnalités de navigation dans l'interface utilisateur dont nous avons besoin. Mais il permet également d'injecter des scripts pour améliorer vos capacités de test.
Dans notre application, nous utilisons abondamment laformidable bibliothèque React DnDde Dan Abramov. Pour la tester, Aaron a mis en place une commande Nightwatch qui encapsule Drag Mock d’Andy Wermke de la manière suivante :
Cela nous permet d'intégrer des actions de glisser-déposer sur les objets de la page :
Ce qui nous offre un moyen simple et sémantique de définir les comportements de glissement dans les tests :
Tout comme l'utilisation de JSX a permis à nos designers de soumettre davantage de PR de conception, ces techniques de test nous permettent de faire appel à des ingénieurs en automatisation QA encore assez débutants pour nous aider à rédiger des tests de grande qualité, tandis que les testeurs QA manuels de l'équipe peuvent repérer très tôt dans le processus toute interprétation erronée des exigences. Tout le monde y gagne.
Le rôle des tests d'intégration « full stack »
Cela dit, aucune de ces techniques ne remplace la nécessité de disposer d'unités de test solides. Nous utilisons Mocha pour tester les réducteurs, les actions, etc. de Redux, et Enzyme pour tester les composants React de manière isolée. Nous considérons également qu'une série de tests a échoué si le code source ne respecte pas les règles d'ESLint.
Mais j’accorde bien plus d’importance à ces tests « full stack », car ils nous confirment que, lorsque l’on retire les simulateurs et que l’on connecte tous les services backend, nous disposons toujours de toutes les fonctionnalités que nous promettons à nos utilisateurs, et pas seulement dans Chrome sur un écran Cinema Display à Soma, mais aussi en conditions réelles, sur un ordinateur portable Vista défectueux fonctionnant sous IE11 sur une plate-forme pétrolière. C’est là que notre logiciel doit tenir ses promesses, et Nightwatch nous aide à avoir confiance dans le fait que nous y parvenons.











