Jasmine use it to over ride and test a method that uses aiax - ajax

I have a JS file that contains many methods, ajax caller is constant.
function ajaxCaller(data,url,callback) { //standard jquery ajax call here }
function method1(){
// ... does work ... then
ajaxCaller(data,url,function(){ // changes the dom } );
}
How can I use jasmine to over ride the ajaxCaller method that is being called by nearly every method in my js file such that I can test that the DOM is getting changed?

Probably you have something like the code below, right?
function ajaxCaller(data, url, callback) {
$.ajax(url, { data: data, success: callback });
}
In this case you can mock the jQuery ajax method so that instead of real AJAX request the function you provide will be called. It is possible to define the response you want to be "returned from the server". Jasmine andCallFake function will do it for you:
it ('when some response returned from the server, something happens', function() {
var response = {}; // ... define the response you need
spyOn($, 'ajax').andCallFake(function(url, options) {
options.success(response);
});
method1();
// and assert that something really happens ...
});

Related

How to avoid loop in Ajax call

I have function getData() which make an ajax call and retrive JSON data. On success i call another function which is marquee() . inside marquee on finish event i call getData() again, But each time getData() when get called, it increases it's request to mentioned file data.php, For example on first call it call once, Second call it request twice, and then twice become 4times,8times and more and more, how to avoid this?!
function getData()
{
$.get('data.php).done(function(response)
{
var data = JSON.parse(response);
if(data.Direction == "left")
{
$(".marquee").html("<span data-direction='"+data.Direction+"'>"+data.Message+"</span>");
}else if(data.Direction == "right"){
$(".marquee").html("<span data- direction='"+data.Direction+"'>"+data.Message+"</span>");
}
});
}
function marquee()
{
$(".marquee").marquee({duration : 10000}).bind("finished",function()
{
getData();
});
}
I hope i was clear... Appreciate each answer.
Every time you are calling marquee function, you are basically binding an event finished on to it. On multiple such function calls, you will have duplicate events. In your code setup, you need to unbind the function before binding it. Something like
$(".marquee").marquee({duration : 10000}).unbind("finished",getData).bind("finished",getData)
Ideally, you should bind only once so you do not have to unbind it again and again.

AJAX + jQuery Deferred: execution sequence

Task: get data from server with $.post, process them by method .success(), after that call some function.
var t;
$.when($.post("get_json.php", function(res) {
t = res;
}, 'json')).done(function() {
console.log(t);
});
Do I understand correctly that the Deferred method .done() is executed after .success is done (ie t = res)?
But why "console.log(t)" shows "undefined"?
Is .done() fires after request, but before .success()?
Passing a "success" callback to $.post() is an alternative to the (preferred) chaining of .done(...). Do one or the other, not both, then you don't need to worry about the execution order.
Also, unless you have a decent caching strategy for async data, you shouldn't be setting t as an outer var.
$.post("get_json.php", ...).done(function(t) {
console.log(t);
//do awesome things with t here
});
Caching would be something like this :
var asyncCache = {};
...
function get_t() {
return (asyncCache.t) ? $.when(asyncCache.t) : $.post("get_json.php", ...).done(function(t) {
asyncCache.t = t;
});
}
...
get_t().done(function(t) {
console.log(t);
//do awesome things with t here
}
$.when() is ONLY needed when you have multiple promises and you want to wait for all of them to complete. You simply don't need it at all for your single ajax call. You can just do it like this:
$.post("get_json.php").done(function(t) {
// use the results of the ajax call here
console.log(t);
});
In addition, your code example was using BOTH a success callback function AND a .done() handler. Pick one of the other, not both as they are different ways of getting a callback when the ajax call is done. I'd suggest the promise implementation above because it's more flexible. But, you could also use just the success handler:
$.post("get_json.php", function(t) {
// use the results of the ajax call here
console.log(t);
}, 'json');
Note, when you have an asynchronous operation like this, you need to consume the results of the ajax call in the success callback (or the promise callback) or call some function from there and pass it the data. You do not want to put the data into a global variable or a variable in a higher scope because other code will simply have no way of knowing when the data is ready and when it is not. Put your action in the callback.
If you have more than one ajax call that you want to wait for, then you can do it like this:
$.when($.post("get_json.php"), $.post("get_json2.php")).done(function(r1, r2) {
// use the results of the ajax call here
console.log(r1[0]); // results from first ajax call
console.log(r2[0]); // results from second ajax call
});

Create wrapper function around ajax calls

I want to create a wrapper around my API calls in AngularJS like
function MakeCall (url){
$http.get(url, config).success(successfunction);
return response;
}
Can you help me how to wait for the call to complete and get the final response from the call. In above code the "return response" is what I want to get after the completion of call. This function will be used like
response = MakeCall("to some url");
response = MakeCall("to some url");
That's not how promises work. You cannot synchronously return the result of an ajax call.
You just seem to want to return the promise that $http.get() already yields from your function:
function MakeCall (url){
return $http.get(url, config).success(successfunction);
}
Then use it like this:
MakeCall("to some url").then(function(response) {
…
});

Jasmine test event with asynchronous call

The issue is to test the event handlers with asynchronous internal methods, which is executed by SDK like facebook.
the plain test is:
describe('Listens to someevent', function () {
it('and triggers anotherevent', function () {
var eventSpy = spyOnEvent(document, 'anotherevent');
var data = {
param1: 'param1',
param2: 'param2',
}
this.component.trigger('somevent', data);
runs(function() {
expect(eventSpy).toHaveBeenTriggeredOn(document);
});
});
});
when someevent is triggered with options, the component handler is fired:
this.handler = function (e, data) {
SDK.apicall(data, function (err, response) {
if (!err) {
doSomething();
}
// trigger data event
that.trigger(document, 'anotherevent');
});
}
;
};
In jasmine 1.3 and before, a runs without a preceding waitsFor still executes immediately. It's really the waitsFor that makes the spec asynchronous. This has changed in 2.0.
Alternatively, if you don't really want to call the external API during your tests. You can use something like jasmine-ajax (docs). This will allow you to return the ajax call immediately in test with whatever response you want to test with. This has the advantage of making your specs faster (there's no waiting for the API), and make your specs less dependent on the API being up when they run.

How can I handle async calls when validating with Backbone.js (uniqueness specifically)

This is relevant for either client or server side apps using backbone. I am attempting to create a validation function with uniqueness checks to MongoDB or some REST call (depending on environment). Both of these calls are async by nature; however, I think I actually need to make it block here for validation purposes. If I don't return anything the validate function will assume validation passed.
My code currently looks like this on the server side:
isUnique: function (key) {
var dfdFindOne = this.findOne({key: this.get(key)}),
dfd = new Deferred();
dfdFindOne.done(function (err, result) {
console.log(result);
dfd.resolve(true);
});
return dfd;
};
... some stuff here....
I feel like I can do some sort of wait till done functionality here before I return... perhaps not though. I wish backbone provided a callback function or something or accepted some sort of deferred type thing.
validate: function() {
var result = undefined;
if(!this.isUnique(key).done(function(){
result = "AHHH not unique!";
});
return result;
}
A possible solution might be to force mongodb's native node client to call things synchronously. I think I can do the same with rest calls... This is probably a bad solution though.
You could call the ajax request and set async:false in this way the return will have value. However to use async:false is evil because could appear as the browser is locked. For server side maybe there are not always workarounds for set async: false
My recommendation is to use your own validation flow instead of Backbone.validate flow, because the validation flow of Backbone was made thinking for synchronous validations only. You could try something like this:
//Code in your Model
isUnique: function (callback) {
var dfdFindOne = this.findOne({key: this.get(key)});
dfdFindOne.done(function (err, result) {
console.log(result);
callback(result);
});
};
validate: function(callback) {
this.isUnique(callback);
}
//trying to validate before save
model.validate(function(result){
if( result == 'whatexpected'){
model.save();
}
});

Resources