Search code examples
javascriptnode.jsmocha.jssinonchai

How to mock, and test, closures with mocha, chai and sinon


I have a simple Node.js middleware that I would like to test is it being processed correctly.

Simple middleware

module.exports = (argumentOne, argumentTwo) => (req, res, next) => {
  if (!argumentOne || !argumentTwo) {
    throw new Error('I am not working');
  };

  req.requestBoundArgumentOne = argumentOne;
  req.requestBoundArgumentTwo = argumentTwo;

  next();
};

I would like to test this middleware using mocha, chai and sinon but I simply can't figure out how to test this inner function.

I have tried the following approach

describe('[MIDDLEWARE] TEST POSITIVE', () => {
  it('should work', () => {
    expect(middleware('VALID', 'TESTING MIDDLEWARE')).to.not.throw();
  });
});

describe('[MIDDLEWARE] TEST NEGATIVE', () => {
  it('shouldn\'t work', () => {
    expect(middleware('INVALID')).to.throw();
  });
});

In my TEST POSITIVE I know this code is valid but it still throws following error

AssertionError: expected [Function] to not throw an error but 'TypeError: Cannot set property \'requestBoundArgumentOne\' of undefined' was thrown

Solution

  • From looking at the code you posted, your function returns another function that needs to be called. So the test should be written in this way:

    describe('middleware', () => {
      let req, res, next;
    
      beforeEach(() => {
        // mock and stub req, res
        next = sinon.stub();
      });
    
      it('should throw an error when argumentOne is undefined', () => {
        const fn = middleware(undefined, 'something');
        expect(fn(req, res, next)).to.throw();
      });
    
      it('should throw an error when argumentTwo is undefined', () => {
        const fn = middleware('something', undefined);
        expect(fn(req, res, next)).to.throw();
      });
    
      it('should call next', () => {
        const fn = middleware('something', 'something');
        fn(req, res, next);
        expect(next.calledOnce).to.be.true;
      });
    });
    

    To test the success case properly you'll need to stub out the values for req and res.