Ce billet est le second d’une série sur la création d’un environnement de test pour des projets web. Aujourd’hui nous parlerons d’IHM, c’est-à-dire comment tester que l’interface (visuelle) de mon site n’est pas cassée sous tel ou tel navigateur.
Je rappelle que l’objectif ce ces billets / outils est de pouvoir dire “Vous n’avez pas de raison valable de ne pas tester” :)
La question de tester une interface graphique est complexe pour plusieurs raisons :
Au fil du temps, j’ai testé pas mal d’outils de test de régression. Tous s’appuient sur des comparaisons de captures d’écrans (du site en entier, ou de blocs (divs, etc.) du site).
Navigateurs headless :
Vrais navigateurs (qui plus est ces outils ont des connecteurs vers des solutions de virtualisation externe, de type SauceLabs ou BrowserStack) :
Sass :
Pour les curieux, ceux que je n’ai fait que survoler :
Nous allons donc utiliser Gemini. Voici un exemple de rapport HTML que l’on souhaite obtenir :
Si le site a subi des régression, les écarts seront mis en surbrillance comme suit:
Là encore, j’ai préparé une image Docker pour vous:
docker pull qualiboo/testing-gemini
On va s’appuyer sur le fichier docker-compose.yml
que l’on a créé la dernière fois.
gemini:
image: roukmoute/testing-gemini
links:
- hub
- firefox
- chrome
volumes:
- ./gemini:/var/work
hub:
image: qualiboo/testing-hub
ports:
- 4444:4444
firefox:
image: qualiboo/testing-node-firefox
ports:
- 5900
links:
- hub
chrome:
image: qualiboo/testing-node-chrome
ports:
- 5900
links:
- hub
Vous constatez que l’on utilise Selenium, avec des noeuds Chrome et Firefox.
Vérifions l’installation. La commande suivante doit afficher la version de gemini:
docker-compose run gemini version
Nous allons procéder en deux temps :
gemini capture
) ;gemini test
).Pour cela, créez un dossier ./gemini/suite
et créez-y le fichier premier-test.js
avec le contenu suivant :
var gemini = require('gemini');
gemini.suite('homepage', function(suite) {
suite
.setUrl('/')
.setCaptureElements('#nav-menu');
.capture('menu');
});
Le code (JavaScript) est assez simple : on capture la div
dont l’id est #nav-menu
depuis la racine du site.
Maintenant, créez le fichier ./gemini/.gemini.yml
qui va permettre de configurer Gemini :
rootUrl: http://qualiboo.com
gridUrl: http://hub:4444/wd/hub
browsers:
chrome:
desiredCapabilities:
browserName: chrome
firefox:
desiredCapabilities:
browserName: firefox
Nous indiquons ici à Gemini l’URL de base du site, les navigateurs souhaités, et comment se connecter à Selenium Grid..
Lancez la capture du référentiel (ça prend quelques secondes):
docker-compose run gemini capture
Vérifiez bien à chaque fois que vous faites une capture
que les images générées (dossier ./gemini/gemini/screens
) correspondent à vos attentes. Elle serviront de référentiel pour les tests.
Voilà, les tests peuvent être lancés :
docker-compose run gemini test
Après quelques secondes/minutes, vous voilà avec un “beau” rapport HTML dans ./gemini/gemini-report/index.html
. Il ne reste plus qu’à l’ouvrir dans votre navigateur préferé…
Avant toute chose, il faut savoir que le monde de tests d’IHM n’est pas parfait. La version du ChromeDriver actuelle pour Linux (2.20) ne permet pas de capturer un bloc qui est plus grand que le viewport
du navigateur. Si vous voulez capturer toute la page (le body
), il faudra passer par Firefox.
Il est simple avec Gemini de forcer certains tests à être exécutés uniquement dans Firefox ou Chrome. Dans le fichier ./gemini/.gemini.yml
ajoutez le contenu suivant:
(...)
sets:
firefox:
files:
- suite/firefox-only
browsers:
- firefox
chrome:
files:
- suite/chrome-only
browsers:
- chrome
Tous les tests qui seront placés dans le dosser ./gemini/suite/firefox-only
seront désormais lancés uniquement par firefox (et même chose pour ./gemini/suite/chrome-only
).
Comme nous souhaitons capturer la page entière (le body
), plaçons notre fichier de test (./gemini/suite/premier-test.yml
) dans le dossier firefox-only
Nous allons tester notre site sous des résolutions différentes ; pour cela, modifiez le fichier premier-test.yml
.
Nous allons changer la résolution de l’écran avant chaque test, et cette fois nous capturons donc le body
:
var gemini = require('gemini');
gemini.suite('homepage', function(suite) {
suite
.setUrl('/')
.setCaptureElements('body')
.capture('homepage', function (actions) {
actions.setWindowSize(1200, 1024).wait(1000);
})
.capture('homepage tablet', function (actions) {
actions.setWindowSize(768, 1024).wait(1000);
})
.capture('homepage mobile', function (actions) {
actions.setWindowSize(320, 568).wait(1000)
});
});
N’oubliez pas de mettre à jour le référentiel de screenshots :
docker-compose run gemini capture
A vous désormais de lancer les tests à votre guise (par exemple à chaque Push sur votre dépôt, à l’aide de Jenkins).
Je l’ai évoqué, un problème récurrent des tests de régression d’IHM concerne le contenu dynamique (publicités, actualités…). Il faut trouver un moyen de faire abstraction de ce type de contenu.
Le seul moyen simple que j’ai trouvé consiste à remplacer ce contenu par du “Lorem ipsum”. Il faut alors, avant chaque test, exécuter un script JavaScript pour ce faire:
suite
.setUrl('/')
.setCaptureElements('body')
.before(function(actions, find) {
actions.executeJS(function(window) {
// replacing images
$('img.my-class').attr('src', '');
// replacing some texts
$('p.another-class, .title, (etc.)').html('Lorem ipsum dolor sit amet');
// advertising
$('.pub').html('PUBLICITE');
// etc.
})
.capture(...)
Dès lors, toutes les images et contenus dynamiques sont remplacés. Il est assez simple de factoriser ce code dans un fichier à part pour le réutiliser partout.
Le contenu du site a changé, donc, oui, nos tests sont alors incomplets et éloignés de la réalité. Mais si on ne le fait pas, le risque est que ces tests ne soient jamais pertinents car fondés uniquement sur de faux-positifs. La suppression des publicités est un compromis pour être pragmatique.
Vous l’avez vu, vous avez là un moyen simple de tester l’IHM de votre site sous différentes résolutions, à l’aide de Docker. Si vous avez un feedback, n’hésitez pas à laisser un commentaire ; et si ce billet vous plaît, n’hésitez pas à le partager :)
© Jean-François Lépine, 2013 - 2024