I have a simple JavaScript function that uses two delegates to (asynchronously) get one value back:
function getMyUserName() {
context.load(user);
context.executeQueryAsync(onGetMyUserNameSuccess, onGetMyUserNameFail);
}
function onGetMyUserNameSuccess() {
return user.get_title();
}
function onGetMyUserNameFail(sender, args) {
return args.get_message();
}
The "context" and "user" variables are already set and initialized, and the first delegate ("onGetMyUserNameSuccess") is getting the correct answer. The question is how I can test the "getMyUserName" function with Jasmine?. If I use "runs", I have no way to know the response from the delegates (also I don't see any way to know if the delegates are called). I tried to set spies to mock the delegates, but probably I didn't it correctly (I'm just starting with Jasmine).
Any help will be very welcome.
Thanks in advance,
Gustavo
In most of the cases when you have to work with async code, you should call the function by yourself. But not directly but in the way your code would call it. So in your case spy on context.executeQueryAsync and use spy.mostRecentCall.args to get the reference to the function and then call them.
var async = jasmin.spyOn(context, 'executeQueryAsync');
async.mostRecentCall.args[0]()
var args = {get_message: jasmine.createSpy()}
async.mostRecentCall.args[1]({}, args);
expect(args.get_message.toHaveBeenCalled());
Note that there is the sinon framework that have a bunch of methodes to automatically call callbacks
Related
I am trying to test a function in a redux container but the issue is barely about redux or react. Basically the fetchData function I am trying to test, takes two functions as parameters and calls them.
What I was hoping to do was to have two anonymous stubs and pass them to the function this way:
var firstStub = sinon.stub().withArgs(mockResponse).returns('success');
var secondStub = sinon.stub().withArgs(mockResponse).returns('success');
AccountApp.fetchData({ firstStub , secondStub });
When this happens my function fetchData complains about the firstStub and secondStub not being a function. I know they are stub objects but if that is the case what is the correct way of managing this situation.
Passing the stubs as
AccountApp.fetchData({ firstStub , secondStub });
seems to be the culprit, because this means that you actually (after ES6 desugaring) invoke this:
AccountApp.fetchData({ firstStub: firstStub, secondStub: secondStub });
and this means that your fetchData() function would need to have an implementation like this:
function(args) {
// ....
args.firstStub(params);
args.secondStub(params);
// ...
};
I seriously doubt that your production code refers to those callbacks as "stubs". So you probably want to invoke the function like this:
AccountApp.fetchData(firstStub, secondStub);
What I want looks like this:
function bindFunctions(bindFunction, callbackFunction) {
// Add binding so that I can call the callbackFunction if the bindFunction is called
}
function log(message) {
console.log(message);
}
function notifyUser() {
alert('Something');
}
bindFunctions(log, notifyUser);
log('Error'); // Now the notifyUser-functions should be called and "Something" printed to the alert-box
bindFunctions($('.element').click, function() {/* CODE */}); // Or this: but I don't know if this is even possible because this is not the event-function but the binding-function of the click-event
Important: I have no influence on the bindFunction so it's not possible to implement a trigger there.
It's an attachment of a callback on any kind of existing function. Do you know how or if this is possible?
I believe you're looking at it the wrong way. What you need is some good old dependency inversion. Whatever code needs log has to receive it from a higher-level component (e.g. the composition root of your application). You're then free to implement a straightforward wrapper that calls notifyUser and inject it instead of the actual log.
I've linked some articles taking an OO perspective, but feel free to translate to a more functional model (the approaches are equivalent). In your case, you're using closures (which are, under a certain light, "equivalent" to objects with a single anonymous method).
The way you have to do to add a callback to a function is this:
var foo = function(number, callback){
number += 2;
callback(number);
}
foo(2, function(result){
window.alert(result)
});
https://jsfiddle.net/6dpz88md/
Good luck
I have a scenario whereby I want to call done() on a beforeEach after a callback has been invoked.
I tried to do this as follows :
spyOn(scope, 'onAdmin').and.callThrough().and.callFake(function(){done()})
But I'm not sure I get the right behaviour. Essentially what I want to achieve is to be able to call done() after each callback is done doing what it does.
UPDATE: workaround solution
scope.onAdminBackup = scope.onAdmin;
spyOn(scope, 'onAdmin').and.callFake(function(admin) {
scope.onAdminBackup();
done() ;
})
I have never chained these kinds of functions together cuz in my mind they seem to do the opposite. You are saying when I call this method -onAdmin - in the scope call it as normal. Which is what the callThrough method jasmine provides for us does.
But then you are chaining along a callFake method as well so then you say but dont actually call it call this fake function instead - very conflicting.
If you want to call spy on the method onAdmin and instead of it being fired you want it to do something else - something mocked - then use the .and.callFake(fn). Also take into account like #stefan above said - dont invoke the function - callFake is simply wanting a function as a parameter it will take care of calling it itself.
This might be more along the lines of what you are looking for, if not show us some more code.
spyOn(scope, 'onAdmin')and.callFake(done)
you are calling done right-away when you write done()
try passing in done as a value:
spyOn(scope, 'onAdmin').and.callThrough().and.callFake(done)
I found a work around way to do this. Jasmine has a method called addSpyStategy where you can add a custom strategy like callThrough or callFake. It would look something like this:
jasmine.addSpyStrategy('callThroughAndThen', (spy, fn) => {
return function() {
spy.and.callThrough();
setTimeout(() => fn(...arguments), 0);
}
});
the timeout makes sure the real function finishes before executing the custom function. Then for your spy, you can do this:
const spy = spyOn(scope, 'onAdmin')
spy.and.callThroughAndThen(spy, () => {
// your custom callback
done();
});
note: make sure to put custom strategy in a beforeEach block
What's the simplest way to define multiple jQuery.Callbacks() prerequisites?
// simple pubsub example
var pubsub=(function() {
var callbacksObj={};
return function(id){
if(!id) throw 'callbacks requires an id';
return (callbacksObj[id] = callbacksObj[id] || $.Callbacks('unique memory'));
};
})();
function fn1(){
console.log('fn1');
};
function fn2(){
console.log('fn2');
};
function fn3(){
console.log('fn3');
};
// subscribing
pubsub('foo').add(fn1);
pubsub('bar').add(fn2);
pubsub('foo','bar').add(fn3); // adding a function with multiple dependencies
// publishing
pubsub('foo').fire() // should only log 'fn1';
pubsub('bar').fire() // should log both 'fn2' AND 'fn3' since both have fired
I can see wrapping each added function in another function that checks each id's fired() state, though this seems like a common enough scenario that perhaps there's a simpler way I'm missing.
I think deferred is what you're looking for:
http://api.jquery.com/category/deferred-object/
it looks like this:
$.when(some_promise).then(some_callback)
And you can have:
$.when(some_promise, another_promise).then(some_callback)
In this case some_callback will only be called if some_promise and another_promise have been resolved.
deferred basically just adds a level of abstraction to your asynchronous functions, making it easier to express the dependencies. I suppose your example would look like:
// simple pubsub example
var pubsub=(function() {
var callbacksObj={};
return function(id){
if(!id) throw 'callbacks requires an id';
return some_assynchrnous_function(id); // like $.ajax
};
})();
function fn1(){
console.log('fn1');
};
function fn2(){
console.log('fn2');
};
function fn3(){
console.log('fn3');
};
// subscribing
var foo = pubusb('foo'); // should return a deferred/promise
var bar = pubsub('bar');
$.when(foo).then(fn1);
$.when(bar).then(fn2);
$.when(foo, bar).then(fn3);
I'm not entirely sure if this is correct for jQuery, but you get the idea. I didn't find the jQuery API to make very much sense to me so I wrote my own :3
I find it useful to be able to make 'empty' deferred objects, then attaching a done handler to it, then passing the deferred object along to something that will eventually end up resolving it. I'm not sure if jQuery can do this.
It may seem a little daunting at first, but if you can wrap your head around it you can get so much awesomeness from this. Dependencies is a big one but scoping is also great, you can add multiple done handlers on multiple levels, one handler may handle the actual data, one handler may just be interested in when the handler finishes so you can show a loading bar etc.
I am working with a user control that has set of javascript functions that are called when an action is performed. This user control is used in a lot of places in the application.
When one of the inbuilt JS function completes execution, I need to fire a custom JS function on my page.
Is there a way for me to attach a function to be fired when another function completes execution? I don't want to update the inbuilt JS function to call this page JS function.
Hope this makes sense.
There are a couple design patterns you could use for this depending upon the specific code (which you have not shared) and what you can and cannot change:
Option 1: Add a callback to some existing code:
function mainFunction(callbackWhenDone) {
// do other stuff here
callbackWhenDone();
}
So, you can call this with:
mainFunction(myFunction);
Option 2: Wrap previous function:
obj.oldMethod = obj.mainFunction;
obj.mainFunction = function() {
this.oldMethod.apply(this, arguments);
// call your stuff here after executing the old method
myFunction();
}
So, now anytime someone does:
obj.mainFunction();
it will call the original method and then call your function.
You're basically trying to do callbacks. Since you're not mentioning what functions you're talking about (as in code), the best thing to do would be basically to wrap the function, -quick and dirty- and make it work with callbacks.
That way you can pass it a Lambda (Anonymous Function) and execute anything you want when it's done.
Updated to demonstrate how to add Callbacks:
function my_function($a, $callback) {
alert($a);
$callback();
}
my_function('argument', function() {
alert('Completed');
});
The ugliest and best solution is to monkey-patch the built-in function. Assume the built-in function is called "thirdParty":
// first, store a ref to the original
var copyOfThirdParty = thirdParty;
// then, redefine it
var thirdParty = function() {
// call the original first (passing any necessary args on through)
copyOfThirdParty.apply(this, arguments);
// then do whatever you want when it's done;
// custom code goes here
customFunction();
};
We've essentially created a modified version of the built-in function without ever touching the original version.
Since Javascript is highly dynamic you can modify the original function without modifying its source code:
function connect_after(before, after){
return function(){
before.apply(this, arguments);
after();
};
}
var original_function = function(){ console.log(1); }
original_function = connect_after(original_function, function(){ console.log(2); })