Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

express middleware testing mocha chai

Is there a way to test those kind of middleware in express:

module.exports = function logMatchingUrls(pattern) {
    return function (req, res, next) {
        if (pattern.test(req.url)) {
            console.log('request url', req.url);
            req.didSomething = true;
        }
        next();
    }
}

The only middleware testing i found was:

module.exports = function(request, response, next) {
    /*
     * Do something to REQUEST or RESPONSE
    **/

    if (!request.didSomething) {
        console.log("dsdsd");
        request.didSomething = true;
        next();
    } else {
        // Something went wrong, throw and error
        var error = new Error();
        error.message = 'Error doing what this does'
        next(error);        
    }
};


describe('Middleware test', function(){

    context('Valid arguments are passed', function() {
        beforeEach(function(done) {
            /* 
             * before each test, reset the REQUEST and RESPONSE variables 
             * to be send into the middle ware
            **/
            requests = httpMocks.createRequest({
                method: 'GET',
                url: '/css/main.css',
                query: {
                    myid: '312'
                }
            });
            responses = httpMocks.createResponse();

            done(); // call done so that the next test can run
        });

        it('does something', function(done) {
            /*
             * Middleware expects to be passed 3 arguments: request, response, and next.
             * We are going to be manually passing REQUEST and RESPONSE into the middleware
             * and create an function callback for next in which we run our tests
            **/
            middleware(responses, responses, function next(error) {
                /*
                 * Usually, we do not pass anything into next except for errors, so because
                 * in this test we are passing valid data in REQUEST we should not get an 
                 * error to be passed in.
                **/
                if (error) { throw new Error('Expected not to receive an error'); }

                // Other Tests Against request and response
                if (!responses.didSomething) { throw new Error('Expected something to be done'); }

                done(); // call done so we can run the next test
            }); // close middleware
        }); // close it
    }); // close context
}); // close describe

This work well with the simple middleware (it like testing basic function with callback) provided above but with more complex middleware i cannot get it work. Is it possible to test this kind of middleware?

like image 761
Aaleks Avatar asked Dec 29 '15 18:12

Aaleks


2 Answers

Here's a simple setup that you could use, using chai and sinon:

var expect = require('chai').expect;
var sinon  = require('sinon');

var middleware = function logMatchingUrls(pattern) {
    return function (req, res, next) {
        if (pattern.test(req.url)) {
            console.log('request url', req.url);
            req.didSomething = true;
        }
        next();
    }
}

describe('my middleware', function() {

  describe('request handler creation', function() {
    var mw;

    beforeEach(function() {
      mw = middleware(/./);
    });

    it('should return a function()', function() {
      expect(mw).to.be.a.Function;
    });

    it('should accept three arguments', function() {
      expect(mw.length).to.equal(3);
    });
  });

  describe('request handler calling', function() {
    it('should call next() once', function() {
      var mw      = middleware(/./);
      var nextSpy = sinon.spy();

      mw({}, {}, nextSpy);
      expect(nextSpy.calledOnce).to.be.true;
    });
  });

  describe('pattern testing', function() {
    ...
  });

});

From there, you can add more elaborate tests for the pattern matching, etc. Since you're only using req.url, you don't have to mock an entire Request object (as created by Express) and you can just use a simple object with a url property.

like image 132
robertklep Avatar answered Nov 08 '22 13:11

robertklep


I used node-mocks-http to unit test my middleware. Here's my code:

function responseMiddleware(req, res, next) {    
    res.sendResponse = (...args) => { 
        //<==== Code removed from here
    };
    next();
}

And in my spec file I did it like this:

var expect = require('chai').expect;
var sinon  = require('sinon');    
var responseMiddleware = require('./response');
var httpMocks = require('node-mocks-http');


    describe('request handler calling', function() {
      it('should call next() once', function() {        
        var nextSpy = sinon.spy();

        responseMiddleware({}, {}, nextSpy);
        expect(nextSpy.calledOnce).to.be.true;
      });
      it('should add sendResponse key', function() {
        var nextSpy = sinon.spy();
        var req = httpMocks.createRequest();
        var res = httpMocks.createResponse();

        responseMiddleware(req, res, nextSpy);
        expect(nextSpy.calledOnce).to.be.true;
        responseMiddleware(req, res, () => {
            expect(res).to.have.property('sendResponse');        
        })        
      });
    });

If you are using async calls then you can use await and then call done() after that.

like image 24
Black Mamba Avatar answered Nov 08 '22 15:11

Black Mamba