Nightwatch et BrowserStack : Aimez vos tests End to End

le

Les tests End To End avec Selenium, c’est chiant. Vous devez lancer le driver, le client, enregistrer votre session pour pouvoir reproduire vos tests, importer votre scénario, et recommencer à chaque fois que votre UI change.

CasperJS était assez pratique pour ça, mais vu la suite chaotique qui s’annonce pour le support de PhantomJS, associé au fait que vous ne pouvez compter que sur V8 pour tester votre UI (bon ok, vous avez aussi SlimerJS pour Firefox, mais bon…), on se retrouve assez rapidement limité.

C’est là qu’intervient Nightwatch. Ca tourne avec Selenium, mais avec la possibilité de plugger le bousin avec BrowserStack ou encore SauceLabs. Le potentiel qui s’en dégage est énorme : vous avez accès à des tonnes de VM qui vous permettent de tester votre application sur des configs diverses et variées, genre un Windows XP avec Internet Explorer 8, ou un OSX avec la dernière version de Safari ou de Firefox. Le tout en faisant des screens et même des vidéos des sessions de tests, et en récupérant un report de vos tests.

On se fait une petite démo ?

Config

Rien de particulier pour utiliser Nightwatch :

mkdir nightwatch
cd nightwatch
npm init

On installe nightwatch globalement :

sudo npm install -g nightwatch

On va aussi installer selenium en version standalone via NPM :

npm install --save-dev selenium-server-standalone-jar

On créé un fichier nightwatch.json à la racine du projet :

touch nightwatch.json

On va aussi créer un dossier pour stocker nos logs, un autre pour nos reports et bien entendu un dossier pour nos tests :

mkdir nw
cd nw
mkdir logs
mkdir reports
mkdir tests

On va aussi installer le driver Chrome pour le moment :

npm install chromedriver

Et on commence à écrire la config dont on a besoin, on défini le path de selenium en fonction de NPM (adaptez en fonction de la version installée) :

{
 "src_folders" : ["nw/tests"],
 "output_folder" : "nw/reports",
 "custom_commands_path" : "",
 "custom_assertions_path" : "",
 "page_objects_path" : "",
 "globals_path" : "",
 "selenium" : {
 "start_process" : true,
 "server_path" : "./node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-3.4.0.jar",
 "log_path" : "nw/logs",
 "host" : "127.0.0.1",
 "port" : 4444,
 "cli_args" : {
 "webdriver.chrome.driver" : "./node_modules/chromedriver/bin/chromedriver",
 "webdriver.ie.driver" : ""
 }
 },

"test_settings" : {
 "default" : {
 "launch_url" : "http://google.com",
 "selenium_port" : 4444,
 "selenium_host" : "localhost",
 "silent": true,
 "screenshots" : {
 "enabled" : true,
 "path" : ""
 },
 "desiredCapabilities": {
 "browserName": "chrome",
 "javascriptEnabled": true,
 "acceptSslCerts": true
 }
 }
 }
}

Reste à écrire notre premier test. On va faire simple et vérifier la présence d’un wrapper (#content) dans le CSS de… mon blog. On créé un fichier demo.test.js dans notre dossier nw/tests :

module.exports = {
 "Test démo" : function (browser) {
 browser
 .url("http://www.babonaux.com/")
 .waitForElementVisible('body', 2000)
 .expect.element('#content').to.be.present;
 browser.end();
 }
};

On attend deux choses :

  • Que la page contienne un body
  • Qu’il existe un ID #content dans la page

On a plus qu’à lancer notre test :

nightwatch

Youpi !

On pourrait tester une erreur en changeant volontairement l’ID de notre wrapper dans notre test :

module.exports = {
 "Test démo" : function (browser) {
 browser
 .url("http://www.babonaux.com/")
 .waitForElementVisible('body', 2000)
 .expect.element('#contentbidon').to.be.present;
 browser.end();
 }
};

Notre premier test (body) passe, mais le second non. Tout est normal.

Pluggons tout ça à Browserstack

Avant tout, créez vous un compte sur Browserstack. De base vous avez accès à suffisamment de minutes d’utilisation pour cette démo. Dans Account -> Settings, vous pourrez récupérer votre username et votre access key.

On va créer un fichier de conf supplémentaire à la racine du projet :

touch nightwatch.browserstack.js

On va lui coller les infos dont on a besoin :

nightwatch_config = {
 "src_folders" : ["nw/tests/"],
 "selenium" : {
 "start_process" : false,
 "host" : "hub.browserstack.com",
 "port" : 80
 },
 "common_capabilities": {
 "browserstack.user": "votreusername",
 "browserstack.key": "votreaccesskey"
 },

"test_settings": {
 "default": {},
 "chrome": {
 "desiredCapabilities": {
 "browser": "chrome"
 }
 },
 "firefox": {
 "desiredCapabilities": {
 "browser": "firefox"
 }
 },
 "ie": {
 "desiredCapabilities": {
 "browser": "internet explorer"
 }
 }
 }
}

// Code to support common capabilites
for(var i in nightwatch_config.test_settings){
 var config = nightwatch_config.test_settings[i];
 config['selenium_host'] = nightwatch_config.selenium.host;
 config['selenium_port'] = nightwatch_config.selenium.port;
 config['desiredCapabilities'] = config['desiredCapabilities'] || {};
 for(var j in nightwatch_config.common_capabilities){
 config['desiredCapabilities'][j] = config['desiredCapabilities'][j] || nightwatch_config.common_capabilities[j];
 }
}

module.exports = nightwatch_config;

Notez qu’on change de driver pour Nightwatch, on ne passe plus par Selenium mais directement par le hub Browserstack qui se chargera du reste.

On défini aussi les browsers que l’on veut tester, ici Chrome, Firefox et Internet Explorer.

La dernière partie du fichier de config permet de merger les capabilities.

Désormais on doit fournir le fichier de config Browserstack lorsque l’on souhaite effectuer un test :

nightwatch -c nightwatch.browserstack.js -e chrome,firefox,ie

On passe ici, le fichier de config ainsi que les browsers que l’on souhaite tester. Le terminal nous donne le résultat sous la même forme que le test précédent, à l’exception près que l’on trouve trois tests (correspondants aux 3 navigateurs) :

Il y a mieux

Jusqu’ici on a simplement décentralisé les tests. On reviendra sur le fait de monter un véritable environnement d’intégration continue avec GitLab CI par exemple, où l’on pourra lancer nos tests unitaires, nos tests end to end et pourquoi pas builder en cas de success.

Ce qui nous intéresse ici, c’est la possibilité de retrouver les tests sous forme de vidéo sur Browserstack. Allez dans Automate, et vous retrouverez l’ensemble de vos tests :

Un peu d’interactions

On va améliorer un peu notre test en ajoutant un ou deux évènements. Admettons que, sur mon blog, dans le formulaire de recherche, on souhaite rechercher le terme ReactJS.

On prend la classe du champ de recherche ( .search-field) et celle du bouton submit (.search-submit).

module.exports = {
 "Test démo" : function (browser) {
 browser
 .url("http://www.babonaux.com/")
 .waitForElementVisible('body', 1000)
 .setValue('.search-field', 'reactjs')
 .waitForElementVisible('.search-submit', 1000)
 .click('.search-submit')
 .pause(1000)
 .assert.urlContains('reactjs')
 .end();

browser.end();
 }
};

On lance le test localement :

Tout est ok !

On fait la même chose avec Browserstack :

C’est good !

Voici une des trois vidéos enregistrée par Browserstack :

En deux mots

Le fait d’automatiser les tests end to end apporte un réel intérêt en terme d’intégration continue. Non seulement, si vous créez un pipeline digne de ce nom avec GitLab, vous vous assurerez de ne rien péter lors d’un passage en staging ou en prod, mais vous aurez en plus des informations sur ce qui a échoué pendant les test.

C’est encore plus pratique si vous devez livrer du code qui tourne sur de vieilles versions d’IE.

Vu le pricing de Browserstack, et le gain apporté, n’hésitez pas à saouler votre CTO pour demander du budget 😉

 

2 commentaires Ajoutez le votre

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *