Correct way to unit test Express Middleware

Jak Hammond picture Jak Hammond · Jan 13, 2017 · Viewed 15.9k times · Source

I have a piece of Express middleware that is set to check for a valid Content-Type header in all of my POST requests that hit my server, the code for this middleware is below:

import * as STRINGS from "../Common/strings";

function ContentTypeValidator(req, res, next) {
    let contentHeader = req.get("content-type");
    if(!contentHeader) {
        res.status(400).send(STRINGS.ERROR_CONTENT_TYPE_MISSING);
    } else {
        if(contentHeader.toLowerCase() !== "application/json") {
            res.status(415).send(STRINGS.ERROR_CONTENT_TYPE_UNSUPPORTED);
        } else {
            next();
        }
    }
}

export default ContentTypeValidator;

I am using mocha, chai and node-mocks-http for my TDD and my question surrounds the tests when next() will not be called as res.send() will handle the ending of this request for me.

it("Should return 200 for valid Content-Type header", (done) => {
    req = nodeMocks.createRequest({
        headers: {
            "Content-Type": "application/json"
        }
    });
    ContentTypeValidator(req, res, (err) => {
        res.statusCode.should.equal(200);
        expect(err).to.be.undefined;
        done();
    });
});

it("Should return 400 if Content-Type header is missing", (done) => {
    ContentTypeValidator(req, res, () => {});
    res.statusCode.should.equal(400);
    res._getData().should.equal("Content-Type header missing");
    done();
});

In the first test above, I am expecting this to pass, so I pass in a function to act as the next() function and this test passes. In the second test, I am expecting this to fail so if I pass in a function then mocah complains that the test has exceeded 2000ms as the callback function is never called, which is to be expected since res.send() is handling it in this instance.

Is the way I've written the second test correct when it comes to unit testing Express middleware like this or is there a better/more advisable way to do this?

EDIT: So just to clarify, I am focused on wanting to test the middlewear when the next callback will NOT be called, the question I'm apparently duplicating is looking at using sinon to check if next is called. I am looking to see how to unit test when the callback function will NOT be called.

Answer

Med Lazhari picture Med Lazhari · Jan 13, 2017

Check out this answer

https://stackoverflow.com/a/34517121/4996928

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() {
    ...
  });

});