2

I'm using requirejs with inline requires, for instance:

define(['someDep'], function(someDep) {
  return {
    someFn: function() {
      require(['anotherDep'], function(anotherDep) {
        anotherDep.anotherFn();
      });
    }
  } 
});

In my particular case, I cannot include anotherDep in the define.

When testing with mocha, I have a test case like this:

define(['squire'], function(Squire) {
  var squire = new Squire();
  describe('testcase', function() {
    it('should mock anotherDep', function(done) {
      var spy = sinon.spy();
      squire.mock('anotherDep', {
        anotherFn: spy
      });
      squire.require(['someDep'], function(someDep) {
        someDep.someFn();
        expect(spy).to.have.been.calledOnce;
        done();
      });
    });
  });
});

fails because anotherDep calls require directly and not squire.require. The work-around is to replace require in the global scope,

var originalRequire;

before(function() {
  originalRequire = require;
  require = _.bind(squire.require, squire);
});

after(function() {
  require = originalRequire;
});

This works (note that squire.require must be bound to the squire object in some way, I'm using underscore to do this) except that the spy will still not be called because of timing. The test also has to change to

it('should mock anotherDep', function(done) {
  squire.mock('anotherDep', {
    anotherFn: function() {
      done();
    }
  });
  squire.require(['someDep'], function(someDep) {
    someDep.someFn();
  });
});

Is there a better way? If not, hope this provides a solution for others running into the same problem.

Paul Spencer
  • 1,355
  • 1
  • 8
  • 16

1 Answers1

4

I've not tried to do specifically what you are trying to do but it seems to me that if squire is doing a thorough job, then requiring the require module should give you what you want without having to mess with the global require. The require module is a special (and reserved) module that makes available a local require function. It is necessary for instance when you use the Common JS syntactic sugar. However, you can use it whenever you desire to get a local require. Again, if squire does a thorough job, then the require it gives you should be one that squire controls rather than some sort of pristine require.

So:

define(['require', 'someDep'], function (require, someDep) {
  return {
    someFn: function() {
      require(['anotherDep'], function(anotherDep) {
        anotherDep.anotherFn();
      });
    }
  } 
});
Louis
  • 146,715
  • 28
  • 274
  • 320
  • 1
    This works perfectly. At first I was hesitant to modify my modules to include depending on 'require' as a module as it seems a bit hacky and unnecessary, but after some thought I realized this is really about writing testable code and if doing this allows code to be unit-testable then it is a worthwhile pattern to put in place. – Paul Spencer Oct 14 '14 at 17:29
  • 1
    Glad to help! Let me note that there is no hack here. Putting `require` in the dependencies is part of the public API of RequireJS, and is in fact necessary for some use cases (besides the one I've mentioned in my answer). – Louis Oct 14 '14 at 17:32