Mocking/Stubbing CommonJS Dependencies with Browserify and Karma

Mocking, stubbing and strategies for dependency injection are often overly complex parts of the JavaScript test code we have to write. But they help us isolate the unit that we want to test. Since CommonJS modules often act as a natural seam for a unit, it makes perfect sense that test frameworks like Jest automatically mock CommonJS dependencies.

While Jest looks absolutely awesome and can do other great things like like parallel testing, runAllTimers and provide promise helpers, Karma and Jasmine are still my weapons of choice and firmly fastened to the old utility belt… Especially now that I’ve found the karma nyan reporter ;)

But I’m not here to talk about karma reporters, as colourful as they can be…

So how do we stub CommonJS Dependencies?

proxyquire is a super easy to use proxy for requiring modules, that takes an object literal of stubbed dependencies as it’s second argument.

In the following example we’re going to test a member service, which has a create method and for the purposes of testing we want to isolate it from the ajax service call.

member.js

1

2

3

4

5

6

7

8

9

10

11

12

var ajax = require('./ajax');

var member = {

create: function(firstName, surname) {

return ajax.post({

firstName: firstName,

surname: surname

});

}

};

module.exports = member;

In our test spec, we’ll require member.js via proxy and stub out the ajax service to return a successfully resolved promise containing a member number.

member.spec.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

var proxyquire = require('proxyquire');

// use a helper to return a promise like the ajax post

// method would

var promiseStub = require('promiseStub');

var ajaxStub = {

post: function() {

return promiseStub.success('MEM1234');

}

};

var member = proxyquire('../member', {

'./ajax' : ajaxStub

});

describe('using proxyquire', function() {

var memberNumber;

beforeEach(function (done) {

member.create('Peter', 'Rabbit').then(function (data) {

memberNumber = data;

done();

});

});

it('subsitutes the required module for the stub', function() {

expect(memberNumber).toBe('MEM1234');

});

});

It’s worth noting that the path to the stubbed module (ie. './ajax') is relative to the location of member.js, not member.spec.js.

Browserify + proxyquire = proxyquireify

@tlorenz, the smart guy behind proxyquire also put together proxyquireify for use with browserify, and the usage is near identical to the above CommonJS examples except for a couple of reference changes.

Heres a walkthrough of steps to get it working with Browserify and Karma :

Install the proxyquireify node module

npm install proxyquireify --save-dev

Edit your karma.conf.js file

put var proxyquire = require('proxyquireify'); at the top of the file

in the browserify section, add a configure function to add the proxyquire plugin to browserify and set the root folder for the tests.