My question is about unit testing with promises and event emitters in Node.js. I am using the jasmine framework if that matters.
The code below uses the https module of Node.js to send a request to an API. The API will return JSON. The JSON from the API is the "rawData" variable in the code below.
I want to unit test that the function returns JSON (and not a JavaScript object).
I have unsuccessfully tried several approaches to unit testing that aspect of this function:
1) I tried spying on the Promise constructor so that it would return a fake function which would simply return a JSON string.
2) I have tried spying on the .on('eventType', callback) function of EventEmitters in Node.js to fake a function that returns JSON.
My question is: are either of the two approaches above possible and/or recommend for accomplishing my goal? Is there a different approach to isolating the http request and emitting of events from my unit test objective? Do I need to rewrite this function to facilitate easier unit testing?
const https = require('https');
function getJSON() {
return new Promise((resolve, reject) => {
const request = https.get(someConfig);
request.on('response', resolve);
})
.then(msg => {
return new Promise((resolve, reject) => {
let rawData = '';
msg.on('data', chunk => { rawData += chunk });
msg.on('end', () => {
resolve(rawData);
});
});
})
.then(json => {
JSON.parse(json);
return json;
})
}
I would say that you need to refactor the code a little bit to be more testable.
When I write unit tests for functions I keep below points in mind
You do not need to test for the inbuilt or library modules as they are already well tested.
Always refactor your functions to have very specific reponsibility.
Implementing these two in your example, i would separate the server call in a service module whose sole responsibility is to take url (and configurations, if any) make server calls.
Now, when you do that you get two benefits 1. you have a reusable piece of code which you can now use to make other server calls(also makes your code cleaner and shorter)
Now all thats left to test in your getJSON function is to spyOn that service module and use tohaveBeenCalledWith and check that data is properly parsed.You can mock the service to return your desired data.
1 its making a service call so test for toHaveBeenCalledWith
2 its parsing to JSON so test for valid/invalid JSON also test for failures
//no need to test whether https is working properly
//its already tested
const https = require('https');
const service = require("./pathToservice");
function getJSON() {
return service.get(somConfig)
.then(json => {
JSON.parse(json);
return json;
})
}
//its cleaner now
//plus testable