2016-11-29 2 views
2

Dans le cadre de la migration d'une application plus ancienne d'ExpressJs vers Koa JS (v1). J'ai écrit un morceau de middleware pour gérer les erreurs qui se produisent. Il ressemble à ceci:Comment tester un middleware Koa personnalisé pour la gestion des erreurs?

module.errors = function * (next) { 
    try { 
    yield next; 
    } catch (err) { 
    switch(err && err.message) { 
     case: 'Bad Request': 
     this.status = 400; 
     this.body = {message: 'Bad Request'}; 
     brea; 
     default: 
     this.status = 500; 
     this.body = {message: 'An error has occurred'}; 
    } 

    this.app.emit('error', err, this); 
    } 
} 

Il sera inclus dans ma demande comme ceci:

const app = require('koa')(); 
const router = require('koa-router'); 
const { errors } = require('./middleware/errors'); 

app.use(errors) 
    .use(router.routes()); 

app.get('/some-request', function *(next){ 
    // request that could error 
}); 

app.listen(); 

Tout cela fonctionne très bien, mais je voudrais tester le middleware avec mes tests unitaires, et peut-être parce que je suis encore relativement nouveau dans les fonctions Koa et Generator, j'ai du mal à comprendre comment faire cela.

Je sais que si j'importe le middleware de gestion d'erreur, je dois lui passer une fonction qui va générer une erreur, mais comment j'exécute la fonction passée? Est-ce que ce doit être une fermeture de quelque description? Comment puis-je affirmer/attendre sur les valeurs définies pour le code d'état et similaires?

const { expect } = require('chai'); 
const { errors } = require('../middleware/errors'); 

describe('errors middleware',() => { 

    it('returns a 500 on a generic error',() => { 
     let thrower = function(){ throw new Error() } 
     let errorHandler = errors(thrower()); 

     // mass of confusion 

     expect(errorHandler.next()).to.throw(Error); 
    }); 
}); 

Répondre

0

intergiciels Koa sont des générateurs (plusieurs fois retour/rendement) et ne se comportent pas comme des fonctions, il me fait bizarre d'écrire des tests unitaires pour eux. Personnellement, je me contente de cas de test de bout en bout.

Cependant, ce qui suit pourrait fonctionner dans votre cas.

const { expect } = require('chai'); 
const { errors } = require('../middleware/errors'); 

describe('errors middleware',() => { 

    it('returns a 500 on a generic error',() => { 

     let ctx = { body: {}, status: 404 }; 

     let errorMidIterator = errors().call(ctx, 'NEXT_MID'); 

     // test that it correctly yields to next middleware 
     expect(errorMidIterator.next().value).should.equal('NEXT_MID'); 

     // simualte an error and test if it correctly sets the body 
     expect(errorMidIterator.throw(new Error()).done).to.equal(true); 
     expect(ctx.status).should.equal(500); 
    }); 
}); 

Comme une note de côté, je pense qu'il est préférable d'exporter des usines de middleware de vos fichiers plutôt que des fonctions de générateur de middleware ordinaire. Le premier vous donne plus de contrôle (c'est-à-dire que vous pouvez éventuellement injecter certaines des dépendances, dans ce cas la fonction thrower(), via les arguments de la fonction Factory). Mes fichiers middleware ressemblent à ceux-ci.

module.exports = function MyMiddleware(options) { 
    return function *MyMiddleware(next) { 
     // options.config.foo 
     // options.httpclient.get(..) 
    }; 
} 

koa Enfin enveloppe les fonctions du générateur avec co, qui change la sémantique si les tests unitaires ne sont pas utiles que (subjective)

0

vous pouvez utiliser cette bibliothèque qui https://www.npmjs.com/package/co utilisée par koa.js 1.x à Enveloppez vos fonctions de générateur et simulez l'objet de contexte.

const co = require('co'); 
const Emitter = require('events'); 
const { expect } = require('chai'); 
const { errors } = require('../middleware/errors'); 

const wrapped = co.wrap(errors); 
const mockApp = new Emitter(); 

describe('errors middleware',() => { 

    it('returns a 500 on a generic error', (done) => { 
    const ERROR_MSG = 'middleware error'; 
    const ctx = {app: mockApp}; 
    const next = function*() { 
     throw new Error(ERROR_MSG); 
    } 
    wrapped.call(ctx, next) 
     .then(() => { 
     try { 
      expect(ctx.status).to.equal(500); 
      expect(ctx.body.message).to.equal(ERROR_MSG); 
      done(); 
     } catch (err) { 
      done(err); 
     } 
     }) 
     .catch(err => done(err)) 

    }); 
});