So I'm unit-testing my code and I face a problem with testing an anonymous function being called inside the function that I'm unit-testing.
The reason for why I didn't make the anonymous function an instance named function, is because I need the closure of some of the variables from the unit-tested function to be used inside the anonymous function.
Example to illustrate:
function funcBeingTested(done, arg1) {
var self = this;
...
self.array.push({
"arguments": [
"x", "y", function (error, result) {
// do some stuff with arg1...
done(error, arg1);
}, "z"
]
});
...
self.run(); // Eventually will call the anonymous function above from 'self.array'
}
Now, my question is there a way to test what's going on inside that anonymous function using sinon.js ? Someway I could call it with specific arguments as part of the unit test of funcBeingTested() ?
Edit:
To clear up any misconception about what I'm trying to achieve,
I wish to be able to unit test the anonymous function it-self and cover all it's possible branches to get 100% coverage. I already know how to check if the done() callback was called, and with what args using sinon.js, the problem is how would I test the anonymous function in an isolation, and call it with specific arguments to cover all possible branches.
You can test the anonymous function by defining the done function and spying on it. You need to know if this function is called with the right arguments when the anonymous function is called.
For example:
// Define the `done` function.
var doneFunction = function (error, args) {
// do something
};
// Spy on the `done` function to register calls.
var doneSpy = sinon.spy(doneFunction);
// Test the funcBeingTested
funcBeingTested(doneFunction, someArg);
// Check that doneFunction was called
assert(doneSpy.calledWith(someArg));
You can read more about the Spy API for Sinon
Related
I am trying to understand how an anonymous function inside of a callback function is invoked.
For example:
const callbackExample = function(param, callback) {
console.log('This is an example of a callback function');
callback(param);
};
callbackExample('What', function(param) {
console.log(param);
})
My question is how does a anonymous function get invoked? If I substitute the callback to equal the anonymous function below.
Is the callback being substituted for the anonymous function.
Does the callback === function(param) { console.log(param) }
What I mean is I cannot invoke the function like this.
function() { console.log('Not') } ();
There are only three ways to declare and invoke a function.
assign a anonymous function a name: function expression
give a function a name: function declaration
Immediate Invocation function express
My theory is when not using a function express or function declaration for the callback function then Javascript parses the code and detects a anonymous function and uses iife to invoke the anonymous function.
I cannot find anything on the internet nor an api that describes what is happening behind the scenes, so I ask can somebody explain this to me.
IIFE (immeadiately invoked function expression) is just a name coined by the community for this specific construct:
(function() { /*...*/ })()
It's a function expression, that is directly followed by a function call to that function. That's it. You don't have an IIFE in your code.
My question is how does a anonymous function get invoked?
Functions get invoked using a reference to them, their name is just a debugging feature (and it's a reference to the function itself inside the functions body). Functions don't need a name:
let test = function /*irrelevant*/ () { };
let test2 = test;
test(); test2();
If you use a function declaration, the name is not only used as the function name, but also as the name of a variable that references the function:
function named() { }
is barely equal to (let's ignore "hoisting" here):
var named = function named() { }
If you invoke a function using a function expression as one of it's arguments:
function called(reference) { }
called(function irrelevant() { })
then the function expression gets evaluated, a function gets created, and a reference to it gets passed to the called function as an argument, which can then be accessed using the reference variable.
My questions here is about the way the call back function works.
const fs = require('fs');
let fileContents = 'initial value';
fs.readFile('file.txt', 'utf-8',function(error,res){
fileContents = res;
console.log(fileContents);
})
So, when the fs.readFile runs, the function(error,res) is called. But why does the fileContents receives the text inside the txt file if my parameter is empty?
I'm assuming that the readFile adds the value read to the res parameter.
Is it always like this?
Another questions is why do I get null when I erase error?
Readfile looks like something like this:
function readFile(path, cb) {
try {
// Some very complicated stuff
// All fine, call callback:
path(/*error:*/ null, /*res: */ "somedata");
} catch(error) {
path(error, /*res: */ undefined);
}
}
So what you get inside the callbacks parameter does not depend on its name, but on its position, so when you do:
readFile("/..", function(res) { /*...*/ });
res will be the error readFile passes back, and if thats null its a good thing.
Maybe take a little time to experiment with callback functions.
A callback function is just a function that you pass as a parameter to another function. In the code below I declared my function. myFunc uses another function as parameter to the function called callback. Inside my function I invoke the function and pass myName as parameter to the callback. This allows me to declare other anonymous functions as parameters which I included as examples. When myFunc is invoked it invokes the callback inside its local environment.
I can then manipulate the data that is passed to the callback and write my own code inside the anonymous function using the variable that is passed to myFuncs callback.
In your example you are using readFile which retrieves the data from the file and passes it to a callback function and/or passes an error assuming something went wrong.
function myFunc( callback){
let myName = "Joe Smo";
callback(myName);
}
/*
Now I can use my function and add another anonymous function to do whatever I want
provided I use the same parameters that are inside my function.
*/
myFunc(function(name){
console.log("What's up!"+name);
});
myFunc(function(strangeName){
console.log(strangeName+" is a strange name.");
});
I was working on a function in JavaScript and i wondered if i could call a anonymous function later on:
code
more code
(function() {
alert('Hello World!');
})();
more code
(function() {
alert('Goodbye World!');
})();
//call to the first anonymous function
//call to the first anonymous function
Is it possible to call anonymous functions?
I imagine there could be an array containing all functions?
Since functions are "first class citizens" you can assign them to variables, or put them into arrays/objects whatever just like any other var, whether they're anonymous or not.
So you'll have to assign the anonymous function to a variable (or put it into an array) in order to have some kind of means to reference it later on.
Furthermore, you don't execute it immediately, rather you execute it at a later time.
var anon1 = (function(){
alert("anon1");
}); // <-- no () so it doesn't execute now.
// code code
anon1(); // <-- execute now
// ----- or -------
var myFuncs = [];
myFuncs.push( (function(){
alert("in myFuncs");
}) ); // <-- not executing it here.
// code code
myFuncs[0](); // <-- execute now
I don't understand why some JavaScript frameworks like ember.js use an anonymous function as a function parameter value. I would understand if the function was returning something, but it is not.
Here is a sample code of the routing system of ember.js that demonstrate my question:
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
Please explain me why this code creates an anonymous function as a parameter.
It's because that function .map is an async function, and that anonymous function is what to run AFTER .map completes.
Typically async functions look like:
function async(callback) {
//async stuff, yada
callback();
}
That callback is what you pass in to run once the async operations complete
So basically this creates a way to encapsulate functionality, and run the route set up w/e they need to. I'm not 100% familiar with amber, but my guess is that they do some setup and checking/validation before initializing the routes. Because you pass in the anonymous function, they can now defer the set up you specify until everything is set and ready to go!
A function passed in as a parameter means that the function will be run at some point during (or at the end of) the outer function. Often this is used to pass in a callback function.
For example, the map method might do some stuff and then call the anonymous function when finished:
function map(function) {
// Do some stuff
function();
}
Does anyone know how to pass parameters to a callback function that you cannot alter?
So here is the code I'm trying to implement (It is a siesta testing method):
Base.js:
waitForComponentQueryVisible: function (parentNext, parameters) {
var th = this,
query = parameters.query,
scope = th,
callback = callFunct,
timeout = 10000;
//The function inside here (returnToParentTester(parentNext, parameters)) is from Base.js
callFunct = function () {
scope.returnToParentTester(parentNext);
}
this.test.waitForComponentQueryVisible(query, callback, scope, timeout);
},
The problem here is of two parts:
1. I cant get the scope just right so I can use the returnToParentTester method that is found in Base.js
2. I want to pass in parentNext into the method but cannot do that when defining it as a callback
this is the method I need to run as the callback:
Base.js:
returnToParentTester: function (parentNext, parameters) {
debugger;
if (parentNext) {
parentNext.call(undefined, parameters);
} else {
this.test.fail('--Developer Error-- undefined parentNext ' +
'variable. All the chains are going to fail');
}
},
I can't get the scope just right so I can use the returnToParentTester method that is found in Base.js
Use the call method to change the scope:
Base.returnToParentTester.call(myScope)
I want to pass in parentNext into the method but cannot do that when defining it as a callback
Use an anonymous function as a callback and pass parameters within its scope:
$("body").click(function(e){foo(e.target,bar,baz)})
then let it do the work:
function foo(myScope, next1, param1)
{
Base.returnToParentTester.call(myScope, next1, param1)
}
References
Fast JavaScript max/min
Mixins and Constructor Functions
Function.prototype.apply revisited
applyFunctionArguments - argument injection technique in JavaScript
Functional JavaScript, Part 3: .apply(), .call(), and the arguments object