Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retest same URL using Mocha and Nock?

Am using Mocha, Chai, Sinon, Proxyquire and Nock.

For this particular test scenario (for which this question is being asked), wish to test the exact same URL several times, each in a separate test that expects a different response.

For example, a response with no merchant feeds, 1 merchant feed, and yet again with 2 merchant feeds.

The existing code all works, furthermore if I run tests individually they pass.

However, if i run them together using Mocha in a single suite they fail. Believe the issue is that Nock hijacks the global http object for a given URL and each test (running asynchronously at the same time) is competing for the same global response reference.

In the scenario above, a response prepared with a canned reply of 1 merchant is getting say overwritten by the setup to respond with 2 merchants etc.

Is there a mechanism to avoid this happening, for instance guarantees around serial execution of async Mocha testcases (which I believed was the default behaviour).

like image 287
arcseldon Avatar asked Jul 03 '14 12:07

arcseldon


People also ask

What is Nock testing?

Nock is an HTTP server mocking and expectations library. You can use this library to test frontend modules that are performing HTTP requests. You can test in isolation because Nock lets you dictate what our API responses will be.

How do I exit Mocha test?

0.0 or newer, you can use --exit for a quick (this is however not necessarily recommended) fix. Before version v4. 0.0, Mocha would force its own process to exit once it was finished executing all tests by default.

What is Nock JS?

Nock is an HTTP server mocking and expectations library for Node. js. Nock works by overriding the http. request and http. ClientRequest functions, intercepting all requests made to a specified URL and returning specified responses that mimic the data that the real URL would return.


2 Answers

Ok, so this works (sample code):

 beforeEach(function (done) {
            nock(apiUrl)
                .get('/dfm/api/v1/feeds?all=false')
                .reply(200, [
                    {'merchantId': 2, 'id': 2, 'disabled': false}
                ], { server: 'Apache-Coyote/1.1',
                    'set-cookie': [ 'JSESSIONID=513B77F04A3A3FCA7B0AE1E99B57F237; Path=/dfm/; HttpOnly' ],
                    'content-type': 'application/json;charset=UTF-8',
                    'transfer-encoding': 'chunked',
                    date: 'Thu, 03 Jul 2014 08:46:53 GMT' });

            batchProcess = proxyquire('./batchProcess', {
                './errorHandler': errorHandler.stub,
                './batchTask': batchTask.stub
            });

            winston.info('single valid feed beforeEach completed');
            done();
    });

There were lots of complicating factors. Two things to be aware of:

1). I had async testcases but was using beforeEach() without the done param. This was then causing the URL collisions. By explcitly declaring each beforeEach(done) and invoking done() Mocha will run in serial order and there is no longer an issue.

2). Be sure that if you have more than one test in same testsuite file, that any Nock fixtures you set in a previous test actually get executed IF you have declared the same URL in a subsequent test with alternate response. If the prior nock fixture doesn't get invoked then nock STILL retains the response from the wrong test (the previous one). This was my primary problem. You could argue that tests should not have any fixtures declared if they don't get run - but you could also argue this is still a bug in the way Nock works. The test fixtures were each isolated in their own describe / beforeEach(done) functions..

Update 2 days later... OK point 2). just bit me again, and I was pleased I wrote the note above to remind myself about this hard to debug issue. If you are using Mocha and Nock together be aware of this issue!!

Did eventually implement a nock helper function too, to assist with this (coffeescript here):

global.resetNock = ->
  global.nock.cleanAll()
  global.nock.disableNetConnect()

Then at the start of beforeEach just apply resetNock()

like image 181
arcseldon Avatar answered Oct 06 '22 10:10

arcseldon


In response to your point 2), you can use nock.cleanAll() to cleanup all prepared nocks:

https://github.com/pgte/nock#cleanall

You can put this in an afterEach block to make sure you don't have leftover nocks between tests.

afterEach ->
  nock.cleanAll()
like image 27
James Duffy Avatar answered Oct 06 '22 11:10

James Duffy