Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to unit test Express Middleware [duplicate]

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.

like image 998
Jak Hammond Avatar asked Jan 13 '17 13:01

Jak Hammond


People also ask

How do you test a route?

Testing routes can be done both via application tests or container tests. Application tests will likely provide better coverage for routes because routes are typically used to perform transitions and load data, both of which are tested more easily in full context rather than isolation.


1 Answers

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

});
like image 153
Med Lazhari Avatar answered Sep 21 '22 09:09

Med Lazhari