Testing Node.js code that requires JSON files

A preferred way of creating a JavaScript object from a JSON file is to use the require function. Require will take care of the file’s encoding, and will cache the results so reading the same file a second time will not hit the file system. Testing such code can seem challenging, however.

Let’s imagine for example that we want to test the following module residing in lib/get-name.js, that loads a JSON file, and returns the “name” property of the object it contains:

module.exports = function(jsonFilePath) {
var data = require(jsonFilePath);
return data.name;
};

In order for the tested code to never hit the file system, we’ll need to mock require itself. One library that enables this is Proxyquire. The way it works is that you point it to the module where you want require to include your stubs instead of the real thing, and you give it a list of the dependencies you want to replace. The call returns the instance of the module. It’s like requiring the module to test, but with phony dependencies that you specify:

describe('get-name', function() {
it('reads the name in a JSON file', function() {
var stubs = {};
stubs[path.normalize('path/to/file.json')] = {
name: 'Expected name',
'@noCallThru': true
};
var phoniedGetName = proxyquire('../lib/get-name', stubs);
var name = phoniedGetName('path/to/file.json');
expect(name).to.equal('Expected name');
});

The stubs object collection in this code gets a new property that has the path to the JSON file as its name. This is why I had to use the indexer notation to get the property in: the name of the property is dynamically determined, and will be different depending on what OS you are running the code (on Windows, it will use backslashes).

The stub object for the contents of the JSON file itself carries that name property, of course, but it also has a special “@noCallThru” that instructs Proxyquire to not try to resolve against the real object those properties that would be missing on the stub. In this case, there *is* no real object, so it’s important to tell Proxyquire to not even try to find it.

And this is how you test modules that requires JSON files.

No Comments