Mobile Web

Mise en place de Cypress.js dans Gitlab CI – partie 1

by Pierre Cavalet 9 juin 2020

Cette article est divisé en deux parties. La première explique comment mettre en place des tests end-to-end dans une application très simple, en découvrant quelques fonctionnalités très pratiques de Cypress.js. La deuxième (en cours d’écriture) expliquera comment intégrer ces tests dans Gitlab CI, de la mise en place des jobs et pipelines aux différents workflows de tests que l’on utilise.

    Passer de Nightwatch.js à Cypress.js

    Cypress.js a été pour nous une révolution. Nous avons utilisé Nightwatch.js pendant un long moment. Nous en étions assez content, mais quand nous avons testé Cypress.js, il était assez clair pour nous qu’il était pertinent de changer, principalement pour deux raisons :

    • Stabilité : nous avons eu beaucoup de mauvaises surprises (principalement des tests qui échouent une fois mais réussissent le reste du temps ou des problèmes d’interaction avec certains elements, click, type…) en utilisant différents frameworks de tests end-to-end. Cypress.js n’est pas parfait mais il est beaucoup plus stable, en grande partie parce qu’il n’utilise pas Selenium.
    • Experience de développement : enregistrement de videos, progression des tests, logger, debugger, attente automatique, time travel, reload automatique, etc. Cypress.js possède une quantité d’outils considérable pour les développeurs, ce qui fait de son utilisation un véritable plaisir.

    J’aime travailler sur des projets simples pour illustrer mes propos. On va donc utiliser ce (faux) site web pour explorer ce que peut faire Cypress.

    Il est temps d’aider Jordan, un développeur curieux qui a décidé d’apprendre à tester son application. Jordan a choisi (sans aucune influence) de tester son application avec Cypress.js.

    Premiers pas avec Cypress.js

    Jordan a son site en production, prêt à être testé. La première chose qu’il doit faire est d’installer Cypress.

    npm install cypress --save-dev

    Il ajoute ensuite un nouveau script dans son package.json pour pouvoir lancer ses tests.

    "scripts": {
      "cypress:open": "cypress open"   
    }

    Il peut ensuite lancer la commande :

    npm run cypress:open

    Et voilà ! Jordan est prêt. L’installation n’est pas très complexe.

    Note: Cypress.js génère beaucoup de tests. C’est utile pour voir à quoi ça ressemble, mais comme ce n’est pas vraiment le sujet. Jordan va supprimer tous les exemples qui ont été créés dans le dossier integration .

    Écrire son premier test

    Jordan se demande :

    Certaines personnes ont beaucoup d’inspiration, d’autres beaucoup moins. Regardons déjà ce que fait ce site web pour savoir ce qu’il faut tester.

    Jordan sait qu’une grande partie de son trafic arrive directement sur sa page d’accueil (car il utilise des outils analytics, c’est pas n’importe qui). En arrivant sur la page d’accueil, les utilisateurs choisissent ensuite de créer un compte ou de se connecter. Et c’est tout. Pas le site le plus intéressant, mais bon.

    Bien joué Jordan.

    Avec un peu d’aide (vraiment pas beaucoup), Jordan crée un nouveau fichier qu’il appelle homepage.spec.js et le remplit avec le contenu suivant :

    • cy.visit() est utilisé pour aller sur une URL passée en paramètre.
    • cy.get() est utilisé pour récupérer un élément dans le DOM et .should('exist') vérifie que cet élément existe bien dans le DOM.

    Note: cy.get() utilise les query selectors pour sélectionner les éléments ans le DOM. data-cy est un data-attribute (data-*) que l’on peut mettre sur n’importe quelle balise HTML (ou presque). Il est préférable d’utiliser des data-attributes plutôt que des ids ou des classes pour ne pas entrer en conflit avec les modifications liées à l’affichage de la page (changement de style par exemple). Points bonus pour les data-attributes qui servent aussi à expliquer pourquoi ils sont là, tous les data-cy sont là pour permettre à Cypress de sélectionner les éléments (cf.Cypress.js Best practices).

    Jordan peut maintenant lancer son test directement depuis l’interface graphique de Cypress.

    Interface Cypress.js

    Jusqu’ici tout est bon.

    Tests avec des interactions utilisateur

    Lorsqu’on souhaite tester des fonctionnalités qui sont dépendantes de données (comme la connexion par exemple), il faut être sûr que, par exemple pour la connexion, le compte qu’on utilise pour se connecter existe (ou n’existe pas si c’est ce qu’on souhaite tester). Le compte que Jordan va utiliser pour son test sera toujours le même et a été créé dans ce but : servir de compte de test.
    Un autre exemple pourrait être un article. Si nous avions un blog, le but du test de l’article ne serait pas d’en prendre un au hasard depuis la page d’accueil. Nous voudrions garder toujours le même pour garder le test consistant. Revenons au site de Jordan.

    Note: Ce site accepte toutes les adresses emails et tous les mots de passe (oui c’est un faux site).

    Jordan doit trouver quel workflow de login il veut tester en premier.

    Et voici à quoi ressemble le test qu’il écrit :

    Les commandes Cypress sont assez simples à comprendre si on parle un minimum anglais. Regardons ce que font ces nouvelles commandes :

    cy.url().should('eq', 'XXX')

    Celle-ci permet de récupérer l’URL courante puis d’utiliser l’assertion should pour vérifier que l’URL est bien égale ('eq') au second paramètre.

    type et click peuvent être utilisés avec get pour taper dans un champ ou cliquer sur un élément.

    Commandes Cypress.js

    Le test fonctionne sans soucis.

    Je voudrais maintenant poser une question simple. En regardant le code au-dessus qui (je pense) n’est pas très difficile à produire, à quel point ces tests pourraient être utilisés pour votre site web sur vos fonctionnalités principales par rapport au temps nécessaire pour les mettre en place ?

    Je pense personnellement qu’ils sont un excellent investissement. Je vais continuer cette article sur les fonctionnalités de Cypress, car je souhaite garder cette article structuré. Si j’étais à la place de Jordan, j’arrêterai de développer des suites de tests et j’essayerai d’intégrer les tests que j’ai déjà écrits dans ma CI.

    Le plus important n’est pas de couvrir toutes les fonctionnalités de votre site web mais plutôt de couvrir les workflows les plus importants pour être sûr qu’ils ne cassent pas. On peut toujours ajouter des suites de tests plus tard. Retournons sur le site de Jordan.

    Commandes personnalisées de Cypress

    Ne t’inquiète pas Jordan, on va faire ça mieux. Imaginons qu’on utilise un routeur. Il serait bien plus simple de pouvoir écrire des instructions de navigation de cette façon plutôt que de taper les URLs :

    cy.goTo('home')
    cy.goTo('login')
    cy.goTo('signup')

    On peut créer une commande personnalisée goTo pour répondre à ce besoin. Commençons par créer un “faux” router. L’implémentation dépendra de votre router mais l’idée reste la même. Voici donc notre router services/router.js :

    Maintenant qu’on a un router, on peut l’utiliser dans notre fichier support/commands.js .

    Et on peut maintenant utiliser cette commande dans notre suite de tests (pas besoin d’utiliser require pour récupérer la commande):

    Cet exemple est simplifié car il ne prend pas en compte les paramètres du router et ce genre de chose, mais l’idée reste la même et il suffit simplement de passer les paramètres à la commande et de les réinjecter dans le router.

    Les “tasks” de Cypress

    Attention ! Ce workflow ressemble à celui de connexion mais il y a un piège.

    On pourrait juste ouvrir un client Gmail et récupérer le code directement depuis le client pas vrai ? NON.

    Premièrement, Cypress ne nous laisse pas changer de domaine.  On peut toujours trouver un contournement, mais ce qu’il faut retenir, c’est qu’on ne veut pas passer par l’interface de Gmail car elle peut changer et donc casser nos tests.

    Ce qu’on veut faire, c’est utiliser l’API de Gmail (ou une autre API) pour récupérer l’email, et extraire le code de son contenu pour ensuite l’injecter dans notre suite de tests. On peut faire ce genre de chose grâce aux tasks de Cypress.

    Une task (ou tâche en français) est juste une fonction qui sera exécutée quand elle sera déclenchée. Ce qui la rend particulière est que cette fonction ne s’exécute pas dans le navigateur, mais dans un environnement Node.js, ce qui veut dire qu’on peut faire ce qu’on veut (plus ou moins), car on a accès à l’API de Node.js. On peut par exemple lire un fichier avec le package fs …

    … ou on peut installer un package qui permet de lire un email via une API et récupérer notre code dans l’email. 😃

    Note: Puisque c’est un peu long à mettre en place, on ne va pas vraiment récupérer le code depuis Gmail. On utilisera à la place une “fausse” API qui renvoie le code (toujours le même). Si vous souhaitez le mettre en place, vous pouvez utiliser ce package et faire la même chose avec un peu plus de configuration.

    Après avoir lu la documentation, Jordan écrit sa “task” dans le dossier plugins en s’assurant d’installer axios pour faire son appel API.

    npm install axios

    Puisqu’on retourne une promise, Cypress attendra que la promise soit résolue (ou rejetée).

    Il peut maintenant utiliser sa “task” dans la suite de tests :

    Et oui, Cypress tapera le code avant de cliquer sur le bouton submit.

    Task Cypress.js

    Cette première partie était une introduction à Cypress.js. On peut faire beaucoup de choses avec cet outil. Rappelez-vous que le but n’est pas créer une usine de tests trop compliquée à maintenir. Démarrez avec peu de tests très stables et ajoutez des tests au fur et à mesure. Le plus important est de pouvoir tester les fonctionnalités qui ont beaucoup de valeurs et de faire confiance à ses tests.

    Dans le prochain article, on réutilisera le code que l’on a produit et on l’intégrera dans Gitlab CI. Stay tuned.

    Pierre Cavalet

    Pierre Cavalet

    Expert technique

    Développeur et expert technique chez Kaliop, je travaille principalement sur des technologies Javascript. J'aime travailler sur de nouveaux projets innovants.

    Commentaires

    Ajouter un commentaire

    Votre commentaire sera modéré par nos administrateurs

    Vous avez un projet ? Nos équipes répondent à vos questions

    Contactez-nous