sinon.js stub - How to stub async.map - javascript

I want to test following function.
var myFun = function (a, b, callback) {
async.map(a, function (b, mapCallback) {
//Do something with b => code I don't want to execute
mapCallback(null, res)
},
function (err, output) {
if (err) {
Logger.error(err);
return callback(err, null);
}
return callback(null, output.filter(function(n){ return n != null }));
});
}
Here I am using async.map, what I want is to stub. async.map takes 3 parameters, first array and second and third callback. I want to stub second callback as well and call third callback with test values. How to do it?
I tried:
var mockAsync = sinon.stub(async, "map")
mockAsync.yields("Some error", null);
But this executes second function and not third function, I tried using callsArg, but that also did not help, not sure that is relevant here or not.

See in Sinon docs
stub.callArg(argNum)
stub.callArgWith(argNum, [arg1, arg2, ...])
In your context it should be
mockAsync.callArgWith(1, "Some error", null)

Related

Why does it matter to Mocha's `before()` whether the function passed takes parameters or not?

I have code like this in my describe: before(a).
When a looks like this:
function a() {
return chai.request(app)
...
.then(res => {
res.blah.should.blah;
return Promise.resolve();
});
}
...everything works great (it's a very quick call.)
However, when I make a take some input variables:
function a(dummy, my_var) {
return chai.request(app)
... // use my_var here
.then(res => {
res.blah.should.blah;
console.log("finished!");
return Promise.resolve();
});
}
The promise never resolves. Two observations:
finished! does get properly output (immediately)
dummy is populated.
It's populated with this:
function (err) {
if (err instanceof Error || toString.call(err) === '[object Error]') {
return done(err);
}
if (err) {
if (Object.prototype.toString.call(err) === '[object Object]') {
return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err)));
}
return done(new Error('done() invoked with non-Error: ' + err));
}
if (result && utils.isPromise(result)) {
return done(new Error('Resolution method is overspecified. Specify a callback *or* return a Promise; not both.'));
}
done();
}
I don't know where that's from exactly, but I don't need it, that's why I just put it into a dummy variable.
Now I suspect that has something to do with it, but I wonder why my workaround doesn't do the trick here.
I still want to use before(a) for the default case, leaving my_var undefined. When I do actually want to pass that variable, I intended to:
before(() => {
return a('my_content');
})
That's because Mocha inspects the function you pass to before to check how many parameters are defined on it like this:
this.async = fn && fn.length;
If there's any parameter defined, then the function is deemed to be asynchronous. (Mocha also checks if it returns a promise but that's a different test.) If there's at least one parameter defined, then Mocha passes as 1st parameters a function that you are meant to call when your before callback is done doing its work. That callback (traditionally named done) is useful for code that does not use promises.
If you do not call it, then Mocha waits forever even if you return a promise.
Note that Mocha does the same with all other hooks: beforeEach, after, etc., and with the callback you pass to it.
Mocha before, after, it function accepts one parameter - callback. It should be defined and called when your test uses async functions:
db.connect is async function:
before(done => {
db.connect(done);
}
When db.connect returns a promise you shouldn't use callback and could return the promise:
before(() => {
return db.connect();
}
In your code, you call before with a function, which accepts two parameters. Mocha interprets the first parameter as callback, and tries to call it.
To prevent this issue, you need to call a function directly and pass params in it:
before(() => {
return a(dummy, my_var);
}

Callback mechanism in Javascript

I am trying to understand the callback mechanism in javascript(typescript). If I have a function which expects a callback as input argument, do I have to explicitly use a return statement to hook it up with the actually callback implementation form the calling code OR we can simply have use "callback" reference in the code being called and it automatically hooks up with callback code in the calling code
Code samples (typecript)
// callback code being hooked up using return statement
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
return callback(err, null);
db.collection(collectionName).remove();
});
return callback();
}
// callback code being hooked up using reference to reserved callback keyword for automatic hook up with calling code
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
return callback(err, null);
db.collection(collectionName).remove({}, callback);
});
}
You don't need to return, you can simply call it like
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
callback(err, null);
db.collection(collectionName).remove();
});
return callback();
}
// callback code being hooked up using reference to reserved callback keyword for automatic hook up with calling code
clear(collectionName: string, callback: any) {
this.getConnection((err, db) => {
if (!db)
callback(err, null);
db.collection(collectionName).remove({}, callback);
});
}
No. Functions are first-class citizens in Javascript thus you can use them as a normal variables and pass them all around. You just need to call them (as normal functions) at proper moments. No return statement required. For example look at how Array.prototype.forEach works under the hood. It accepts the callback as a parameter that gets currently iterated element as a first argument and current index as a second argument:
Array.prototype.forEach = function(callback) {
for(i = 0; i < this.length; i++) {
if (callback) callback(this[i], i)
}
}

SailsJS Nested callback in async waterfall function not returning correct value

I'm creating an application with SailsJS. I have a question about using callbacks within an Async waterfall and Async each.
I've got two functions inside an async waterfall function. The first callback returns the correct value. The second function has a nested callback. However, the value of the nested callback is stuck within the waterline find function, and never gets returned to the outer function.
Do you know how I could return the value to the outer function?
Thanks for your help.
myFunction: function (req,res) {
async.waterfall([
function(callback){
// native MongoDB search function that returns an Array of Objects
},
function(result, callback){
async.each(resultAll, function (location){
Model.find({location:'56d1653a34de610115d48aea'}).populate('location')
.exec(function(err, item, cb){
console.log (item) // returns the correct value, but the value cant be passed to the outer function
})
})
callback(null, result);
}], function (err, result) {
// result is 'd'
res.send (result)
}
)}
When you use async's function you should you should use you callback once you are done with operations you want to perform.
for example:
async.waterfall([
function(cb1){
model1.find().exec(function(err,rows1){
if(!err){
model2.find({}).exec(function(err,rows2){
var arr=[rows1,rows2];
cb1(null,arr);
});
}else
cb1(err);
})
},function(arr,cb2){
/**
* here in the array....we will find the array of rows1 and rows2 i.e.[rows1,rows2]
* */
model3.find().exec(err,rows3){
if(!err){
arr.push(rows3);
// this arr will now be [rows1,rows2,rows3]
}
else
cb2(err);
}
cb1(null,arr);
}],
function(err,finalArray){
if(err){
// error handling
}
else{
/**
* in finalArray we have [rows1,rows2] ,rows3 is not there in final array
* beacause cb2() was callbacked asynchronously with model3.find().exec() in second function
*/
}
});
so according to me your code should be like
async.waterfall([
function(callback){
// native MongoDB search function that returns an Array of Objects
},
function(result, callback){
async.each(resultAll, function (location){
Model.find({location:'56d1653a34de610115d48aea'}).populate('location')
.exec(function(err, item, cb){
console.log (item) // returns the correct value, but the value cant be passed to the outer function
callback(null, yourData);
/**
* yourData is the data whatever you want to recieve in final callbacks's second parameter
* i.e. callback(null,item) or callback(null,[result,item]) or callback(null,result)
*/
})
})
}], function (err, result) {
// result is 'd'
res.send (result)
}
);
Apply this and you can see things you want in your final callback.

nodejs callback don't understand how callback result come through argument

Seen and run code below, thought I understand closures... How that 'avatarUrl' in callback argument is received in 'avatar'which is function argument too. I know this is common pattern, just can't get it yet
var GitHubApi = require('github');
var github = new GitHubApi({
version: '3.0.0'
});
var getUserAvataWithCallback = function(user, callback) {
github.search.users({q: user}, function(err,res) {
if (err) { callback(err, null);}
else {
var avatarUrl = res.items[0].avatar_url;
callback(null, avatarUrl);
}
});
};
getUserAvataWithCallback('irom77', function(err,avatar) {
console.log('got url with callback pattern', avatar);
})
So, callbacks are an underlying and integral concept in javascript, so it is important that you understand a few concepts. Look at this example:
// This is the function definition for "foo"
//here the callback argument refers to
//the second argument in the function call at
//the bottom which is a function
var foo = function(arg, callback) {
if(arg%2 != 0)
callback("arg is odd", arg)
else
callback(null, arg)
}
//Function call to foo
foo(2, function(err, num) {
if(err)
console.log(err)
else
console.log(num)
}
So, in the example above, you can think of the function call as a call with two parameters, the integer 2 and a function.
In the function definition:
The integer is referred to as "arg" and the function is referred to as "callback".
When callback("arg is odd", arg) is executed, the function is called with:
err = "arg is odd"
num = arg
When callback(null, arg) is executed, the function is called with:
err = null
num = arg
The important thing to remember here is that in javascript, functions can be passed as arguments to other functions. Do some further reading here.
The name of the argument passed to a function does not need to be the name of the argument in the definition of the function, the argument in the definition is the name of the variable that will be initialized inside the scope of given function. The argument declaration will receive the value passed at the second position of the function call (as per the code you've provided) and you will be able to access it inside the scope with that name. You can:
function foo(arg1, arg2) {
console.log(arg1, arg2);
}
foo(true, true); // will output true, true
foo(0, 1); //will output 0, 1
foo('shikaka', 1); //will output "shikaka", 1
var bar = "shikaka";
foo(bar, "shikaka"); //will output "shikaka", "shikaka"

Function not returning results

I'm trying to refactor some complexity into a function called getData but code that calls this function doesn't seem to be getting the results.
function getData(sql) {
pool.getConnection(function(err, connection) {
if (err) return;
connection.query(sql, function(err, rows) {
if (err) return;
if (rows.length > 0) {
console.log(rows); // This outputs result from table
return rows;
} else {
return [{"error":"Not found"}];
}
});
connection.end();
});
}
However, when it is called from a function like this, I get undefined returned, even though code inside the function works fine.
app.get('/1/employees/past', function(req, res, next) {
var rows = getData("select * from users");
res.json(rows);
})
Your return is returning from the inner function, which doesn't affect the outer function.
You'd need to capture it and return it, and seeing as it appears to work with callbacks, you'd need to pass an additional callback to getData().
Something like this...
function getData(sql, callback) {
// ...
connection.query(sql, function(err, rows) {
// ...
callback && callback(rows); // etc
});
// ...
}
If you wanted to be safer, ensure the callback implements [[Call]] with typeof (link to my own blog post).
Your getData function does not return anything - the return statements inside the code are all for the anonymous functions which you pass into connection.query and connection.query.
Your connection-related function are asynchronous - i.e. they return immediately after you call them without waiting for any results to be available. If you want to do something with the results which get returned you need to do it inside one of the anonymous functions, rather than trying to do it as soon as getData completes.
The getData function is not returning anything! The getConnection function inside the getData function is calling a function which calls a function which returns something; the getData function itself is not returning anything.
What's more, if this code executes asynchronously, all the returns will execute long after the getData function has returned.
You're either going the synchronous return route or the asynchronous callback route, you can't mix both styles.

Categories

Resources