Ajax via SuperAgent, testé avec mocha(TDD inside)

SuperAgent permet de faire du CRUD sur une URL relative ou absolue, notamment - et c'est ce qui nous intéresse - dans node. C'est le cas typique de la consommation d'une RESTful API.

L'installation se fait avec npm :

npm install superagent  

Faire du CRUD se fait simplement en utilisant le verbe approprié :

request.get('/search');  
//ou bien avec une url absolue
request.get('http://bla.com/search');  

Les autres verbes étant :

request.post('/user');

request.put('/user');  

En revanche, ce sera del() au lieu de delete(), delete étant un mot réservé en JavaScript :

request.del();  

Pour envoyer votre requète, il faut chainer avec la fonction end(), qui prendra un callback :

request.get('/search').end(function(res){});  

Il est également possible de passer le verbe en paramètre :

request('GET', '/search').end(function(res){});  

Comme la méthode HTTP par défaut est GET, on pourrait omettre le verbe dans le cas d'une requête GET :

request('/search', function(res){});  

Ajouter des headers se fait via le setter set():

request  
  .get('/search')
  .set('Accept', 'application/json')
  .end(function(res){});

Pour passer plusieurs champs, set peut prend un object en paramètre :

request  
  .get('/search')
  .set({ 'API-Key': 'foobar', Accept: 'application/json' })
  .end(function(res){});

Tout cela est détaillé dans la documentation de SuperAgent.

Ce qui n'apparait en revanche pas mais est très utile quand on fait du Test Driven Development (TDD), c'est qu'on peut utiliser SuperAgent pour faire des requêtes et permettre aux modules de test, mocha et expect dans notre exemple, de faire des tests asynchrones. Autrement dit, on peut demander à mocha d'attendre que notre requête vers un serveur web (accès au réseau == lenteur) soit accomplie, avant de décider si le test a réussi ou échoué. Le cas typique sera un développement en TDD d'une RESTful API.

Commençons par installer mocha globalement afin d'avoir accès à mocha en ligne de commande plus tard :

npm install -g mocha --save-dev  

rappel : --save-dev déclare mocha comme un module à installer uniquement en développement, pas en production, -g (installation globale) permettra d'utiliser l'outil de ligne de commande fourni par mocha.

Si n'est déjà fait, installons également SuperAgent et expect :

npm install superagent  
npm install expect --save-dev  

Créons test.js, qui contiendra notre test. Remarquez le callback 'done' - deuxième paramètre de it() passé au callback -, qui va faire patienter mocha:

var superagent = require("superagent");  
var expect = require("expect");

describe("it uses superagent", function(){  
    it('GETs google web page', function(done){
        superagent
            .get("https://www.google.fr")
            .end(function(res){
                console.log(res);
                done();
            });
    });
});

Attention au "ReferenceError: describe is not defined"

Le reflexe d'exécuté mon application avec la commande "node" m'a piègé. J'ai eu droit à une belle ReferenceError sur la fonction describe(). Ceci car l'exécution des tests (les it() qui se trouvent dans describe()), nécessite d'exécuter la commande "mocha" :

mocha test.js  

et non pas :

node test.js

Donc si vous êtes victime d'un

"ReferenceError: describe is not defined", vous saurez quoi corriger.

Penser à faire patienter mocha

On peut facilement oublier de d'appeler done() peu avant la fin de end(). Cela aurait pour effet de faire échouer le test avec le message d'erreur suivant :

Error: timeout of 2000 ms exceeded

Si en revanche vous avez bien appelé done() à la fin de end(), vous aurez un beau :

1 passing (2s)  

Afficher le contenu de l'object "res" permet de voir que cet unique objet retourné contient tout ce qu'il faut, au lieu des 3 paramètres qu'aurait retournés un traditionnel $.ajax() propre à jQuery. "res" contient non seulement le contenu de la page html demandée, mais également des headers et d'autres propriétés que je vous laisse découvrir dans votre console.

Un dernier détail : describe() correspondrait plutôt à une fonction utilisée dans le BDD. Rien ne vous empêche d'utiliser:

  • suite() plutôt que describe()
  • test() plutôt que it()
  • setup() plutôt que before()
  • teardown() plutôt qu'after()
  • suiteSetup() plutôt que beforeEach()
  • suiteTeardown plutôt que afterEach()

... etc ... .

Voilà, avec SuperAgent pour faire vos requêtes, accompagné de mocha et expect, vous pourrez facilement faire du TDD ou du BDD avec node, notamment lors de la création de vos RESTful APIs. Il suffira ainsi de créer des tests qui utilisent SuperAgent pour faire des requêtes sur des urls correspondant à vos quatre verbes (GET POST PUT DELETE), avec pour POST et PUT le recours, en prime, à la fonction send({}) qui passera les données à créer ou à mettre à jour :

superagent.post('http://localhost/API/collection').send({foo: bar, bla: bli});  

Lesdits tests échoueront dans un premier temps puisque votre API n'existe pas encore. Puis à mesure que les fonctionnalités seront implémentées, les tests passeront. Ne manquera plus qu'une refactorisation. Ainsi, vous satisferez au mantra "Red Green Refactor" cher au TDD.