Findmypast Tech

Stubbing dependencies in commonJS

Richard Kotze Richard Kotze
Reading time: 2 min

Unit testing is a valuable tool and it can be challenging to stub a dependency used by a module under test when applying the commonJS pattern. This is primarily because it is only accessible to itself ( much like a private field). Enabling the ability to control the response and ensuring data reaches the code being tested are two of the many good reasons to mock and stub particular bits of functionality.

An elegant solution I’ve discovered for accessing this is to use a node package called proxyquire. Proxyquire proxies the node ‘require’ function, allowing it to override the dependencies with a stub. In a test file, instead of using ‘require’ or ‘import’ for the module, we use proxyquire to load it in. The second parameter is an object which uses the key as the name/file path of the dependency and the value is the stub.

In order to demonstrate proxyquire, the example below has a simple module that has been built to fetch and render a twitter feed. There are a couple dependencies that need to be stubbed, one for fetching the tweets and the other to render them. In the module to test there is some logic to check:have any tweets have been retrieved and an HTML element has been specified to output too. For some side points I will use sinonJS for stubbing the dependencies and shouldJS to assert.

Twitter feed module

import twitterApi from './twitterApi';
import feed from './feed';

var twitterFeed = function(elementId, username) {
	if (elementId) {
		let tweets = twitterApi.get(username, 10);

		if (tweets.found)
			feed.renderTo(elementId, tweets.feed);
		else
			feed.renderTo(elementId, username + ' has no tweets');
	}
};

Test Twitter feed

import should from 'should';
import sinon from 'sinon';
import proxyquire from 'proxyquire';

describe('Twitter Feed', function(done) {
	var twitterApi = {
			get: sinon.stub()
		},
		feed = {
			renderTo: sinon.spy()
		},
		twitterFeed = proxyquire('./twitterFeed', {
			'./twitterApi': twitterApi,
			'./feed': feed
		});


	it('to render tweets', function() {
		//arrange
		let expectedUsername = 'richardkotze',
			elementId = 'rich-tweets',
			expectedTweets = [{
				tweet: 'This is a tweet.'
			}];
		twitterApi.withArgs(expectedUsername).returns(expectedTweets);

		//act
		twitterFeed(elementId, expectedUsername);

		//assert
		twitterApi.get.calledWith(expectedUsername).should.be.true();
		feed.renderTo.calledWith(elementId, expectedTweets).should.be.true();
	});

	it('to render error message', function() {
		//arrange
		let expectedUsername = 'richardkotze',
			elementId = 'rich-tweets',
			expectedTweets = null,
			expectedError = expectedUsername + ' has no tweets';
		twitterApi.withArgs(expectedUsername).returns(expectedTweets);

		//act
		twitterFeed(elementId, expectedUsername);

		//assert
		twitterApi.get.calledWith(expectedUsername).should.be.true();
		feed.renderTo.calledWith(elementId, expectedError).should.be.true();
	});

	it('not to render anything', function() {
		//arrange
		let expectedUsername = 'richardkotze',
			elementId = null;

		//act
		twitterFeed(elementId, expectedUsername);

		//assert
		twitterApi.get.called.should.be.false();
		feed.renderTo.called.should.be.false();
	});

});

Being able to access and stub these private variables significantly helps to make testing easier. Proxyquire does an excellent job of achieving this. Another library worth noting is rewire and it too allows you to stub private dependencies.