Correct way to unit test Express Middleware

20,594

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

});
Share:
20,594
Jak Hammond
Author by

Jak Hammond

Updated on January 14, 2020

Comments

  • Jak Hammond
    Jak Hammond over 4 years

    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.

  • Jak Hammond
    Jak Hammond over 7 years
    I had actually seen that one, but that answer seems more focused on using sinon to check that next() is actually called. In my instance I can't call next since the response will be rejected before it's called.
  • Ivor Scott
    Ivor Scott about 7 years