Metaduck

HTTP Mocking Made Easy With Nock

I love testing and I love small easily testable modules in Node.

Recently I had to build a library module that interacts with some web services via HTTP.

To test this module as it was would mean that I would have to have a sandboxed account on the other end. I also would have to have setup and teardown routines that would reset the sandbox to a known state, etc, etc.

What I really wanted for the unit tests was to test the module in isolation. In this case, it would mean capturing the HTTP requests and replying a pre-made response.

Enter nock.

Nock is an HTTP mocking and expectations library for Node.js

With Nock you can easily mock a GET request:

var nock = require('nock');

var scope = nock('http://myapp.iriscouch.com')
                .get('/users/1')
                .reply(200, {_id: "123ABC", _rev: "946B7D1C", username: 'pgte', email: 'pedro.teixeira@gmail.com'});

or a POST request with a specified body (string or json-encoded object):

var scope = nock('http://myapp.iriscouch.com')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .reply(201, {ok: true, id: "123ABC", rev: "946B7D1C"});

or a PUT or a DELETE in the same fashion.

You can also specify the response as a string:

var scope = nock('http://api.app.com')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .reply(201, "OK");

or as a JSON-encoded object:

var scope = nock('http://api.app.com')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .reply(201, {ok: true, _id: "abcdef", _rev: "1234"});

or from the contents of a file:

var scope = nock('http://api.app.com')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .replyWithFile(201, __dirname + '/assets/reply.json');

Filtering paths and bodies

If you have time-dependent or random data you want to filter out from the request path or body, you can use a regular expression, much like String.prototype.replace:

var scope = nock('http://api.app.com')
                .filterPath(/timestamp=[^&]*/g, '')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .replyWithFile(201, __dirname + '/assets/reply.json');

.filterPath() also accepts a function as sole argument. That function should return the filtered path.

As said, Nock also supports request body filtering much the same way it does with path filtering. Just use .filterRequestBody like this:

var scope = nock('http://api.app.com')
                .filterRequestBody(/timestamp=[^&]*/g, '')
                .post('/users', {username: 'pgte', email: 'pedro.teixeira@gmail.com'})
                .replyWithFile(201, __dirname + '/assets/reply.json');

or even with a function as the only argument.

Expectations

When a scope is defined Nock intercepts every HTTP request being made in that process to that host. If a match is not found - Nock matches verb, path and body - an exception is raised.

When a mocking match is found, Nock removes that match.

At the end of the test, if you wish to test that all the expected calls were made, you can use

scope.done();

and a detailed exception will be thrown if some expectations were not met.

Feedback

I hope this module makes testing easier for you.

Feedback with suggestions is welcome!