0

How would one test that a piece of custom middleware is actually called from a standard HTTP event?

ie. The middleware is called from:

MyController.js

router.get('/some/endpoint', [myMiddleware()], (req, res, next) => {
    // Code to do whatever here
});

The middleware itself can be defined as:

MyMiddleware.js

module.exports = () => {
    // Middleware code in here
}

My quest is to check that the middleware is called once from my unit test, but I cannot find documentation around this.

MyTest.test.js

it('Should return whatever from GET call', () => {
    return request(app).get('/some/endpoint')
        .expect(200)
        .expect(res => {res.body.should.deep.equal(bodyValue)});
    // How would I place code in here to check that MyMiddleware is called? 
    // ie. sinon.assert.calledOnce(MyMiddleware)
});

I have thought about using Sinon's spy, but I can't think of how to hook into the middleware... My attempt was this:

const mwSpy = sinon.spy(require('path to middleware file'));

sinon.assert(calledOnce(mwSpy));
physicsboy
  • 5,656
  • 17
  • 70
  • 119

1 Answers1

0

The usual way of going about this is splitting this into two tests, an integration test and a unit test.

  1. Will the middleware I specified in the router.get call end up being called when someone hits this endpoint?
  2. Does my middleware do the right thing?

The first part is basically testing that the Express API is doing what the documentation says. That's not what unit tests are for (this was tagged unit-testing), but since you are already using HTTP requests to test the endpoint, I guess that's not what you are after anyway: you are basically creating verification tests for your system.

You could still test the Express routing without HTTP, though, as I detail in the answer to this question, concerning how to test the router programmatically (faster tests, no http), but less just stick to what you have.

So the basic question is: "My quest is to check that the middleware is called once from my unit test". You don't seem to concern yourself with whether the middleware is doing the right thing or not, just that it's called, which calls for the question on whether we should test the middleware or the layer using the middleware.

In both cases, you need to find a way of injecting a test spy. Either you write a small utility method that will inject that spy: function setMiddleware(module){ middleware = module; } or you use some tooling like proxyquire. See this tutorial on Sinon's homepage for background.

I would just do this (in the test code):

it('Should return whatever from GET call', () => {
  var middlewareFake = sinon.fake();
  // I am assuming it's the actual app object you are referencing below in the request(app) line
  var app = proxyquire('../app/index.js', { './my-middleware': middlewareFake });

  //
  return request(app).get('/some/endpoint')
    .expect(200)
    .expect(res => {
      res.body.should.deep.equal(bodyValue)

      expect(middlewareFake).was.called;
    });
});
oligofren
  • 20,744
  • 16
  • 93
  • 180