I'm trying to get the grasp of the tool Nock in order to mock the request and response from my code doing the calls. I'm using npm request as a simple HTTP client to request the back-end REST API, Chai for the expectation library and Mocha to run my tests. Here is the code that I have for the tests:
var nock = require('nock');
var storyController = require('../modules/storyController');
var getIssueResponse = {
//JSON object that we expect from the API response.
}
it('It should get the issue JSON response', function(done) {
nock('https://username.atlassian.net')
.get('/rest/api/latest/issue/AL-6')
.reply(200, getIssueResponse);
storyController.getStoryStatus("AL-6", function(error, issueResponse) {
var jsonResponse = JSON.parse(issueResponse);
expect(jsonResponse).to.be.a('object');
done();
})
});
And here is the code to do the GET request:
function getStoryStatus(storyTicketNumber, callback) {
https.get('https://username.atlassian.net/rest/api/latest/issue/' + storyTicketNumber, function (res) {
res.on('data', function(data) {
callback(null, data.toString());
});
res.on('error', function(error) {
callback(error);
});
})
}
This single test is passing and I don't understand why. It seems like it is actually doing a real call and not using my fake nock request/response. If I comment the nock section or change:
.reply(200, getIssueResponse) to .reply(404)
It doesn't break the test and nothing change, I'm not doing anything with my nock variable. Can someone please explain me with a clear example how to mock the request and response in my NodeJS http-client using Nock?
TLDR: I think your code is doing more than what it tells you.
Important note: when putting an http request in "stream mode" the data
event could (and probably does) gets fired multiple times, each one for a "chunk" of data, over internet chunks could be variable between 1400 to 64000 bytes, so expect multiple callback invocations (that's a very special kind of bad)
As a simple suggestion, you can try using request or just concatenate the received data, then invoke the callback on the end
event.
I have tried a very small snippet using the latter technique
var assert = require('assert');
var https = require('https');
var nock = require('nock');
function externalService(callback) {
// directly from node documentation:
// https://nodejs.org/api/https.html#https_https_get_options_callback
https.get('https://encrypted.google.com/', (res) => {
var data = '';
res.on('data', (d) => {
data += d;
});
res.on('end', () => callback(null, JSON.parse(data), res));
// on request departure error (network is down?)
// just invoke callback with first argument the error
}).on('error', callback);
}
describe('Learning nock', () => {
it('should intercept an https call', (done) => {
var bogusMessage = 'this is not google, RLY!';
var intercept = nock('https://encrypted.google.com').get('/')
.reply(200, { message: bogusMessage });
externalService((err, googleMessage, entireRes) => {
if (err) return done(err);
assert.ok(intercept.isDone());
assert.ok(googleMessage);
assert.strictEqual(googleMessage.message, bogusMessage);
assert.strictEqual(entireRes.statusCode, 200);
done();
});
})
})
And it works very fine, even with using on('data')
Edit:
Reference on how to handle correctly a stream
I have expanded the example as a full-fledged mocha example