CasperJS : les tests fonctionnels sous stéroïdes


Technique

Qu’est-ce que CasperJS ?

CasperJS est un utilitaire open source, écrit en javascript et basé sur PhantomJS qui permet de tester des scénarios de navigation à travers un site internet.

CasperJS permet de définir des scénarios de navigation par actions. Par exemple, remplir un formulaire de login avec telles ou telles données. Lors de la mise en place de tests fonctionnels, CasperJS pourrait permettre de vérifier que l’on est bien redirigé soit vers son compte soit vers la page de login avec un message d’erreur, en fonction des données envoyées au formulaire.

CasperJS n’est pas uniquement un outil de test fonctionnel bien sûr. On peut aussi s’en servir pour monitorer un site internet, renvoyer des screenshots en cas de comportement non-attendu. Il est par exemple possible de créer un crawler qui va cliquer sur l’ensemble des liens d’un site et renvoyer un rapport avec les pages et les liens menant à des erreurs 404.

Ce qui distingue CasperJS des autres outils de test fonctionnel (par exemple Selenium ou la librairie intégrée à Symfony2) et qui fait sa grande force, c’est qu’il se base sur une version headless de Webkit, de la même manière que Safari ou Chrome. Les tests ne sont pas effectués contre le code source renvoyé par le serveur mais bel et bien comme si un utilisateur devant un navigateur interagissait avec un navigateur. Il est donc possible de tester entre autres la visibilité d’éléments du DOM, le bon fonctionnement du javascript ou le chargement d’une image.

 

Fonctionnement

Pour faire simple, et dans le but de rester clair, rien ne vaut qu’un peu de code pour se mettre en jambe :

———————-
var casper = require(‘casper’).create();

casper.start(‘https://www.disko.fr/#!/contact’, function() {
this.test.assertTitle(‘Contactez-nous’, ‘title is the good one’);
this.test.assertExists(‘h1’, ‘h1 found’);
this.test.assertExists(‘form[action= »/contact »]’, ‘contact form is found’);
});

casper.run(function() {
this.test.done(3); // vérifie que 3 assertions ont étés executés
this.test.renderResults(true);
});
———————-
Une dizaine de lignes suffisent pour se rendre sur le site de Disko et tester les 3 choses suivantes :

  • Que le titre de la page est bien “Contactez-nous”
  • Qu’il trouve bien un élément de type h1
  • Et qu’il y a bien la présence du formulaire de contact, en s’assurant qu’il pointe effectivement vers la bonne URL.

On pourrait donc automatiser un lot de “validations” à un ensemble de sites par exemple (vérification la présence d’un BASIC Authentification sur chaque preprod clients, vérifier que les sites sont bien fonctionnels, et enfin que les homepages retournent bien un code 200, etc.).

Ensuite, dans le but de vous démontrer la puissance de CasperJS, le code suivant permet de prendre une capture d’écran d’une page :

——————
var casper = require(« casper »).create({
// On défini la résolution du navigateur
viewportSize: {
width: 1280,
height: 1024
},
verbose: true,
logLevel: « info »
});

// On récupère le nom du fichier désiré
var filename = casper.cli.get(0);

if (!filename || !/.(png|jpg|pdf)$/i.test(filename)) {
casper
.echo(« Usage: $ casperjs screenshot.coffee <filename.[jpg|png|pdf]> »)
.exit(1)
;
}

/* On crawl le site disko, la page Work parce que c’est la plus complexe niveau rendu simple smile CasperJS : les tests fonctionnels sous stéroïdes */
casper.start(« https://www.disko.fr/#!/work », function() {
/* On attend que le crawler trouve la div #work, pratique, car la balise est chargée en AJAX ! */
this.waitForSelector(« #work », (function() {
/* On capture tout le code HTML a l’intérieur des balises <html> */
this.captureSelector(filename, « html »);
this.echo(« Saved screenshot of  » + (this.getCurrentUrl()) +  » to  » + filename);
}), (function() {
/* Sinon on affiche une erreur. */
this.die(« Timeout reached. Fail whale? »);
this.exit();
}), 12000);
});

/* on lance */
casper.run();
——————

Ce qui donne :

 CasperJS : les tests fonctionnels sous stéroïdes
Comme vous pouvez le constater, le rendu est parfait ! Pourtant on utilise du JavaScript et du CSS3 pour mettre en forme la page “Work” du site Disko ( https://www.disko.fr/#!/work ) qui est donc complexe.

 

Pour aller plus loin

Mais pourquoi s’arrêter à un seul utilisateur ? Bien que CasperJS ne permette pas nativement de lancer plusieurs instances en parallèle (seulement en séquentiel), rien n’empêche d’écrire un programme pour lancer plusieurs CasperJS, et ainsi simuler la présence de plusieurs utilisateurs simultanés sur un site. Voici ce que nous avons fait pour tester en continu un des projets DISKO au frontend particulièrement complexe : chaque ensemble d’action était décidé de manière aléatoire (cliquer sur ce lien ou ce bouton ? remplir ce form ou pas ?). Ainsi un utilisateur CasperJS ne suivait plus un scénario prédéfini mais une route aléatoire dans un ensemble de scénarios possibles. Avec le script suivant qui permet de lancer facilement plusieurs instances de CasperJS, nous avons pû simuler la présence de 10, 20 ou 50 utilisateurs qui interagissent avec notre site de façon réaliste, tout en nous remontant des messages et des screenshots au moindre problème.

// NodeJS CasperJS Launcher by DISKO
// Utilisation :
// node launcher.js 15
// lance 15 instances de CasperJS

var spawn = require(‘child_process’).spawn;
var usercount = parseInt(process.argv[2] || 10);

console.log(« Spawing  » + usercount.toString() + ‘ bots’);

for( var i = 0; i < usercount; i++ ) {
(function(e) {
setTimeout(function() {
console.log( » -> spawing user  » + e.toString());

// lancement de l’instance CasperJS “testsuit.js”
var ls = spawn(‘casperjs’, [
‘testsuit.js’,
‘–username=Bot’ + e.toString()
]);

// la sortie du CasperJS est renvoyée vers la console
ls.stdout.on(‘data’, function (data) {
process.stdout.write(data);
});

ls.stderr.on(‘data’, function (data) {
process.stdout.write(data);
});

ls.on(‘exit’, function (code) {
console.log(‘User ‘ + e.toString() + ‘ exited with code ‘ + code);
});
}, Math.random()*(e*1000+1000)); // on lance les instances avec un léger décalage pour ne pas DDOS le serveur simple smile CasperJS : les tests fonctionnels sous stéroïdes
})(i);
}

Conclusion

Vous avez peut-être déjà utilisé Selenium, qui était déjà un bon début dans la création de tests utilisateur. CasperJS va bien plus loin que les tests fonctionnels classiques : il permet d’automatiser des tâches de manière réaliste qui ne pourraient être effectuées – à moins de passer des heures à tester chaque page les unes après les autres.

Comme beaucoup de solutions de tests fonctionnels, on peut récupérer le résultat des tests effectués avec CasperJS au format xUnit XML. Le résultat est donc exploitable par d’autres logiciels tel que le célèbre Jenkins, et au final s’intègre parfaitement à l’automatisation des builds applicatifs. Mais contrairement à beaucoup d’outils concurrents, CasperJS est basé sur un vrai navigateur, ce qui donne accès à toutes les fonctionnalités de celui-ci.

Pour terminer, cet outil peut effectivement devenir indispensable pour des sites de très grosses envergures et/ou sensibles. Le seul problème restera le temps destiné à l’écriture des tests fonctionnels du projet, autrement dit, les seules limites seront votre imagination et la bienveillance de votre chef de projet… 😉

 

 

Laisser un commentaire