Un parcours de test E2E, partie 2 : WebdriverIO vers Cypress
Publié: 2019-11-21Remarque : Il s'agit d'un message de #frontend@twiliosendgrid. Pour d'autres articles d'ingénierie, rendez-vous sur le blog technique.
Dans toutes nos applications frontales, nous avions, et avons toujours, l' objectif suivant : fournir un moyen d'écrire des tests d'automatisation E2E (de bout en bout) cohérents, débogables, maintenables et précieux pour nos applications frontales et de les intégrer à CICD (intégration continue et déploiement continu).
Pour atteindre l'état que nous avons aujourd'hui dans lequel des centaines de tests E2E sont peut-être déclenchés ou exécutés selon un calendrier dans toutes nos équipes frontales de SendGrid, nous avons dû rechercher et expérimenter de nombreuses solutions potentielles en cours de route jusqu'à ce que nous ayons accompli ce principal but.
Nous avons tenté de lancer notre propre solution personnalisée Ruby Selenium développée par des ingénieurs de test dédiés, appelée SiteTestUI alias STUI, dans laquelle toutes les équipes pouvaient contribuer à un référentiel et exécuter des tests d'automatisation multi-navigateurs. Il a malheureusement succombé à des tests lents et instables, à de fausses alarmes, à un manque de contexte entre les dépôts et les langues, à trop de mains dans le même panier, à des expériences de débogage douloureuses et à plus de temps consacré à la maintenance qu'à la valeur ajoutée.
Nous avons ensuite expérimenté une autre bibliothèque prometteuse dans WebdriverIO pour écrire des tests en JavaScript colocalisés avec les dépôts d'application de chaque équipe. Bien que cela ait résolu certains problèmes, renforcé la propriété de l'équipe et nous ait permis d'intégrer des tests avec Buildkite, notre fournisseur CICD, nous avions toujours des tests floconneux qui étaient pénibles à déboguer et difficiles à écrire en plus de traiter des bogues et des bizarreries Selenium trop similaires. .
Nous voulions éviter un autre STUI 2.0 et avons commencé à explorer d'autres options. Si vous souhaitez en savoir plus sur nos leçons apprises et nos stratégies découvertes lors de la migration de STUI vers WebdriverIO, consultez la partie 1 de la série d'articles de blog.
Dans cette dernière partie de la série d'articles de blog, nous couvrirons notre parcours de STUI et WebdriverIO à Cypress et comment nous avons traversé des migrations similaires dans la configuration de l'infrastructure globale, l'écriture de tests E2E organisés, l'intégration avec nos pipelines Buildkite et la mise à l'échelle pour autres équipes frontales de l'organisation.
TLDR : Nous avons adopté Cypress plutôt que STUI et WebdriverIO et nous avons atteint tous nos objectifs en écrivant de précieux tests E2E à intégrer à CICD. Une grande partie de notre travail et des leçons apprises de WebdriverIO et de STUI s'est bien transposée dans la façon dont nous utilisons et intégrons les tests Cypress aujourd'hui.
Table des matières
Explorer et atterrir sur Cypress
Passer de STUI et WebdriverIO à Cypress
Étape 1 : Installation des dépendances pour Cypress
Étape 2 : Configurations et scripts d'environnement
Premier passage des configurations d'environnement et des scripts
Évolution des configurations d'environnement et des scripts
Étape 3 : Implémenter les tests E2E localement
Étape 4 : dockeriser les tests
Étape 5 : Intégration avec CICD
Étape 6 : Comparer Cypress et WebdriverIO/STUI
Étape 7 : Mise à l'échelle vers d'autres équipes frontales
Ce que nous attendons avec impatience avec Cypress
Adopter Cypress dans le futur
Explorer et atterrir sur Cypress
Lorsque nous avons recherché des alternatives à WebdriverIO, nous avons vu d'autres wrappers Selenium comme Protractor et Nightwatch avec un ensemble de fonctionnalités similaire à WebdriverIO, mais nous avons pensé que nous aurions très probablement rencontré de longues configurations, des tests feuilletés et un débogage et une maintenance fastidieux sur la route.
Heureusement, nous sommes tombés sur un nouveau cadre de test E2E appelé Cypress, qui présentait des configurations rapides, des tests rapides et débogables exécutés dans le navigateur, un stubbing de demande de couche réseau et, surtout, ne pas utiliser Selenium sous le capot.
Nous nous sommes émerveillés de fonctionnalités impressionnantes telles que les enregistrements vidéo, l'interface graphique Cypress, le service de tableau de bord payant et la parallélisation à essayer. Nous étions prêts à faire des compromis sur la prise en charge de plusieurs navigateurs en faveur de tests précieux réussissant systématiquement contre Chrome avec un répertoire d'outils à notre disposition pour implémenter, déboguer et maintenir les tests pour nos développeurs et QA.
Nous avons également apprécié les frameworks de test, les bibliothèques d'assertions et tous les autres outils choisis pour que nous ayons une approche plus standardisée des tests dans toutes nos équipes frontend. Ci-dessous, nous avons fourni une capture d'écran des différences entre une solution telle que WebdriverIO et Cypress. Si vous souhaitez en savoir plus sur les différences entre les solutions Cypress et Selenium, vous pouvez consulter leur documentation sur son fonctionnement.
Dans cet esprit, nous nous sommes engagés à tester Cypress comme une autre solution pour écrire des tests E2E rapides, cohérents et déboguables à intégrer éventuellement à Buildkite pendant le CICD. Nous avons également délibérément fixé un autre objectif consistant à comparer Cypress aux solutions précédentes basées sur Selenium afin de déterminer en fin de compte, par des points de données, si nous devons continuer à chercher ou à créer nos suites de tests avec Cypress à l'avenir. Nous avions prévu de convertir les tests WebdriverIO existants et tous les autres tests hautement prioritaires encore dans STUI en tests Cypress et de comparer nos expériences de développement, la vitesse, la stabilité, les durées d'exécution des tests et la maintenance des tests.
Passer de STUI et WebdriverIO à Cypress
Lors du passage de STUI et WebdriverIO à Cypress, nous l'avons abordé systématiquement via la même stratégie de haut niveau que celle que nous avons utilisée lorsque nous avons tenté notre migration de STUI vers WebdriverIO dans nos référentiels d'applications frontales. Pour plus de détails sur la façon dont nous avons accompli ces étapes pour WebdriverIO, veuillez vous référer à la partie 1 de la série d'articles de blog. Les étapes générales de la transition vers Cypress impliquaient les éléments suivants :
- Installation et configuration des dépendances pour se connecter à Cypress
- Établir des configurations d'environnement et des commandes de scripts
- Implémentation de tests E2E qui passent localement contre différents environnements
- Dockeriser les tests
- Intégration de tests dockerisés avec Buildkite, notre fournisseur CICD
Afin d'atteindre nos objectifs secondaires, nous avons également ajouté des étapes supplémentaires pour comparer Cypress avec les solutions Selenium précédentes et pour éventuellement faire évoluer Cypress dans toutes les équipes frontend de l'organisation :
6. Comparaison de Cypress en termes d'expériences de développement, de vitesse et de stabilité des tests par rapport à WebdriverIO et STUI
7. Mise à l'échelle vers d'autres équipes frontales
Étape 1 : Installation des dépendances pour Cypress
Pour être opérationnel rapidement avec Cypress, tout ce que nous avions à faire était de "npm install cypress" dans nos projets et de démarrer Cypress pour la première fois pour qu'il soit automatiquement configuré avec un fichier de configuration "cypress.json" et un dossier cypress
. avec des appareils de démarrage, des tests et d'autres fichiers de configuration pour les commandes et les plugins. Nous avons apprécié la façon dont Cypress est venu avec Mocha en tant que testeur, Chai pour les assertions, et Chai-jQuery et Sinon-Chai pour encore plus d'assertions à utiliser et à enchaîner. Nous n'avons plus eu à passer beaucoup de temps à rechercher quels testeurs, rapporteurs, assertions et bibliothèques de services installer et utiliser par rapport à nos débuts avec WebdriverIO ou STUI. Nous avons immédiatement exécuté certains des tests générés avec leur interface graphique Cypress et exploré les nombreuses fonctionnalités de débogage à notre disposition telles que le débogage du voyage dans le temps, le terrain de jeu du sélecteur, les vidéos enregistrées, les captures d'écran, les journaux de commandes, les outils de développement de navigateur, etc.
Nous l'avons également configuré plus tard avec Eslint et TypeScript pour des règles de vérification et de formatage de type statique supplémentaires à suivre lors de la validation du nouveau code de test Cypress. Nous avons d'abord eu quelques problèmes avec la prise en charge de TypeScript et certains fichiers devaient être des fichiers JavaScript comme ceux centrés autour des fichiers de plugins, mais pour la plupart, nous avons pu vérifier la majorité de nos fichiers pour nos tests, objets de page et commandes.
Voici un exemple de structure de dossiers qu'une de nos équipes frontend a suivie pour incorporer des objets de page, des plugins et des commandes :
Étape 2 : Configurations et scripts d'environnement
Après avoir rapidement installé et configuré Cypress pour qu'il s'exécute localement, nous avions besoin d'un moyen d'exécuter nos tests Cypress avec des paramètres différents pour chaque environnement et nous voulions prendre en charge les mêmes cas d'utilisation que nos commandes WebdriverIO nous permettaient de faire. Voici une liste illustrant la plupart des cas d'utilisation de la manière dont nous voulions exécuter ces tests et pourquoi nous souhaitions les prendre en charge :
- Contre un serveur de développement Webpack s'exécutant sur localhost (c'est-à-dire http://localhost:8000) et ce serveur de développement pointerait vers une certaine API d'environnement (c'est-à-dire https://testing.api.com ou https://staging.api. com) comme les tests ou la mise en scène.
Pourquoi? Parfois, nous devons apporter des modifications à notre application Web locale, telles que l'ajout de sélecteurs plus spécifiques pour nos tests afin d'interagir avec les éléments de manière plus robuste ou nous étions en train de développer une nouvelle fonctionnalité et devions ajuster et valider les tests d'automatisation existants. passerait localement contre nos nouveaux changements de code. Chaque fois que le code de l'application a changé et que nous n'avons pas encore poussé vers l'environnement déployé, nous avons utilisé cette commande pour exécuter nos tests sur notre application Web locale. - Par rapport à une application déployée pour un certain environnement (c'est-à-dire https://testing.app.com ou https://staging.app.com) comme les tests ou la mise en scène
Pourquoi? D'autres fois, le code de l'application ne change pas, mais nous devrons peut-être modifier notre code de test pour corriger certaines irrégularités ou nous nous sentirons suffisamment en confiance pour ajouter ou supprimer des tests sans apporter de modifications frontales. Nous avons beaucoup utilisé cette commande pour mettre à jour ou déboguer les tests localement par rapport à l'application déployée afin de simuler plus précisément l'exécution de nos tests dans CICD. - Exécution dans un conteneur Docker sur une application déployée pour un certain environnement, comme les tests ou la mise en scène
Pourquoi? Ceci est destiné à CICD afin que nous puissions déclencher l'exécution de tests E2E dans un conteneur Docker, par exemple sur l'application déployée intermédiaire et nous assurer qu'ils réussissent avant de déployer le code en production ou lors d'exécutions de tests planifiées dans un pipeline dédié. Lors de la configuration initiale de ces commandes, nous avons effectué de nombreux essais et erreurs pour créer des conteneurs Docker avec différentes valeurs de variables d'environnement et tester pour voir les tests appropriés exécutés avec succès avant de les connecter à notre fournisseur CICD, Buildkite.
Premier passage des configurations d'environnement et des scripts
Lorsque nous avons expérimenté la configuration de Cypress pour la première fois, nous l'avons fait dans le référentiel qui couvre https://app.sendgrid.com, une application Web qui comprend des pages de fonctionnalités telles que l'authentification de l'expéditeur, l'activité des e-mails et la validation des e-mails, et nous avons inévitablement partagé nos découvertes et nos apprentissages avec les équipes derrière notre application Web Marketing Campaigns, qui englobe le domaine https://mc.sendgrid.com. Nous souhaitions exécuter nos tests E2E dans notre environnement de staging et avons utilisé l'interface de ligne de commande de Cypress et des options telles que --config
ou --env
pour accomplir nos cas d'utilisation.
Afin d'exécuter les tests Cypress sur l'application Web localement sur, par exemple, http://127.0.0.1:8000
ou sur l'URL de l'application de staging déployée, nous avons ajusté l'indicateur de configuration baseUrl
dans la commande et ajouté des variables d'environnement supplémentaires telles que testEnv
pour vous aider. chargez certains luminaires ou données de test spécifiques à l'environnement dans nos tests Cypress. Par exemple, les clés d'API utilisées, les utilisateurs créés et d'autres ressources peuvent être différents d'un environnement à l'autre. Nous avons utilisé testEnv
pour basculer ces luminaires ou ajouter une logique conditionnelle spéciale si certaines fonctionnalités n'étaient pas prises en charge dans un environnement ou si la configuration de test différait et nous accédions à l'environnement via un appel comme Cypress.env(“testEnv”)
dans nos spécifications.
Nous avons ensuite organisé nos commandes cypress:open:*
pour représenter l'ouverture de l'interface graphique Cypress pour que nous sélectionnions nos tests à exécuter via l'interface utilisateur lorsque nous avons développé localement et cypress:run:*
pour désigner l'exécution de tests en mode sans tête, ce qui était plus adapté. pour s'exécuter dans un conteneur Docker pendant CICD. Ce qui venait après open
ou l' run
serait l'environnement afin que nos commandes se lisent facilement comme npm run cypress:open:localhost:staging
pour ouvrir l'interface graphique et exécuter des tests sur un serveur de développement Webpack local pointant vers des API de staging ou npm run cypress:run:staging
pour exécuter des tests en mode headless sur l'application et l'API de staging déployées. Les scripts package.json
Cypress sont sortis comme ceci :
Évolution des configurations d'environnement et des scripts
Dans un autre projet, nous avons fait évoluer nos commandes et configurations Cypress pour tirer parti d'une logique de nœud dans le fichier cypress/plugins/index.js
afin d'avoir un fichier cypress.json
de base et des fichiers de configuration séparés qui seraient lus en fonction d'une variable d'environnement appelée configFile
pour charger un fichier de configuration spécifique. Les fichiers de configuration chargés seraient ensuite fusionnés avec le fichier de base pour éventuellement pointer vers un serveur intermédiaire ou un faux serveur principal.
Au cas où vous vous poseriez des questions sur le serveur backend fictif, nous avons développé un serveur Express avec des points de terminaison backend renvoyant simplement des réponses variables de données JSON statiques et de codes d'état (c'est-à-dire 200, 4XX, 5XX) en fonction des paramètres de requête transmis dans les requêtes. Cela a débloqué l'interface pour continuer à développer les flux de pages avec des appels réseau réels vers le faux serveur backend avec des réponses imitant à quoi ressemblera l'API réelle lorsqu'elle sera disponible à l'avenir. Nous pourrions également simuler facilement différents niveaux de succès et de réponses d'erreur pour nos différents états d'interface utilisateur qui seraient autrement difficiles à reproduire en production, et puisque nous ferions des appels réseau déterministes, nos tests Cypress seraient moins floconneux en tirant sur le même réseau demandes et réponses à chaque fois.
Nous avions un fichier de base cypress.json
qui comprenait des propriétés partagées pour les délais d'attente généraux, l'ID de projet pour se connecter au service de tableau de bord Cypress dont nous parlerons plus tard, et d'autres paramètres comme indiqué ci-dessous :
Nous avons créé un dossier de config
dans le dossier cypress
pour contenir chacun de nos fichiers de configuration, tels que localhostMock.json
pour exécuter notre serveur de développement Webpack local sur un serveur d'API factice local ou staging.json
pour s'exécuter sur l'application et l'API de staging déployées. Ces fichiers de configuration à différencier et à fusionner avec la configuration de base ressemblaient à ceci :
Les fichiers de configuration CICD avaient un fichier JSON encore plus simple car nous devions définir dynamiquement les variables d'environnement pour tenir compte de l'URL de base variable du service Docker et des hôtes d'API de serveur fictifs que nous approfondirons plus tard.
Dans notre fichier cypress/plugins/index.js
, nous avons ajouté une logique pour lire une variable d'environnement appelée configFile
définie à partir d'une commande Cypress qui finirait par lire le fichier correspondant dans le dossier config
et le fusionnerait avec la base cypress.json
comme ci-dessous :
Afin d'écrire des commandes Cypress sensées avec des variables d'environnement définies pour nos cas d'utilisation, nous avons tiré parti d'un Makefile
qui ressemblait à ce qui suit :
Avec ces commandes soigneusement disposées dans un Makefile, nous pourrions rapidement faire des choses comme make cypress_open_staging
ou make cypress_run_staging
dans nos scripts npm `package.json`.
Avant, nous avions l'habitude de placer certaines commandes sur une longue ligne qu'il serait difficile d'éditer sans erreur. Heureusement, le Makefile a aidé à mieux répartir les choses avec une interpolation lisible des variables d'environnement dans les commandes Cypress sur plusieurs lignes. Nous pourrions rapidement définir ou exporter des variables d'environnement telles que configFile
pour le fichier de configuration d'environnement à charger, BASE_URL
pour visiter nos pages, API_HOST
pour différents environnements backend ou SPECS
pour déterminer les tests à exécuter avant de lancer l'une des commandes Makefile.
Nous avons également utilisé les commandes Makefile pour d'autres longs scripts npm et commandes Docker, telles que la création de nos actifs Webpack, l'installation de dépendances ou l'exécution de commandes simultanément avec d'autres. Nous traduirions finalement certaines commandes Makefile dans la section des scripts package.json
, bien que cela ne soit pas nécessaire si quelqu'un voulait uniquement utiliser le Makefile, et cela ressemblerait à ceci :
Nous avons délibérément laissé de côté une grande partie des commandes CICD de Cypress car ce n'étaient pas des commandes qui seraient utilisées dans le développement quotidien et nous avons ainsi simplifié le package.json
. Plus important encore, nous avons pu voir en un coup d'œil toutes les commandes Cypress liées au serveur fictif et au serveur de développement Webpack local par rapport aux environnements de développement et lesquelles "ouvrent" l'interface graphique plutôt que "s'exécutent" en mode sans tête.
Étape 3 : Implémenter les tests E2E localement
Lorsque nous avons commencé à implémenter des tests E2E avec Cypress, nous avons référencé nos tests existants de WebdriverIO et STUI pour les convertir et ajouté de nouveaux tests pour d'autres fonctionnalités hautement prioritaires, allant des simples vérifications de l'état aux flux de chemin heureux compliqués. La traduction des objets de page existants et des fichiers de test de WebdriverIO ou STUI en objets de page et spécifications équivalents dans Cypress s'est avérée être un jeu d'enfant. Cela a en fait abouti à un code beaucoup plus propre qu'auparavant avec une attente moins explicite pour les éléments et une meilleure chaînabilité des assertions et d'autres commandes Cypress.
Par exemple, les étapes générales des tests sont restées les mêmes du point de vue de l'utilisateur final, de sorte que le travail de conversion a impliqué le mappage de l'API WebdriverIO ou STUI à l'API Cypress de la manière suivante :
- De nombreuses commandes sont apparues et ont fonctionné de manière similaire au point où nous remplacions presque simplement
$
oubrowser
parcy
ouCypress
, c'est-à-dire en visitant une page via$(“.button”).click()
àcy.get(“.button”).click()
,browser.url()
àcy.visit()
, ou$(“.input”).setValue()
àcy.get(“.input”).type()
- L'utilisation
$
ou$$
se transforme généralement ency.get(...)
oucy.contains(...)
c'est-à-dire$$(“.multiple-elements-selector”)
ou$(“.single-element-selector”)
transformé ency.get(“.any-element-selector”)
,cy.contains(“text”)
, oucy.contains(“.any-selector”)
- Suppression des appels superflus
$(“.selector”).waitForVisible(timeoutInMs)
,$(“.selector”).waitUntil(...)
, ou$(“.selector”).waitForExist()
en faveur de laisser Cypress par défaut gérer les tentatives et la récupération des éléments encore et encore aveccy.get('.selector')
etcy.contains(textInElement)
. Si nous avions besoin d'un délai d'attente plus long que la valeur par défaut, nous utiliserionscy.get('.selector', { timeout: longTimeoutInMs })
puis, après avoir récupéré l'élément, nous enchaînerions la commande d'action suivante pour faire quelque chose avec l'élément, c'est-à-direcy.get(“.selector”).click()
. - Commandes personnalisées avec navigateur.
addCommand('customCommand, () => {})` turned into `Cypress.Commands.add('customCommand', () => {})
et fait `cy.customCommand()` - Faire des requêtes réseau pour l'installation ou le démontage via l'API à l'aide d'une bibliothèque appelée
node-fetch
et l'envelopper dansbrowser.call(() => return fetch(...))
et/oubrowser.waitUntil(...)
conduit à faire des requêtes HTTP dans un serveur Cypress Node viacy.request(endpoint)
ou un plugin personnalisé que nous avons défini et effectué des appels commecy.task(taskToHitAPIOrService)
. - Auparavant, lorsque nous devions attendre qu'une demande réseau importante se termine éventuellement sans modification notable de l'interface utilisateur, nous devions parfois recourir à l'utilisation de
browser.pause(timeoutInMs)
, mais avec Cypress, nous avons amélioré cela avec la fonctionnalité de remplacement du réseau et avons pu écouter et attendez que la requête spécifique se termine aveccy.server()
,cy.route(“method”, “/endpoint/we/are/waiting/for).as(“endpoint”)`, and `cy.wait(“@endpoint”)
avant de lancer l'action qui déclencherait la demande.
Après avoir traduit une grande partie de la syntaxe et des commandes WebdriverIO en commandes Cypress, nous avons apporté le même concept d'avoir un objet de page de base pour les fonctionnalités communes partagées et des objets de page étendus pour chaque page dont nous avions besoin pour les tests. Voici un exemple d'objet de page de base avec une fonctionnalité open()
commune à partager sur toutes les pages.
Un objet de page étendu ajouterait des getters pour les sélecteurs d'éléments, implémenterait la fonctionnalité open()
avec son itinéraire de page et fournirait toute fonctionnalité d'assistance, comme indiqué ci-dessous.
Nos objets de page étendus réels utilisaient également une simple carte d'objets pour conserver tous nos sélecteurs CSS d'éléments en un seul endroit que nous brancherions à nos composants React en tant qu'attributs de données, référence dans les tests unitaires et utiliser comme nos sélecteurs dans les objets de page Cypress. De plus, nos classes d'objets de page variaient parfois en tirant parti du constructeur de classe si, par exemple, un objet de page était réutilisé pour un tas de pages similaires et fonctionnant comme nos pages de suppression et nous passions des arguments pour modifier l'itinéraire ou des propriétés spécifiques.
En remarque, les équipes n'avaient pas besoin d'utiliser des objets de page, mais nous avons apprécié la cohérence du modèle pour conserver les fonctionnalités de page et les références de sélecteur d'éléments DOM avec une structure d'objet de classe standard pour partager des fonctionnalités communes sur toutes les pages. D'autres équipes ont préféré créer de nombreux fichiers différents avec peu de fonctions utilitaires et sans utiliser de classes ES6, mais la chose importante à retenir était de fournir un moyen organisé et prévisible de tout encapsuler et d'écrire des tests pour une meilleure efficacité et maintenabilité des développeurs.
Nous avons adhéré à la même stratégie de test générale utilisée avec nos anciens tests WebdriverIO en essayant de configurer le test autant que possible via l'API. Nous voulions surtout éviter de construire notre état de configuration via l'interface utilisateur pour ne pas introduire de flakiness et de perte de temps pour les pièces que nous n'avions pas l'intention de tester. La plupart des tests impliquaient cette stratégie :
- Configuration ou suppression via l'API - Si nous devions tester la création d'une entité via l'interface utilisateur, nous nous assurerions de supprimer d'abord l'entité via l'API. Indépendamment de la réussite ou de l'échec du test précédent, le test devait être correctement configuré ou supprimé via l'API pour garantir que le test se comporte de manière cohérente et démarre dans les bonnes conditions.
- Connexion à un utilisateur de test dédié via l'API - Nous avons créé des utilisateurs de test dédiés par page ou même par test d'automatisation afin que nos tests soient isolés et ne piétinent pas les ressources de l'autre lorsqu'ils sont exécutés en parallèle. Nous avons fait la même demande que notre page de connexion via l'API et stocké le cookie avant le début du test afin que nous puissions visiter directement la page authentifiée et commencer les étapes de test réelles.
- Automatisation des étapes du point de vue de l'utilisateur final - Après s'être connecté à l'utilisateur via l'API, nous avons visité la page directement et automatisé les étapes qu'un utilisateur final ferait pour terminer un flux de fonctionnalités et vérifier que l'utilisateur voit et interagit avec les bonnes choses le long du chemin.
Afin de réinitialiser le test à son état d'origine prévu, nous nous connecterions à un utilisateur de test dédié via l'API avec une commande globale cy.login
, définirions un cookie pour garder l'utilisateur connecté, effectuerions les appels d'API nécessaires pour renvoyer le l'utilisateur à l'état de départ souhaité via les cy.request(“endpoint”)
ou cy.task(“pluginAction”)
, et visitez la page authentifiée que nous cherchions à tester directement. Ensuite, nous automatiserons les étapes pour accomplir un flux de fonctionnalités utilisateur comme indiqué dans la mise en page de test ci-dessous.
Rappelez-vous les commandes personnalisées dont nous avons parlé pour la connexion, cy.login()
, et la déconnexion, cy.logout()
? Nous les avons facilement implémentés dans Cypress de cette manière afin que tous nos tests se connectent à un utilisateur via l'API de la même manière.
De plus, nous souhaitions automatiser et vérifier certains flux complexes impliquant des emails que nous ne pouvions pas bien faire auparavant avec WebdriverIO ou STUI. Certains exemples incluent l'exportation de l'activité des e-mails vers un CSV, le passage par le flux Envoyer à un collègue pour l'authentification de l'expéditeur ou l'exportation des résultats de la validation des e-mails vers un CSV. Cypress empêche d'accéder à plusieurs superdomaines en un seul test, donc naviguer vers un client de messagerie via une interface utilisateur que nous ne possédons pas était flou et n'était pas une option.
Nous avons plutôt développé des plugins Cypress via leurs cy.task(“pluginAction”)
pour utiliser certaines bibliothèques du serveur Cypress Node pour se connecter à un client/boîte de réception IMAP de test tel que SquirrelMail pour vérifier les e-mails correspondants dans une boîte de réception après avoir invité une action dans l'interface utilisateur et pour suivre les liens de redirection de ces e-mails vers notre domaine d'application Web afin de vérifier que certaines pages de téléchargement s'affichent et complètent efficacement un flux client complet. Nous avons implémenté des plugins qui attendraient l'arrivée des e-mails dans la boîte de réception SquirrelMail en fonction de certaines lignes d'objet, supprimeraient des e-mails, enverraient des e-mails, déclencheraient des événements d'e-mails, interrogeraient les services principaux et effectueraient des configurations et des démontages beaucoup plus utiles via l'API pour nos tests à utiliser.

Pour mieux comprendre ce que nous avons réellement testé avec Cypress, nous avons couvert une pléthore de cas de grande valeur tels que ceux-ci :
- Contrôles de santé pour toutes nos pages , c'est-à-dire visiter l'application - Nous voulions nous assurer que les pages chargées avec du contenu causent parfois certains services backend ou l'hébergement frontend seraient en panne. Nous avons également recommandé d'effectuer ces tests en premier pour développer la mémoire musculaire mentale de la création d'objets de page avec des sélecteurs et des fonctions d'assistance et pour obtenir des tests rapides et fonctionnels exécutés dans un environnement.
- Opérations CRUD sur une page - Nous réinitialiserions toujours les tests en conséquence via l'API, puis testerions spécifiquement la création, la lecture, la mise à jour ou la suppression dans l'interface utilisateur. Par exemple, si nous avons testé la possibilité de créer une authentification de domaine via l'interface utilisateur, quelle que soit la fin du dernier test, nous devions nous assurer que le domaine que nous allions créer via l'interface utilisateur était d'abord supprimé via l'API avant de continuer. avec les étapes automatisées de l'interface utilisateur pour créer le domaine et éviter les collisions. Si nous avons testé la possibilité de supprimer une suppression via l'interface utilisateur, nous nous sommes assurés de créer d'abord la suppression via l'API, puis de poursuivre les étapes.
- Test des filtres de recherche sur une page – Nous avons testé la définition d'un ensemble de filtres de recherche avancés avec l'activité des e-mails et la visite de la page avec les paramètres de requête pour nous assurer que les filtres étaient remplis automatiquement. Nous avons également ajouté des données via l'API pour la validation des e-mails et, une fois de plus, lancé différents filtres de recherche et validé le tableau correspondant aux filtres de recherche de cette page.
- Différents accès utilisateur - Chez Twilio SendGrid, nous avons des comptes parents qui peuvent avoir des coéquipiers avec des étendues ou des autorisations d'accès variables ou des sous-utilisateurs en dessous qui ont également des degrés d'accès variables et se comportent quelque peu comme un compte parent. Les coéquipiers avec un accès en lecture seule ou administrateur pour certaines pages et les sous-utilisateurs verraient ou ne verraient pas certaines choses sur une page, ce qui faciliterait l'automatisation de la connexion à ces types d'utilisateurs et la vérification de ce qu'ils voient ou non dans les tests Cypress.
- Différents packages utilisateur - Nos utilisateurs peuvent également varier dans les types de packages gratuits à payants tels que Essentials, Pro et Premier et ces packages peuvent également voir ou non certaines choses sur une page. Nous nous connections aux utilisateurs avec différents packages et vérifiions rapidement les fonctionnalités, les copies ou les pages auxquelles les utilisateurs avaient accès dans les tests Cypress.
Étape 4 : dockeriser les tests
Lors de l'exécution de chaque étape du pipeline Buildkite sur une nouvelle machine AWS dans le cloud, nous ne pouvions pas simplement appeler npm run cypress:run:staging
car ces machines n'ont pas de nœud, de navigateurs, de notre code d'application ou de toute autre dépendance pour exécuter réellement le Cypress essais. Lorsque nous avons configuré WebdriverIO auparavant, nous devions assembler trois services distincts dans un fichier Docker Compose pour que les services Selenium, Chrome et de code d'application appropriés fonctionnent ensemble pour que les tests soient exécutés.
Avec Cypress, c'était beaucoup plus simple car nous n'avions besoin que de l'image Docker de base de Cypress, cypress/base
, pour configurer l'environnement dans un Dockerfile
et d'un seul service dans un fichier docker-compose.yml
avec notre code d'application pour exécuter le Cypress essais. Nous allons passer en revue une façon de procéder car il existe d'autres images Cypress Docker à utiliser et d'autres façons de configurer les tests Cypress dans Docker. Nous vous encourageons à consulter la documentation Cypress pour d'autres
Pour mettre en place un service avec tout notre code d'application et de test nécessaire pour exécuter les tests Cypress, nous avons créé un Dockerfile
appelé Dockerfile.cypress
et installé tous les node_modules
et copié le code dans le répertoire de travail de l'image dans un environnement Node. Cela serait utilisé par notre service cypress
Docker Compose et nous avons réalisé la configuration Dockerfile
de la manière suivante :
Avec ce Dockerfile.cypress
, nous pouvons intégrer Cypress pour exécuter des spécifications sélectionnées sur une certaine API d'environnement et une application déployée via un service Docker Compose appelé cypress
. Tout ce que nous avions à faire était d'interpoler certaines variables d'environnement telles que SPECS
et BASE_URL
pour exécuter des tests Cypress sélectionnés sur une certaine URL de base via la commande npm run cypress:run:cicd:staging
qui ressemble à ceci, ”cypress:run:cicd:staging”: “cypress run --record --key --config baseUrl=$BASE_URL --env testEnv=staging”
.
Ces variables d'environnement seraient définies via les fichiers de paramètres/configuration du pipeline Buildkite ou exportées dynamiquement lors du déclenchement des tests Cypress à exécuter à partir de notre pipeline de déploiement. Un exemple de fichier docker-compose.cypress.yml
ressemblait à ceci :
Il y a aussi quelques autres choses à observer. Par exemple, vous pouvez voir la variable d'environnement VERSION
qui nous permet de référencer une image Docker taguée spécifique. Nous montrerons plus tard comment nous étiquetons une image Docker, puis réduisons la même image Docker pour que cette version s'exécute avec le code correct pour les tests Cypress.
De plus, vous remarquerez également le BUILDKITE_BUILD_ID
transmis, qui est gratuit avec d'autres variables d'environnement Buildkite pour chaque build que nous lançons, et le drapeau ci-build-id
. Cela active la fonction de parallélisation de Cypress et lorsque nous définissons un certain nombre de machines allouées pour les tests Cypress, il saura automatiquement comment faire tourner ces machines et séparer nos tests pour qu'ils s'exécutent sur tous ces nœuds de machine afin d'optimiser et d'accélérer notre test. temps d'exécution.
Enfin, nous avons également profité du montage en volume et de la fonction d'artefacts de Buildkite. Nous téléchargeons les vidéos et les captures d'écran pour qu'elles soient directement accessibles via l'onglet "Artefacts" de l'interface utilisateur de Buildkite au cas où nous serions à court de nos enregistrements de test alloués payés pour le mois ou si nous ne pouvions pas accéder au service de tableau de bord. Chaque fois que l'on exécute la commande Cypress "run" en mode sans tête, il y a une sortie dans les dossiers cypress/videos
et cypress/screenshots
pour que l'on puisse les examiner localement et nous montons simplement ces dossiers et les téléchargeons sur Buildkite pour nous en tant que sécurité intégrée.
Étape 5 : Intégration avec CICD
Une fois que nous avons réussi à exécuter les tests Cypress dans un conteneur Docker dans différents environnements, nous avons commencé à intégrer Buildkite, notre fournisseur CICD. Buildkite a fourni des moyens d'exécuter des étapes dans un fichier .yml
sur nos machines AWS avec des scripts Bash et des variables d'environnement définis soit dans le code, soit via les paramètres de pipeline Buildkite du référentiel dans l'interface utilisateur Web. Buildkite nous a également permis de déclencher ce pipeline de test à partir de notre pipeline de déploiement principal avec des variables d'environnement exportées et nous réutiliserions ces étapes de test pour d'autres pipelines de test isolés qui s'exécuteraient selon un calendrier pour que nos QA puissent surveiller et examiner.
À un niveau élevé, nos pipelines de test Buildkite pour Cypress ainsi que nos précédents pipelines WebdriverIO ont partagé les étapes similaires suivantes :
- Configurez les images Docker . Construisez, étiquetez et poussez les images Docker requises pour les tests jusqu'au registre afin que nous puissions les retirer ultérieurement.
- Exécutez les tests en fonction des configurations de variables d'environnement . Déroulez les images Docker balisées pour la version spécifique et exécutez les commandes appropriées sur un environnement déployé pour exécuter des suites de tests sélectionnées à partir des variables d'environnement définies.
Voici un exemple de fichier pipeline.cypress.yml
qui illustre la configuration des images Docker à l'étape « Build Cypress Docker Image » et l'exécution des tests à l'étape « Run Cypress tests » :
Une chose à noter est la première étape, "Build Cypress Docker Image", et comment elle configure l'image Docker pour le test. Il a utilisé la commande Docker Compose build
pour créer le service cypress
avec tout le code de test de l'application et l'a étiqueté avec la variable d'environnement la latest
et ${VERSION}
afin que nous puissions éventuellement extraire cette même image avec la balise appropriée pour cette version dans un étape future. Chaque étape peut s'exécuter quelque part sur une machine différente dans le cloud AWS, de sorte que les balises identifient de manière unique l'image pour l'exécution spécifique de Buildkite. Après avoir étiqueté l'image, nous avons poussé la dernière image étiquetée avec la version vers notre registre Docker privé pour qu'elle soit réutilisée.
Dans l'étape "Exécuter les tests Cypress", nous réduisons l'image que nous avons construite, étiquetée et poussée dans la première étape et démarrons le service Cypress pour exécuter les tests. Sur la base de variables d'environnement telles que SPECS
et BASE_URL
, nous exécuterions des fichiers de test spécifiques sur un certain environnement d'application déployé pour cette version spécifique de Buildkite. Ces variables d'environnement seraient définies via les paramètres du pipeline Buildkite ou seraient déclenchées dynamiquement à partir d'un script Bash qui analyserait un champ de sélection Buildkite pour déterminer quelles suites de tests exécuter et dans quel environnement.
Lorsque nous sélectionnons les tests à exécuter pendant notre pipeline de déploiement Buildkite CICD et déclenchons un pipeline de tests déclenchés dédié avec certaines variables d'environnement exportées, nous suivons les étapes du fichier pipeline.cypress.yml
pour y arriver. Voici un exemple de déclenchement des tests après le déploiement d'un nouveau code dans un environnement de branche de fonctionnalité à partir du pipeline de déploiement :
Les tests déclenchés s'exécuteraient dans un pipeline séparé et après avoir suivi le lien "Build #639", cela nous amènerait aux étapes de construction pour le test déclenché comme ci-dessous :
En réutilisant le même fichier pipeline.cypress.yml
pour nos pipelines Cypress Buildkite dédiés exécutés selon un calendrier, nous avons des versions telles que celle exécutant nos tests E2E "P1", les plus prioritaires, comme le montre la photo ci-dessous :
Tout ce que nous avons à faire est de définir les variables d'environnement appropriées pour des éléments tels que les spécifications à exécuter et l'environnement principal à atteindre dans les paramètres du pipeline Buildkite. Ensuite, nous pouvons configurer une construction planifiée Cron, qui se trouve également dans les paramètres du pipeline, pour démarrer toutes les heures et nous sommes prêts à partir. We would then create many other separate pipelines for specific feature pages as needed to run on a schedule in a similar way and we would only vary the Cron schedule and environment variables while once again uploading the same `pipeline.cypress.yml` file to execute.
In each of those “Run Cypress tests” steps, we can see the console output with a link to the recorded test run in the paid Dashboard Service, the central place to manage your team's test recordings, billing, and other Cypress stats. Following the Dashboard Service link would take us to a results view for developers and QAs to take a look at the console output, screenshots, video recordings, and other metadata if required such as this:
Step 6: Comparing Cypress vs. WebdriverIO/STUI
After diving into our own custom Ruby Selenium solution in STUI, WebdriverIO, and finally Cypress tests, we recorded our tradeoffs between Cypress and Selenium wrapper solutions.
Avantages
- It's not another Selenium wrapper – Our previous solutions came with a lot of Selenium quirks, bugs, and crashes to work around and resolve, whereas Cypress arrived without the same baggage and troubles to deal with in allowing us full access to the browser.
- More resilient selectors – We no longer had to explicitly wait for everything like in WebdriverIO with all the
$(.selector).waitForVisible()
calls and now rely oncy.get(...)
and cy.contains(...)
commands with their default timeout. It will automatically keep on retrying to retrieve the DOM elements and if the test demanded a longer timeout, it is also configurable per command. With less worrying about the waiting logic, our tests became way more readable and easier to chain. - Vastly improved developer experience – Cypress provides a large toolkit with better and more extensive documentation for assertions, commands, and setup. We loved the options of using the Cypress GUI, running in headless mode, executing in the command-line, and chaining more intuitive Cypress commands.
- Significantly better developer efficiency and debugging – When running the Cypress GUI, one has access to all of the browser console to see some helpful output, time travel debug and pause at certain commands in the command log to see before and after screenshots, inspect the DOM with the selector playground, and discern right away at which command the test failed. In WebdriverIO or STUI we struggled with observing the tests run over and over in a browser and then the console errors would not point us toward and would sometimes even lead us astray from where the test really failed in the code. When we opted to run the Cypress tests in headless mode, we got console errors, screenshots, and video recordings. With WebdriverIO we only had some screenshots and confusing console errors. These benefits resulted in us cranking out E2E tests much faster and with less overall time spent wondering why things went wrong. We recorded it took less developers and often around 2 to 3 times less days to write the same level of complicated tests with Cypress than with WebdriverIO or STUI.
- Network stubbing and mocking – With WebdriverIO or STUI, there was no such thing as network stubbing or mocking in comparison to Cypress. Now we can have endpoints return certain values or we can wait for certain endpoints to finish through
cy.server()
andcy.route()
. - Less time to set up locally – With WebdriverIO or STUI, there was a lot of time spent up front researching which reporters, test runners, assertions, and services to use, but with Cypress, it came bundled with everything and started working after just doing an
npm install cypress.
- Less time to set up with Docker – There are a bunch of ways to set up WebdriverIO with Selenium, browser, and application images that took us considerably more time and frustration to figure out in comparison to Cypress's Docker images to use right out of the gate.
- Parallelization with various CICD providers – We were able to configure our Buildkite pipelines to spin up a certain number of AWS machines to run our Cypress tests in parallel to dramatically speed up the overall test run time and uncover any flakiness in tests using the same resources. The Dashboard Service would also recommend to us the optimal number of machines to spin up in parallel for the best test run times.
- Paid Dashboard Service – When we run our Cypress tests in a Docker container in a Buildkite pipeline during CICD, our tests are recorded and stored for us to look at within the past month through a paid Dashboard Service. We have a parent organization for billing and separate projects for each frontend application to check out console output, screenshots, and recordings of all of our test runs.
- Tests are way more consistent and maintainable – Tests passed way more consistently with Cypress in comparison to WebdriverIO and STUI where the tests kept on failing so much to the point where they were often ignored. Cypress tests failing more often signaled actual issues and bugs to look into or suggested better ways to refactor our tests to be less flaky. With WebdriverIO and STUI, we wasted a lot more time in maintaining those tests to be somewhat useful, whereas with Cypress, we would every now and then adjust the tests in response to changes in the backend services or minor changes in the UI.
- Tests are faster – Builds passed way more consistently and overall test run times would be around 2 to 3 times faster when run serially without parallelization. We used to have overall test runs that would take hours with STUI and around 40 minutes with WebdriverIO, but now with way more tests and with the help of parallelization across many machine nodes, we can run over 200 tests in under 5 minutes .
- Room to grow with added features in the future – With a steady open-source presence and dedicated Cypress team working towards releasing way more features and improvements to the Cypress infrastructure, we viewed Cypress as a safer bet to invest in rather than STUI, which would require us to engineer and solve a lot of the headaches ourselves, and WebdriverIO, which appeared to feel more stagnant in new features added but with the same baggage as other Selenium wrappers.
Les inconvénients
- Lack of cross-browser support – As of this writing, we can only run our tests against Chrome. With WebdriverIO, we could run tests against Chrome, Firefox, Safari, and Opera. STUI also provided some cross-browser testing, though in a much limited form since we created a custom in-house solution
- Cannot integrate with some third-party services – With WebdriverIO, we had the option to integrate with services like BrowserStack and Sauce Labs for cross-browser and device testing. However, with Cypress there are no such third-party integrations but there are some plugins with services like Applitools for visual regression testing available. STUI, on the other hand, also had some small integrations with TestRail , but as a compromise, we log out the TestRail links in our Cypress tests so we can refer back to them if we needed to.
- Requires workarounds to test with iframes – There are some issues around handling iframes with Cypress. We ended up creating a global Cypress command to wrap how to deal with retrieving an iframe's contents as there is no specific API to deal with iframes like how WebdriverIO does.
To summarize our STUI, WebdriverIO, and Cypress comparison, we analyzed the overall developer experience (related to tools, writing tests, debugging, API, documentation, etc.), test run times, test passing rates, and maintenance as displayed in this table:
Following our analysis of the pros and cons of Cypress versus our previous solutions, it was pretty clear Cypress would be our best bet to accomplish our goal of writing fast, valuable, maintainable, and debuggable E2E tests we could integrate with CICD.
Though Cypress lacked features such as cross-browser testing and other integrations with third-party services that we could have had with STUI or WebdriverIO, we most importantly need tests that work more often than not and with the right tools to confidently fix broken ones. If we ever needed cross-browser testing or other integrations we could always still circle back and use our knowledge from our trials and experiences with WebdriverIO and STUI to still run a subset of tests with those frameworks.
We finally presented our findings to the rest of the frontend organization, engineering management, architects, and product. Upon demoing the Cypress test tools and showcasing our results between WebdriverIO/STUI and Cypress, we eventually received approval to standardize and adopt Cypress as our E2E testing library of choice for our frontend teams.
Step 7: Scaling to Other Frontend Teams
After successfully proving that using Cypress was the way to go for our use cases, we then focused on scaling it across all of our frontend teams' repos. We shared lessons learned and patterns of how to get up and running, how to write consistent, maintainable Cypress tests, and of how to hook those tests up during CICD or in scheduled Cypress Buildkite pipelines.
To promote greater visibility of test runs and gain access to a private monthly history of recordings, we established our own organization to be under one billing method to pay for the Dashboard Service with a certain recorded test run limit and maximum number of users in the organization to suit our needs.
Once we set up an umbrella organization, we invited developers and QAs from different frontend teams and each team would install Cypress, open up the Cypress GUI, and inspect the “Runs” and “Settings” tab to get the “Project ID” to place in their `cypress.json` configuration and “Record Key” to provide in their command options to start recording tests to the Dashboard Service. Finally, upon successfully setting up the project and recording tests to the Dashboard Service for the first time, logging into the Dashboard Service would show that team's repo under the “Projects” tab like this:
When we clicked a project like “mako”, we then had access to all of the test runs for that team's repo with quick access to console output, screenshots, and video recordings per test run upon clicking each row as shown below:
For more insights into our integration, we set up many separate dedicated test pipelines to run specific, crucial page tests on a schedule like say every couple hours to once per day. We also added functionality in our main Buildkite CICD deploy pipeline to select and trigger some tests against our feature branch environment and staging environment.
Comme on pouvait s'y attendre, cela a rapidement fait exploser nos tests enregistrés alloués pour le mois, d'autant plus que plusieurs équipes contribuent et déclenchent des tests de différentes manières. Par expérience, nous vous recommandons de garder à l'esprit le nombre de tests exécutés selon un calendrier, la fréquence d'exécution de ces tests et les tests exécutés pendant le CICD. Il peut y avoir des exécutions de tests redondantes et d'autres domaines à être plus frugaux, tels que le rappel de la fréquence des exécutions de tests planifiées ou éventuellement la suppression totale de certains pour déclencher des tests uniquement pendant le CICD.
La même règle de frugalité s'applique à l'ajout d'utilisateurs, car nous avons mis l'accent sur l'accès aux seuls développeurs et AQ des équipes frontales qui utiliseront intensivement le service de tableau de bord plutôt qu'aux cadres supérieurs et à d'autres personnes en dehors de ces équipes pour occuper ces places limitées.
Ce que nous attendons avec impatience avec Cypress
Comme nous l'avons mentionné précédemment, Cypress a démontré beaucoup de promesses et de potentiel de croissance dans la communauté open source et avec son équipe dédiée chargée de fournir des fonctionnalités plus utiles à utiliser avec nos tests E2E. Un grand nombre des inconvénients que nous avons soulignés sont actuellement en cours de résolution et nous attendons avec impatience des choses telles que :
- Prise en charge de plusieurs navigateurs - C'est un problème important, car une grande partie de notre refus d'adopter Cypress provient de son utilisation de Chrome uniquement par rapport aux solutions basées sur Selenium, qui prennent en charge des navigateurs tels que Firefox, Chrome et Safari. Heureusement, des tests plus fiables, maintenables et débogables ont gagné pour notre organisation et nous espérons renforcer nos suites de tests avec davantage de tests multi-navigateurs à l'avenir lorsque l'équipe Cypress publiera une telle prise en charge multi-navigateurs.
- Réécriture de la couche réseau - C'est également un problème énorme car nous avons tendance à utiliser l'API Fetch de manière intensive dans nos nouvelles zones React et dans les anciennes zones d'application Backbone/Marionette, nous utilisions toujours jQuery AJAX et les appels normaux basés sur XHR. Nous pouvons facilement supprimer ou écouter les demandes dans les zones XHR, mais nous avons dû faire quelques solutions de contournement avec des polyfills de récupération pour obtenir le même effet. La réécriture de la couche réseau est censée aider à atténuer ces douleurs.
- Améliorations progressives du service de tableau de bord - Nous avons déjà constaté récemment de nouvelles modifications de l'interface utilisateur du service de tableau de bord et nous espérons continuer à le voir se développer avec davantage de visualisations de statistiques et de ventilations de données utiles. Nous utilisons également beaucoup la fonction de parallélisation et vérifions souvent nos enregistrements de test défaillants dans le service de tableau de bord, de sorte que toute amélioration itérative de la mise en page et/ou des fonctionnalités serait agréable à voir.
Adopter Cypress dans le futur
Pour notre organisation, nous avons apprécié l'efficacité du développeur, le débogage et la stabilité des tests Cypress lorsqu'ils sont exécutés sous le navigateur Chrome. Nous avons réalisé des tests cohérents et précieux avec moins de maintenance sur la route et avec de nombreux outils pour développer de nouveaux tests et corriger ceux qui existent déjà.
Dans l'ensemble, la documentation, l'API et les outils à notre disposition l'emportaient de loin sur les inconvénients. Après avoir expérimenté l'interface graphique Cypress et le service de tableau de bord payant, nous ne voulions absolument pas revenir à WebdriverIO ou à notre solution Ruby Selenium personnalisée.
Nous avons connecté nos tests à Buildkite et atteint notre objectif de fournir un moyen d'écrire des tests d'automatisation E2E cohérents, débogables, maintenables et précieux pour nos applications frontales à intégrer à CICD . Nous avons prouvé avec des preuves au reste des équipes frontales, aux ingénieurs supérieurs et aux propriétaires de produits les avantages de l'adoption de Cypress et de l'abandon de WebdriverIO et STUI.
Des centaines de tests ultérieurs dans les équipes frontend de Twilio SendGrid et nous avons détecté de nombreux bogues dans notre environnement de staging et avons pu corriger rapidement tous les tests instables de notre côté avec beaucoup plus de confiance que jamais auparavant. Les développeurs et les QA ne craignent plus l'idée d'écrire des tests E2E, mais ont maintenant hâte de les écrire pour chaque nouvelle fonctionnalité que nous publions ou pour chaque fonctionnalité plus ancienne qui pourrait utiliser une couverture plus étendue.