Javascript unit testing, force error in sinon stub callback - javascript

I am trying to test one last bit of this function I cannot seem to hit correctly. Here is the function
CrowdControl.prototype.get = function(callback) {
var options = this.optionsFor('GET');
return q.Promise(function(resolve, reject) {
callback = callback || function callback(error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
};
callback();
request(options, callback);
});
};
And the part I can't seem to hit is
if (error) {
reject(error);
} else {
resolve(body);
}
I have the request set as a stub, and here is what I am trying
it("should call callback, which should reject if errors.", function() {
var testCallback = testHelpers.stub();
request.returns("Error");
crowdControl.get(testCallback);
//expect(testCallback).to.have.been.called;
expect(testCallback).to.have.been.calledWith("Error");
});
Seems like it is not working as I expected, I need to test the callback throwing an error. Thanks!

Related

node.js - Does calling the callback terminate the current function

I want to call a util function that might encounter an error. In case of an error the process function should be terminated. The only way to throw an error properly is the callback function.
I would terminate the function by returning, but since I am in the util function, the process function will continue after the util() call.
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
return callback("something unexpected happened");
}
}
function process(callback) {
util(callback);
console.log("This should not be printed if an error occurs!");
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
// terminate the process function somehow?
}
});
Does calling the callback terminate the current function?
No, a callback is just a regular function. It might of course throw an exception (although that is despised).
I want to call a util function that might encounter an error. In case of an error the process function should be terminated.
For that, you need to check in the callback what did happen and act accordingly. You could use process.exit for termination.
function myProcess(callback) {
util(function(err, result) {
if (err) {
callback(err);
} else {
console.log("This should not be printed if an error occurs!");
callback(null, result);
}
});
}
myProcess(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1);
}
});
Notice that promises could simplify this a lot, as they distinguish between success and error callbacks. util would have to return a promise for that:
function util() {
return new Promise(function(resolve, reject) {
// do something asynchronous
if (err)
reject("something unexpected happened");
else
resolve(…);
});
}
function myProcess() {
return util().then(function(res) {
console.log("This should not be printed if an error occurs!");
return res;
});
}
myProcess().catch(function (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1); // you might not even need this:
throw err; // The node process will by default exit with an unhandled rejection
});
I suggest you make a few changes to your code
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
callback("something unexpected happened");
return false;
}
return true;
}
function process(callback) {
if(!util(callback)) return;
console.log("This should not be printed if an error occurs!");
}
This seems like a good time to use a Promise, promises are Javascript's way of forcing a synchronous function. Basically you set it up like this:
var util = new Promise(function(resolve, reject) {
/* do some stuff here */
if (someCondition) {
resolve("With a message");
} else {
reject("with a message");
}
}
function process() {
util.then(function() {
console.log("Won't call if there is an error");
}).catch(function() {
console.log("There was an error, Bob");
});
}
No, you will want to do something like this:
function util(callback) {
// do something synchronous
if (err) {
throw new Error('Something unexpected happened');
}
callback(); // only execute callback if an error did not occur
}
function process(callback) {
try{
util(callback);
console.log("This should not be printed if an error occurs!");
} catch(error){
process(error);
}
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1)
}
});

Node js error handling with callbacks in nested functions

I know this kind of error handling is not right, promises should be used instead, but I am wondering if it could work as it is:
router.get('/main', function(req, res, next) {
var myCallback = new function(err, data){
if(err) {
res.status(500).send({ error: "Error (best handling ever)" });
return;
}
res.send("Success");
return;
};
mainProcess(myCallback);
});
function mainProcess(callback){
request.post(requestParams, function(error, response, body) {
if (error) {
console.log(error.message);
callback.return(error, "");
} else {
request.post(requestParams, function(error, response, body) {
if (error) {
console.log(error.message);
callback.return(error, "");
} else {
// Success
callback.return(null, "Success");
}
});
}
});
}
I could test it myself, but I need to know whether callback that was passed as a parameter could be used in nested functions and whether it's the right approach.

Sending request from node.js to apache2.2.21

I am calling function dorequest many times per request to node server.
I have problem with request to webpage running on apache2.2.21. Almost of these request are done without any problems, but several request ending with error ECONNRESET and I don't know why. If I use apapche2.4 then everything going well.
var request = require('request');
function dorequest(set, callback){
request.get(url, function optionalCallback(err, httpResponse, body){
if (err){
console.log(url);
throw err;
} else {
//do some stuffs
}
});
}
Probably your apache server simply drops your request because there are too many connections at the same time initiated by dorequest function.
You can execute those request consequently by calling one in the callback of another by calling the next request in the callback for the previous one, but since there are quite a lot of them and for estetic reasons I would recommend to use async library - it's awesome and really handy when dealing with things like that.
function dorequest(set, callback){
request.get(url, function optionalCallback(err, httpResponse, body){
if (err){
callback(err);
} else {
//do some stuffs
}
callback(err, res);
});
}
var maxRequestAtATime = 30;
async.mapLimit(arrayOfOptions, maxRequestAtATime, dorequest, function(err, results){
// results is now an array of stats for each request
});
If the options of a request depend on the options of the previous one, you should use async.waterfall.
I updated script and use async.queue function for that and still have some err on apache.
function dorequest(set, callback)
{
console.log('add request');
q.push({set: set, callback: callback}, function (err) { });
}
var q = async.queue(function (task, callback) {
setTimeout(function () {
console.log('hello ' + task.set.url, ' lenght: ',q.length());
if (task.set.method=='get')
{
myrequest.get(task.set.url, function optionalCallback(err, httpResponse, body)
{
if (err)
{
console.log(task.set.url);
throw err;
}
else
{
//console.log(set.url,body);
if (typeof task.callback !='undefined') task.callback(body);
callback();
}
});
}
else
{
if (!task.set.data) task.set.data={};
myrequest.post(task.set.url, function optionalCallback(err, httpResponse, body)
{
if (err)
{
console.log(task.set.url);
throw err;
}
else
{
//console.log(set.url,body);
if (typeof task.callback !='undefined') task.callback(body);
callback();
}
}).form(task.set.data);
}
},500);
},1);

How can I avoid my Q promise catch block being called twice in a NodeJS callback-style API when running mocha unit tests?

We're using the Q promise library in our node API, but allow functions to be called via callbacks.
For example:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}).catch(function (err) {
return cb(err, null);
});
}
When I run my mocha unit tests, if there is an exception in the callback, it results in the the callback being called twice.
For example:
var called = 0;
foo(function (err, res) {
called++;
console.log('err: ' + err);
console.log('res: ' + res);
console.log('called: ' + called);
throw Error(throw Error from foo!');
});
This gives the following result:
err: null
res: true
called: 1
err: Error: throw Error from foo!
res: null
called: 2
One approach we found was to do the following:
function foo2(cb) {
var _result, _err;
Q.fcall(function () {
return true;
}).then(function (result) {
_result = result;
}).catch(function (err) {
_err = err;
}).finally(function () {
_.defer(cb, _err, _result);
});
}
The idea was to have one place where the callback would be called and try to prevent developer errors by enforcing the defer to clear the call stack.
With this approach, our callback is called once, and any errors (or in our case, asserts) get handled directly by the caller.
Is there a better technique we can use? I feel like this is a pretty common scenario, so I'd imagine there exists a cleaner solution...
Modify your foo function to handle both the fulfillment and the rejection in the same then call using 2 separate handlers:
function foo(cb) {
Q.fcall(function () {
return true;
}).then(function (result) {
return cb(null, result);
}, function (err) {
return cb(err, null);
});
}

can't submit a form on express/angular app

in my program there's a validation function on it, if there's an error it will prevent the form to submit and display error msg else it will console.log("Success") but my form cannot be submitted even without any error. is there anyway to enable status code 200 when there is no error ? because now the form prevent me to submit because of status code 400
express
function validateSignup(data,callback) {
"use strict";
var USER_RE = /^[a-zA-Z0-9_-]{2,25}$/;
var PASS_RE = /^.{6,100}$/;
var EMAIL_RE = /^[\S]+#[\S]+\.[\S]+$/;
if (!USER_RE.test(data.publicUsername)) {
callback(new Error('Invalid Public Username try just letters and numbers, e.g: Ed, 69, Kelvin and etc'), null);
}
if (!PASS_RE.test(data.password)) {
callback(new Error('Password must be at least 6 characters long'), null);
}
if (data.password != data.confirmPassword) {
callback(new Error('Password must match'), null);
}
if (!EMAIL_RE.test(data.email)) {
callback(new Error('Invalid email address'), null);
}
if (data.email != data.confirmEmail) {
callback(new Error('Email must match'), null);
}
return true;
}
handlesignup
this.handleSignup = function(req, res, next) {
"use strict";
validateSignup(req.body, function(error, data) {
if(error) {
res.send(400, error.message);
} else {
console.log("success");
}
})
}
Angular
function RegisterCtrl($scope, $http, $location) {
$scope.form = {};
$scope.errorMessage = '';
$scope.submitPost = function() {
$http.post('/register', $scope.form).
success(function(data) {
$location.path('/');
}).error(function(err) {
$scope.errorMessage = err;
});
};
}
You have multiple issues in your code.
Your validateSignup function doesn't always call its callback. If the input passes the validation, it shouldn't return true but instead call its callback with no error and the data:
function validateSignup(data,callback) {
// ...
callback(null, data);
}
You don't always answer the client's request:
validateSignup(req.body, function(error, data) {
if(error) {
res.send(400, error.message);
} else {
console.log("success");
res.send(200);
}
})
Edit: As a side note, a callback should aways be called asynchronously (ie. using process.setImmediate, process.nextTick or setTimeout), but that isn't an issue in your specific case as the callback will always be called synchronously. As noted in Effective JS, item 67:
Never call an asynchronous callback synchronously, even if the data is immediately available.
That's why my advice is to always call callbacks asynchronously, which will free you from weird bugs later on. There are a number of reasons as why you shouldn't do it, but the most obvious is that you can easily blow the stack.
Here's how you you can defer the callback execution:
function validateSignup(data,callback) {
// ...
process.setImmediate(function() {
callback(null, data);
});
}

Categories