Créer facilement des tests fonctionnels avec Cypress

Fabien

Fabien, Architecte web 10 mars 2020

Durant la période de consolidation de l'un de nos projets client, nous nous sommes demandé quel outil utiliser pour réaliser les tests fonctionnels. 

Nous avons finalement choisi Cypress - une solution open-source - et vous expliquons pourquoi dans cet article. 

Tests unitaires VS tests fonctionnels

Nous avons l’habitude de séparer les tests en deux catégories (même s’il en existe davantage) : les tests unitaires et les tests fonctionnels.

Les tests unitaires

  • Ils ont pour but de vérifier que la relation d’entrée / sortie donnée par la spécification est bien réalisée
  • Ils se limitent à tester des règles métiers au niveau d’une classe / fonction tout en étant indépendants du framework (ceux-ci étant déjà testés)
  • Toutes les classes n’ont pas forcément d’utilité à être testées, celles contenant de la logique métier sont à privilégier

Les tests fonctionnels

Il existe deux types de tests fonctionnels : les tests fonctionnels de progression et les tests fonctionnels de non régression.

  • Ils ont pour but de s’assurer que le comportement fonctionnel obtenu est bien conforme avec celui attendu.
  • Ils permettent de vérifier l’état général de l’application

Notre besoin initial

Afin de réaliser les tests fonctionnels, nous avions besoin d’un outil qui : 

  • Simule un navigateur pour se rapprocher des conditions réelles
  • Réalise une suite d’actions prouvant que l’application est stable en ayant les comportements prévus
  • Permette de tester le rendu côté navigateur des scripts JS

Choix de l’outil de tests fonctionnels

Notre équipe technique étant habituée à PHP et Symfony, nous nous sommes d'abord orientés vers cet écosystème. 

Nous y avons trouvé deux outils populaires :

  • Le composant natif de Symfony avec son client HTTP : il ne permet néanmoins pas de tester la dynamisation des pages côté client
  • La librairie Panther qui utilise Chrome ou Firefox grâce aux protocoles WEBDriver du W3C et les ChromeDriver et GeckoDriver

Test de Panther

La librairie Panther avait tout pour répondre à notre besoin. Elle permet en effet de créer des tests fonctionnels en simulant un navigateur et tester le résultat des scripts JavaScript.

De plus, elle permet l'utilisation de librairies natives à Symfony auxquelles nous sommes habitués.

Cependant, le fait que le WebDriver ne supporte pas les requêtes POST nous a assez vite bloqués. 

Finalement, ça a été l’occasion de tester un outil de l’écosystème JavaScript : Cypress.

Cypress : un outil efficace pour réaliser des tests fonctionnels

Cypress est plus qu’une librairie, c’est un framework de tests frontend. Il est exécuté dans le navigateur avec un accès bas niveau (accès à la console, aux événements AJAX, au DOM) sans WebDriver.

Il utilise de nombreuses librairies JS connues telles que :

  • Mocha
  • Chai
  • Chai-jQuery
  • Sinon.JS
  • jQuery, Lodash, Moment, Minimatch

Cypress détecte automatiquement les navigateurs disponibles. Il est capable de lancer les tests dans Electron, Chrome mais aussi depuis la version 4 dans Firefox et Edge en version Chromium.

Cypress au quotidien

Le test runner

Le développement de tests fonctionnels est assez visuel avec Cypress grâce à son test runner. 

Pour le lancer, il suffit de modifier le fichier package.json afin d'ajouter le script comme précisé dans la documentation 

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

Puis, lancer la commande...

npm run cypress:open

... pour afficher le test runner :

Nous avons, entre autres, accès à la liste des tests, le choix du navigateur et un récapitulatif de la configuration. Un clic sur un test pour le lancer :

A gauche, on retrouve le log de tout ce qui est fait et à droite la prévisualisation du test :

  • Au survol d’un log, la partie prévisualisation affiche l’application à l’état du log
  • Un clic sur une ligne du log permet d’avoir davantage d’informations

Le test runner peut aussi nous faciliter la création des tests grâce à la possibilité de récupérer le sélecteur d’un élément : 

Après avoir collé, on obtient dans cet exemple :

cy.get('#email1')

Son intégration complète dans le navigateur permet d’avoir accès à la console pour déboguer les tests.

Des scénarios lisibles

Les tests écrits avec Cypress sont lisibles et faciles à comprendre grâce aux librairies JS incluses.

/// 
describe('Post Resource', function() {
  it('Creating a New Post', function() {
    cy.visit('/posts/new')     

    cy.get('input.post-title')
      .type('My First Post')

    cy.get('input.post-body')
      .type('Hello, world!')

    cy.contains('Submit')
      .click()

    cy.url()
      .should('include', '/posts/my-first-post')

    cy.get('h1')
      .should('contain', 'My First Post')
  })
})

À noter sur l’écriture des scénarios :

  • Les instructions “context”, “describe”, “specify” et “it” permettent de découper les tests pour les rendre plus lisibles
  • Les hooks “before”, “after”,  “beforeEach”, “afterEach” sont disponibles pour éviter la répétition de code
  • La possibilité de charger des “fixtures”
  • La création de “plugins” pour exécuter du code spécifique pendant les tests
  • La création de “commands” qui seront disponibles dans tous les tests
  • Le support d’ES2015 en natif

La configuration de Cypress

La configuration est réalisée via le fichier cypress.json qui permet de configurer entre autres :

  • Un préfix d’URL pour tous les tests
  • Des variables d’environnement
  • La liste des tests à exécuter ou non
  • Les répertoires des fichiers de sortie (screeshots / vidéos)
  • Le viewport de l’application
  • Gérer les timeout
  • Renseigner un “projectId” pour le dashboard

Cypress gère aussi la notion d’environnement, pour écraser la configuration par les paramètres associés au bon environnement.

Le dashboard Cypress

Un dashboard en ligne est disponible pour centraliser les résultats des tests :

Nous avons accès :

  • à l’historique des tests 
  • aux screenshots / vidéos générés pendant les tests
  • à la durée d’exécution des tests

Le dashboard est disponible en version payante mais aussi en version gratuite de façon limitée.

Les autres fonctionnalités disponibles dans Cypress

Cypress permet aussi de contrôler tout le cycle de vie de requête AJAX / XHR en écoutant les appels réseaux.

Il peut bien sûr être exécuté dans un environnement de CI. Dans ce cas, le test runner graphique n’est pas lancé, mais un log résumé sera affiché

Dans un écosystème Javascript, Cypress peut aller encore plus loin avec :

  • les stub qui permettent de modifier le fonctionnement des fonctions
  • les spy qui permettent d’espionner une fonction pour vérifier les arguments, le nombre d’appels, la valeur de retour et le contexte
  • les clocks pour contrôler les dates et heures de l’application  

Conclusion sur la création de tests fonctionnels avec Cypress

Difficile de faire la liste exhaustive des fonctionnalités offertes par Cypress dans un seul article tellement elles sont nombreuses. Voici néanmoins un résumé des avantages majeur de Cypress, selon notre équipe :

  • Est un outil open-source avec de nouvelles fonctionnalités ajoutées régulièrement
  • S’installe facilement avec NPM
  • Détecte des navigateurs localement
  • Syntaxe des scénarios compréhensible
  • Prend en compte la visibilité des éléments
  • Possibilité de prendre des screenshots mais aussi des vidéos
  • Se configure simplement en JSON
  • Fournit un test runner permettant de développer des tests fonctionnels assez visuels
  • Propose un dashboard en ligne (en option)
  • Beaucoup d’exemples de scénarios de test disponibles à l’installation de Cypress

Pour en savoir plus sur Cypress