stub request library in javascript - javascript

I'm using a third party restful service for sending SMS verification code. I wrote an unit test for it. However I dont want to be sent a message each time I run the unit-test.
The code is like:
const _request = require("request");
_request({
method: "POST",
url: "http://blah.com/json",
form: {
apikey: "blah",
mobile: input.mobilePhoneNumber,
text: `code is: ${verificationCode}`,
}
}, (err, res, body) => {
if (err) {
dbg(`end, output=${err}`)
return reject(new Error("something wrong"))
} else {
dbg(`end, output=${res}`)
return resolve({})
}
})
And in the test Im using sinon.stub
sinon.stub(request, "post").returns(Promise.resolve({}))
However this stub doesnt really catch the "post" method in request. I looked into the source code and tried many ways (like stub the constructor instead), but none works.
Wondering if there's anyone tried this before. How shall I stub this post method on request?
Thanks!

Your code is not calling request.post(), so stubbing it won't catch the call you're making.
Instead, you need to stub the request function itself, which is difficult to do with Sinon alone because it requires a "parent" object in which it can replace/stub a method/function.
You can work around that using proxyquire, which you can use to "catch" the import of request and replace it with a stub:
const sinon = require('sinon');
const request = require('request');
const proxyquire = require('proxyquire');
let stub = sinon.stub();
const mod = proxyquire('./your-module', { request : stub });
In your test cases, you can make stub yield to the callback you pass:
let fakeError = null;
let fakeResponse = {};
let fakeBody = '';
stub.reset();
stub.yields(fakeError, fakeResponse, fakeBody);
The arguments to yields represent err, res and body in your code. You can pass various combinations to check if your code handles the responses properly.
The reason for calling stub.reset() is that you need to make sure, before each test, that the stub is reset to its original state (so it starts "fresh").

Related

Testing basic async http request in Node with Got, Nock & Chai

I am trying to figure out why my unit test is not working correctly. It seems that the external network request is made despite my using Nock to intercept my http request.
I have a very basic getUser service, getuser-got.js:
const got = require('got');
module.exports = {
getUser(user) {
return got(`https://api.github.com/users/${user}`)
.then(response=>JSON.parse(response.body))
.catch(error => console.log(error.response.body))
}
};
This can be called succesfully but I want a unit test for it.
Here's my code in a file named getuser-got.test.js:
const getUser = require('../getuser-got').getUser;
const expect = require('chai').expect;
const nock = require('nock');
const user_response = require('./response');
describe('GetUser-Got', () => {
beforeEach(() => {
nock('https//api.github.com')
.get('/users/octocat')
.reply(200, user_response);
});
it('Get a user by username', () => {
return getUser('octocat')
.then(user_response => {
// expect an object back
expect(typeof user_response).to.equal('object');
// test result of name and location for the response
expect(user_response.name).to.equal('The Octocat')
expect(user_response.location).to.equal('San Francisco')
})
});
});
The file named response contains a copy of the expected response from the Github API, which I am loading into the user_response variable. I have replaced the values for name and location in order to make my test fail.
module.exports = {
login: 'octocat',
...
name: 'The FooBar',
company: '#github',
blog: 'https://github.blog',
location: 'Ssjcbsjdhv',
...
}
The problem is that I can see that Nock is not intercepting my request. When I run the test it continues to make an actual call to the external API. The test therefore passes, because it is not using my local response as the return value.
I've tried adding in nock.disableNetConnect(); but this just causes the test to timeout, as it's clearly still trying to make the external call. If I run my test I get:
➜ nock-tests npm test
> nock-tests#1.0.0 test /Users/corin/Projects/nock-tests
> mocha "test/test-getuser-got.js"
GetUser-Got
✓ Get a user by username (290ms)
1 passing (296ms)
What am I doing wrong to not have Nock intercept my http request?
The value being passed to the nock function is not a valid URL, it's missing the colon in the schema.
Updating it to nock('https://api.github.com') gets the test to fail locally, as desired.

Sinon stub block of http post request inside non-exported function in node.js

I had a block of post request for which I need to stub response inside non-exported function as mentioned below:
function callMicroserive(a, b, c){
//before post request code part
request.post(requestoptions, function (error, httpResponse, body) {//code}
//after post request code part
}
I don't want to stub and return callMicroserive function on a whole but need to stub http post request inside function.
I tried to implement using sinon along with rewire setter and getter methods.But I can't make to stub http request block alone. Can anyone provide code template for this issue?
Proxyquire
Tried with proxyquire as mentioned in below:
const postcall = proxyquire('../plugins/routes/handlers/contentservicehandler.js', {post : {httpResponse:{statusCode : '200'},'#noCallThru': true}});
postcall();
Sinon
With Sinon, tried below ways:
var request = require('request');
sinon.stub(request, 'post').returns(//jsonObject);
also tried
sinon.yields(null, httpresponse,body)// to send arguments to callback
Rewire
const contentHandler = rewire('../plugins/routes/handlers/contentservicehandler.js');
const postCall = {post:contentHandler.__get__('request.post')};
var stub = sinon.stub(postCall,'post').returns(//json);
contentHandler.__set__('post', stub);
Getting error 'Invalid URI /' when call to request.post() is called with all unit packages. Looks like it is hitting server for actual response.

getting progress callback with jQuery and node express server

I am trying to grasp using node express server and jQuery.ajax() in tandem. I have created a code repository with the following structure:
/
|-public
| |-index.html
|-server.js
My index page has the following JS snippet in it:
var successHandler = function (data, status, jqXHR) {
console.log('success')
};
var failHandler = function (jqXHR, status, errorThrown) {
console.log('fail')
};
var progressHandler = function () {
console.log('progress')
};
var ajaxConfig = {
url: 'http://localhost:4444/test',
type: 'GET'
};
$.ajax(ajaxConfig).then(successHandler, failHandler, progressHandler);
the server-side code is defined as such:
const express = require('express')
const app = express()
const sleep = require('sleep')
app.get('/test', function (req, res) {
console.log('/test method called!');
sleep.sleep(3);
res.status(202).send({"thing":"stuff"})
})
app.post('/test', function(req,res){
res.status(202).send('ok')
})
app.use(express.static('public'))
app.use(express.static('node_modules/jquery/dist'))
app.listen(4444, function () {
console.log('Running on localhost:4444!')
})
The thing that I want to accomplish is to get some hits on the progress handler, just to get it to write data in the console.
According to this page, I need to use the deffered.notify() method to trigger the handler but I have no idea how to get to the deffered object. I tried saving the return value of $.ajax() but that doesn't seem to have the notify() method since it is a jqXHR object.
It is my understanding that I need to have a progress handler defined on the server-side (the post handler for the /test route) that gets called to get to the current status of the pending task. Don't think making a new ajax request is the way to go, but I might be wrong. I have also found some articles that utilize the setTimeout method, My guess is that it gets used in order to repeatedly call the endpoint that gives status info.

ExpressJS apparent race condition between Promise and EventEmitter

I have a NodeJS/Express web application that allows the user to upload a file, which I then parse using connect-busboy save to my database using Sequelize. Once that's done, I want to redirect the user to a given page. But Express is returning a status of 404 before my Promise resolves, even though I'm never calling next(), which I thought was mandatory in order to call the next handler in the middleware chain and thus result in a 404.
This is my code so far:
function uploadFormFile(req, res, next) {
var documentInstanceID = req.params.documentInstanceID;
// set up an object to hold my data
var data = {
file: null,
documentDate: null,
mimeType: null
};
// call the busboy middleware explicitly
// EDIT: this turned out to be the problem... of course this calls next()
// removing this line and moving it to an app.use() made everything work as expected
busboy(req, res, next);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldName, file, fileName, encoding, mimeType) {
var fileData = [];
data.mimeType = mimeType;
file.on('data', function (chunk) {
fileData.push(chunk);
});
file.on('end', function () {
data.file = Buffer.concat(fileData);
});
});
req.busboy.on('finish', function () {
// api methods return promises from Sequelize
api.querySingle('DocumentInstance', ['Definition'], null, { DocumentInstanceID: documentInstanceID })
.then(function (documentInstance) {
documentInstance.RawFileData = data.file;
documentInstance.FileMimeType = data.mimeType;
// chaining promise
return api.save(documentInstance);
}).then(function () {
res.redirect('/app/page');
});
});
}
I can confirm that my data is being persisted correctly. But due to the race condition, the web page says 'can't POST' due to the 404 status being returned by Express, and the res.redirect is failing with an error setting the headers because it's trying to redirect after the 404 has been sent.
Can anyone help me figure out why Express is returning the 404?
The problem is coming from your internal call to busboy inside your handler. Rather than it executing and simply returning control to your handler, it would be calling the next which is passed to it before it returns control. So you code after the busboy call does execute, but the request has already advanced past that point.
In cases in which you want some middleware to only be executed for certain requests, you can chain middleware into those requests, such as:
router.post('/upload',busboy,uploadFromFile)
You can also separate them with .use() such as:
router.use('/upload', busboy);
router.post('/upload', uploadFromFile);
Either of the above will chain the middleware in the way you intended. In the case of .use() the middleware would also be applied to any applicable .METHOD() as Express refers to it in their documentation.
Also, note that you can pass in an arbitrary number of middleware this way, either as separate parameters or as arrays of middleware functions, such as:
router.post('/example', preflightCheck, logSomeStuff, theMainHandler);
// or
router.post('example', [ preflightCheck,logSomeStuff ], theMainHandler);
The execution behavior of either of the above examples will be equivalent. Speaking only for myself and not suggesting it is a best practice, I normally only use the array-based addition of middleware if i am building the middleware list at runtime.
Good luck with it. I hope you enjoy using Express as much as I have.

How to correct this test case in mocha framework?

I am trying to write test case for node application, which is using mocha as test framework.
test.js
var register = require('../routes/users');
var request = require('request');
var baseUrl = 'http://localhost:5000';
describe('registerUser()', function() {
it('check email is already registered', function (done) {
request.post({uri:baseUrl+'/register', form :{
username: 'test',
email: 'test#test.com'
}}, function (e, res, body) {
res.should.have.property('statusCode', 201);
res.should.have.property('regErr', 'This email is already taken!');
})
});
})
The regErr is given as parameter in function registerUser on render. I expected the parameterregErr will be set as property of response and can be get in test.
Please check my registerUser function in github.
I am trying create a test case for this function.
Above code doesn't have property called regErr in response fetched in test case.
How to correct so that the rendering parameters can also be property in response?
Shall I need to change the actual function registerUser to get this? If so, how can I achieve this?
When doing an HTTP request, the callback function is called with three arguments:
err (Possible error return)
res (HTTPRequest object)
body (Buffer of the resulting body)
Therefore, regErr is in the body variable. And since you are rendering an HTML page, you're gonna have to parse the body yourself to find it. A possible solution would be to render JSON and use JSON.parse() on the resulting body buffer.

Categories