Dans le précédent article sur les tests javascript, nous avons vu comment tester jQuery avec JsTestDriver. Le souci c'est lorsqu'une fonction va chercher des fragments de html, ou du json, ou d'autres données par ajax, dans ce cas l'appel de la fonction va réellement déclencher une requête http. En soi ce n'est pas un problème, on peut faire un test d'intégration en écrasant l'url de production vers une url en localhost.

Seulement, il y a 3 écueils :

  • avec JsTestDriver, l'url de base a changé (c'est celle du serveur de test qui est dynamique et pointe vers par exemple http://localhost:9876/slave/id/1311194023939/page/CONSOLE/mode/quirks/timeout/30000/upload_size/50/rt/CLIENT), donc il est nécessaire de faire une requête avec une url absolue (http://localhost/test/monJsonDeTest.json)
  • pour exécuter les tests il faut alors un serveur http en local avec la ressource déployée et le contexte configuré
  • avec JsTestDriver, on obtient une exception javascript (alors que le code de production fonctionne) que je ne suis pas arrivé à expliquer ou à contourner :
    [Exception... \"Component returned failure code: 0x80004005
    (NS_ERROR_FAILURE)\"  nsresult: \"0x80004005 (NS_ERROR_FAILURE)\"
    location: \"JS frame :: jquery.min.js\"

Un excellent livre : "Test Driven Javascript Development" donne une petite librairie (le code associé au chapitre 12) et des exemples pour mocker des appels ajax avec une couche de transport développée par Christian Johansen, l'auteur. J'ai appliqué la méthode qu'il propose à jQuery. Dans notre exemple, nous allons chercher un modèle en JSON, et nous vérifions que le html produit est conforme à ce qu'on attend :

TestCase("TestJsonAjax", {
    setUp: function() {
        // création du mock
        this.xhr = Object.create(fakeXMLHttpRequest);
        this.xhr.send=function () { readyState = 4; };
        this.xhr.getAllResponseHeaders=stubFn({});
        this.xhr.responseText="{'reponse':'réponse mockée'}";
        // masquage des fonctions jQuery
        jQuery.ajaxSettings.isLocal=stubFn(true);
        jQuery.ajaxSettings.xhr=stubFn(this.xhr);
    },

   "test getHtml() renvoie html bien formé": function () {
        var actualHtml;

        getHtml(function(html) {
            actualHtml = html;
        });

        assertEquals("

réponse mockée

", actualHtml);
    }
});

fakeXMLHttpRequest et la fonction stubFn() (crée une fonction qui renvoie la valeur fournie) sont dans la librairie tddjs (le repository git est http://tddjs.com/code/12-abstracting-browser-differences-ajax.git).

la ligne jQuery.ajaxSettings.xhr=stubFn(this.xhr) écrase la fonction de création de requête XMLHttpRequest de jQuery par celle définie dans le setUp (fakeXMLHttpRequest fournie par tddjs).

Le code qui fait passer le test :

function getHtml(resultFunc) {
   jQuery.getJSON('url/vers/le/modele/JSON', function(json) {
       resultFunc('

'+ json['reponse'] + '

');
   });
}