How to test the content of callback of method - node.js

I might not be getting something but I am trying to test the callback content of a method but without calling the method.
The function I am trying to test
functionToSkip(param1, param2, function(arg1, arg2){
if(arg1){
// Do some things here
} else {
// Do other things here
}
}
What I am trying to do is to test the content of the callback function with differents args values that I can change in the tests and the parameter of the functionToSkip can be anything.
All I successfully did is to skip the call of the function but I cannot call the callback method.
I did stub the function to skip and even trying to give values to the callback method but there is not any logs showing.
var spy = sinon.stub(Class, "functionToSkip").calledWith(param1, param2, ("arg1","arg2"))
The main method that is calling the stubbed function works since I can see the logs prior of the function when I call it in the tests.

First of all, if functionToSkip is an instance method on Class, it will be a property on Class.prototype, not Class itself. In order to stub, you can do one of two things:
Create an instance, and create the stub:
instance = new Class(/*costructor arguments*/)
var stub = sinon.stub(instance, 'functionToSkip')
Or, stub on the prototype:
var stub = sinon.stub(Class.prototype, 'functionToSkip');
In the second case, since class prototypes are global state, I'd recommend restoring it-- preferably in something like mocha afterEach to ensure it gets cleaned up whether your test is successful or not. This way it doesn't screw with other tests in your run:
stub.restore()
Between the two, though, I recommend the first approach.
Next up... If you want to make assertions on the content of calls, the firs thing you'll probably want to do is assert that it was in fact called with the signature you're looking for:
sinon.assert.calledWith(stub, sinon.match.any, sinon.match.any, sinon.match.func)
The any matcher allows any value, and the func matcher requires a func. After that, you can obtain the callback function like so:
var cb = stub.firstCall.args[2]
And invoke it like so:
cb('arg1', 'arg2');
As to what assertions you'd do after invoking the callback function-- I'd have to know more about what you're trying to test about it to make recommendations.

Related

jest assert a function have been called twice and both times with particular argument

I am testing a Vue component that dispatches an action(functionx) on mount. The same action(functionx) is dispatched when a particular refresh button is clicked. I am testing the behavior of that refresh button - that is the vuex dispatch action is called with argument 'functionx'. Here is my test:
it('makes an api call to server when refresh button is clicked', () => {
store.dispatch = jest.fn();
const wrapper = mount(Categories, {
sync: false,
store,
localVue
});
const refreshButton = wrapper.find('span.fa-sync');
refreshButton.trigger('click');
expect(store.dispatch).toHaveBeenCalledWith('categoryStore/fetchCategories');
})
});
which passes. Now since the same action is dispatched initially when the component is mounted. So in total dispatch is called twice. I know I can use .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....) to check that dispatch was called both times with same argument, but for that I will have to write two expect statements, like below:
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'categoryStore/fetchCategories');
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'categoryStore/fetchCategories');
Is there any way I can achieve the above thing in one statement? Any matcher function or any property on the expect object that can be used?
Sadly there's currently no easy matcher for this situation (list of matchers).
You could do it "manually" using the .mock parameter, something like this:
function assertFunctionWasCalledTimesWith(jestFunction, times, argument) {
expect(jestFunction.mock.calls.filter((call) => call[0] === argument).length)
.toBe(times)
}
(Using the filter method makes the times assertion only take into account the calls that have given argument)
Using the above function you could assert your code like this:
assertFunctionWasCalledTimesWith(store.dispatch, 2, 'categoryStore/fetchCategories')
Of course, the message when the test fails won't be very descriptive, but it works, anyway.

Nodejs Callback: How to define a Callback?

I am reviewing a sample nodejs server code, which is working fine. but could not understand the following code:
var handlers = {};
// Creating a sample handler
handlers.sample = function(data,callback){
callback(406,{'name':'sample handler'}); // How is this line of code working??
};
// Creating a not found handler
handlers.notFound = function(data,callback){
callback(404); // How is this line of code working??
};
In the entire code there is no implementation of "callback" function then how
callback(406,{'name':'sample handler'});
and
callback(404);
are working?
Please suggest. Thanks.
callback isn't implemented in the code you posted; it's a named parameter.
To call one of the functions that requires a callback, you'll need to pass it in as an argument, like:
handlers.sample("some data", () => console.log("I'm in a callback!));
The first argument ("some data") goes in the data parameter, and the second argument (() => console.log("I'm in a callback!)) goes in the callback parameter. When callback(404) is run, it executes the callback function (in the above example, it would do console.log("I'm in a callback!)).
Basically, when you call handlers.sample, you should pass a function as your second argument, and that function will be called, usually asynchronously, and presumably after something is done with the data you pass as the first argument. For example, based on the code you provided:
handlers.sample(dataObject, (number, object) => {
console.log(number)
console.log(object.name)
})
would yield this result in the console:
406
sample handler
I’m curious if this is a public library you are seeing this code in, so we can take a closer look?
I did a further digging in into this and found that
selectedHandler
in the following code (this is not mentioned in the question) is getting resolved into handlers.sample or handlers.notFound variable names based on some logic (which is not mentioned here)
selectedHandler(data,function(status,payloadData){
// somelogic with the status and payloadData
});
And second parameter of this function which is a complete function in itself
function(status,payloadData){
// somelogic with the status and payloadData
}
is going as the second parameter in handlers.sample or handlers.notFound which is a Callback. So execution of Callback in the current context is execution of this function (this function is anonymous because it has no name and getting executed as Callback)

Node tutorial - LearnYouNode - Juggling Async - using nested callbacks

I was trying to solve the "Juggling Async" problem in the "learnyounode" workshop from nodeschool.io. I saw a lot of questions here about this problem where it is not working because the url's were being called from a loop. I understand why that wouldn't work.
I had tried something like this.
var http=require('http');
console.log(process.argv[2],process.argv[3],process.argv[4]);
fn(process.argv[2],
fn(process.argv[3],
fn(process.argv[4])));
function fn(url,callback){
http.get(url,function(response){
var string='';
response.setEncoding('utf8');
response.on('data',function(data){
string+=data;
});
response.on('end',function(){
console.log(url,string);
if (callback) {
callback();
}
});
});
};
As per my understanding, the second GET call should go out only after the first one has ended, since it is being initiated after response end. But the output is always in different order.
I have seen the correct solution. I know that doing it this way fails to leverage the advantage of async, but shouldn't the callbacks make it output in order?
When you pass in a function as a callback, you need to only pass in the function name or function definition. By providing the arguments, you are actually calling the function.
E.g. let's say you had a function f1 that took in another function as a parameter, and another function f2 that you want to pass into f1:
function f1(func_param) {
console.log('Executing f1!');
}
function f2(a_param) {
console.log('Executing f2!');
}
When you do the following call (which is similar to what you are doing, providing a callback function and specifying parameters for the callback):
f1(f2(process.argv[2]));
You're evaluating f2 first, so 'Executing f2!' will print first. The return of f2 will get passed as a parameter into f1, which will execute and print 'Executing f1!'
In your call
fn(process.argv[2],
fn(process.argv[3],
fn(process.argv[4])));
You are saying, let's pass the result of fn(process.argv[4]) as a callback to fn(process.argv[3]), and we'll get the result of calling that and pass that as a callback to fn(process.argv[2]).

share data between events

I tend to write a function like this:
library.getCookie(request.headers.cookie,function(cookies){
db.query("SELECT name,lastupdate FROM session WHERE id=?",[cookies.SESSID],function(result){
var action = require('./action');
new action({
data : result,
callback : function(){ // this callback's gonna run at the end of the request, after severals other db queries.
require('fs').rename('/session/'+cookies.SESSID,'/session/'+require('crypto').randomBytes(20));
}
}).build();
});
});
I got a feeling that my cookies.SESSID is vunerable to race condition because it will be shared between severals IO events. If my concern is feasible, how can I fix my code?
Declare the variables you want to pass to the more inner callback with var and you will stay safe. Otherwise you are just declaring them as implict global variables and each call of the function will overwrite the value you are expecting to get in the callback;
(the callback inside action could take the value of cookies not like the one you passed when you called the first time but a new value if the function is invoked before the first callback is solved)
I have just answered a similar question, with examples: https://stackoverflow.com/questions/25229739/race-condition-and-common-mistakes

what should nodeJS/commonJS module.exports return

I know that I can set module.exports to either an object or a function
(and in some cases a function that will return an object).
I am also aware of the differences and ways to use exports vs. module.exports so no need to comment on that.
I also understand that whatever is returned is cached and will be returned on any consecutive call to require. So that if I choose to return a function and not an object then possibly this implies that on every require It is necessary to actually run this function.
I was wondering is there any defacto standard on which of those two should be used. Or if there is no such standard - what considerations would apply when deciding if my module should return an object, a function or anything more complicated...
The module I intend to write is expected to be used as part of an express application if it matters (maybe there is a "local defacto standard" for express/connect modules).
If the require'd code is standalone, and does not need access to any objects from the parent code, I export an object.
edit - the above is my preferred way to do it. I do the below only when I need to pass stuff into the module, like configuration data, or my database object. I haven't found a more elegant way to give the module access to variables that are in the parents' scope.
So to pass an object from parent into module I use a function:
//parent.js
var config = { DBname:'bar' };
var child = require('./child.js')(config);
//child.js
module.exports = function(cfg){
var innerchild = {};
innerchild.blah = function(){
console.log(cfg.DBname); // this is out of scope unless you pass it in
}
return innerchild;
};
"so that if I choose to return a function and not an object then
possibly this implies that on every require It is necessary to
actually run this function."
It does not matter whether you return an individual function or an object. In neither cases a function (or functions) are ran. unless you explicitly do so.
For instance, consider the a module hello.js:
exports = function () { return 'Hello'; };
You can use require to get that function:
var hello = require('hello');
If you want to run that function, you need to invoke it explicitly as follows:
var hello = require('hello')();
You wrote you want to make sure your function is executed exactly once. Intuitively this could lead you to writing your hello.js as follows:
var hello = function () { return 'Hello'; };
exports = hello();
In which case you could just store result from hello via require:
var hello = require('hello');
However: if you do that the export system may cache your module. In such cases, you do not get fresh result from hello, but instead, a cached value. This may or may not be what you want. If you want to make sure a function is invoked every time it is required, you need to export a function and call it after require.

Resources