Moonraker

Il existe pleins de frameworks de tests d'IHM en Javascript, et notamment pour faire du test fonctionnel ou BDD. Outre cucumber-js, on trouve aussi l'excellent Yadda qui a le bon goût d'avoir une localisation en français... Et plus encore, on trouve le formidable Moonraker qui propose une solution complète clef en main: Yadda plus mocha, WebDriverJs et Chai et, cerise sur le pompon: des page objects !

Mais avec ExtJs, quand on met un splashscreen pendant le chargement et la création de la page, on a un problème: comment cliquer sur un élément seulement quand le splashscreen a disparu ?

En effet, si on attend simplement que la page soit chargée et qu'on tente, par exemple, de cliquer sur un élément alors que le splashscreen n'a pas complètement disparu, on obtient une exception ressemblant à ça:

 UnknownError: unknown error: Element is not clickable at point (1531, 14). Other element would receive the click: <div class="x-mask splashscreen" id="ext-gen1020" style="opacity: 0.403855921654898;"></div>

On voit ici clairement qu'on était pas loin, vu la valeur d'opacity.

Donc, il faut que ce splashscreen ait une opacité à 0 exactement. A ce moment, style prend également la propriété visibility avec la valeur hidden.

Il suffit de récupérer, via xpath - ce qui est le plus simple avec ExtJS - la div ayant les classes x-mask-msg et splashscreen et le style visibility avec la valeur hidden:

//div[contains(concat(' ', @class, ' '), 'x-mask-msg splashscreen')][contains(concat(' ',@style,' '), 'visibility: hidden')]

Alternativement, on peut aussi chercher:

//div[contains(concat(' ', @class, ' '), 'x-mask-msg splashscreen')][contains(concat(' ',@style,' '), 'opacity: 0;')]

mais dans ce cas, ne pas oublier le ';' après le '0', sinon, ça fonctionnera dès que opacity vaudra 0.9 et on retombera sur l'erreur vue précédemment.

Du coup, comme Selenium utilisé par WebDriverJs va attendre de trouver l'élément indiqué, il ne rendra la main que quand le loading mask aura totalement disparu (il reste présent, mais n'est plus visible).

Dans le page object de Moonraker, on ajoute donc une méthode comme celle-ci:

chargee:      { get: function() { return this.element("//divcontains(concat(' ', @class, ' '), ...contains(concat(' ',@style,' '), 'v...", 'xpath'); } }

Et dans la bibliothèque d'étapes:

 var pageAccueil = require('../pages/accueil.js');                                                                                                                                                      
 
 ...
 
 exports.define = function (steps) {
 
 ...
   steps.given("la page d'accueil", function () {
     pageAccueil.visit();
     pageAccueil.chargee;
   });
 ...