How to spy jQuery AJAX request? - javascript

The following two ways of implementing an ajaxRequest (1) (2) should be equivalent.
Having said that:
Why does the unit test (3) that verifies the callback was executed, succeeds in (1) and fails in (2)?
How should I rewrite the test (3) to spy on the success callback in (2)?
If I try to stub jQuery.ajax using sinon and the code (2) I get an error. How should I fix it?
Please, see the comments in code (3) for more details.
(1)
ajaxRequest: function (message, callback) {
return $.ajax({
url: backendRouter.generate('feedback_send'),
type: 'POST',
dataType: 'json',
data: {
message: message
},
success: callback
});
}
(2)
ajaxRequest: function (message, callback) {
return $.ajax({
url: backendRouter.generate('feedback_send'),
type: 'POST',
dataType: 'json',
data: {
message: message
}
}).success(callback);
}
(3)
it("should execute the callback function on success", function () {
spyOn($, "ajax").andCallFake(function(options) {
options.success();
}); // If I use the code (2) I get the following error
// TypeError: Object #<Object> has no method 'success'
var callback = jasmine.createSpy();
ajaxRequest('some message', callback);
expect(callback).toHaveBeenCalled();
});
(4)
it("makes a GET request for todo items", function () {
sinon.stub(jQuery, 'ajax');
backendController.ajaxRequest('some message', sinon.spy());
// Cannot call method 'success' of undefined
});

Here's a walkthrough:
If you use the code in number 2, you are invoking the ajax function on jquery:
return $.ajax({
url: backendRouter.generate('feedback_send'),
type: 'POST',
dataType: 'json',
data: {
message: message
}
...
after calling this function with those parameters, jQuery returns a jqHR that happens to have a success function defined. That success function is then invoked:
...
}).success(callback);
All is well so far until your jasmine test spies on the ajax function. The same options you used to invoke $.ajax are passed to this new spy.
// this is the value of the options parameter
{
url: backendRouter.generate('feedback_send'),
type: 'POST',
dataType: 'json',
data: {
message: message
}
}
When this object is passed, your fake function actually attempts to call options.success, which does not exist! Hence the error.

There is a jquery plugin that uses sinonjs with qunit and provides a much easier way to write ajax tests and get expected results.
Take a look at jqueryspy

Related

Promise and callback function in ajax, when does success take place ?

Right now I have a code like this:
$.ajax({
url: apiUrl + valueToCheck,
data: {
format: 'json'
},
error: function () {
},
dataType: 'json',
success: function (data) {
checkAgainstDBHelperWH(data, valueToCheck);
},
type: 'GET'
});
If I am not mistaken, checkAgainstDBHelperWH is known as a callback function. The function executes once the servers sends back response for this particular HTTP /ajax request.
I want to try writing something like the one below, but I don't know what are the effects or is it even logical:
var request = $.ajax({
url: apiUrl + valueToCheck,
data: {
format: 'json'
},
error: function () {
},
dataType: 'json',
success: function (data) {
checkAgainstDBHelperWH(data, valueToCheck);
},
type: 'GET'
})
arrayOfPromises.push(request);
$.when.apply(null, arrayOfPromises).done(function () {
//...some javascript here
});
I want to understand if the .done(function () is fired after the callback function checkAgainstDBHelperWH is completed? Or whatever I am trying to write above does not flow consistently with how ajax works?
Thanks!
I tested it, your code only work if the function(in this case, 'checkAgainstDBHelperWH') doesn't call ajax.
If you want to wait finishing the inner ajax process, use then() and return inner ajax.
var ajaxs =
$.get("xxx").then(function() {
return $.get("yyy").done(function() {
});
});
Here is the jsfiddle.
I'm not sure whether this way is general or not.

Jquery AJAX callback not executing on success [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm sending a request to the server to check a user_id and session_id pair, to make sure that it's valid. This function gets the session data associated with the session_id, and then if the user_id from the session data matches the one passed to the function as an argument, it should execute the callback. Unfortunately, the callback doesn't execute for some reason.
If I type into the console "session_is_valid(2, 1, function() { alert('hi'); });", I can see "success" logged in the console, but no alert. Likewise, if I use an invalid pair, I correctly am notified with a "failure" message. But the callback never executes.
Is this some problem with how I'm using the console in my browser? Or is there a problem with my function?
//Confirm a session id / user id pair
function session_is_valid(session_id, user_id, callback) {
var data = {'id': session_id};
return $.ajax({
type: "POST",
url: ears_path + "?q=session",
data: JSON.stringify(data),
contentType: 'application/json; charset=UTF-8',
dataType: 'json',
success: function (result) {
if(result.user_id === user_id) {
console.log('success');
callback
}
else { console.log('failure'); }
}
});
}
There are some comments where you can see the same answer. In my opinion, you will need to make callback() instead of callback to call the function, if you just execute callback you are retrieving and fn object (function object), but you won't execute it. You can check the solution openning the browser console, and writting callback and callback(), if you hace the function in the global scope or if you are debugging the script.
This is how I perform mine, modify to suit your needs.
function run_some_ajax() {
ajax_call(function(result) { //by populating result here, you can reference the data returned from your ajax call
//success callback logic here
console.log(result);
});
}
function ajax_call(callback) {
$.ajax({
type: "POST",
url: ears_path + "?q=session",
data: JSON.stringify(data),
contentType: 'application/json; charset=UTF-8',
dataType: 'json',
success: function (result) {
if(result.user_id === user_id) {
console.log('success');
if(typeof callback === "function") { //always check to see if callback is in fact a function
callback(result); //place results into your callback function to reference later
}
} else {
console.log('failure');
}
}
});
}

What's a non-deprecated way of doing a synchronous ajax call using jQuery?

I've got a small javascript function that's only purpose is to call a script to get some data from the database so it can be used by other functions on the client side.
I'm using a jQuery call to get the data but for me to pass the object out of the success functions scope I need to turn asynchronous off which raises a deprecation warning.
My function works as intended currently but I'd like to use a method that isn't deprecated. Here is my function:
function getData(ID) {
var Data = {};
$.ajax({
url: 'script',
method: 'POST',
dataType: 'json',
async: false,
data: {action: 'get', id: ID },
success: function(response) {
Data = response;
})
});
return Data;
}
I've changed the variable names for privacy reasons so apologies if they're vague.
Also why is synchronous calls considered harmful to the end users experience?
As AJAX call is asynchronous, you will always get blank object ({}) in response.
There are 2 approach.
You can do async:false
To get response returned in AJAX call try like below code. Which wait for response from server.
function getData(ID) {
return $.ajax({
url: 'script',
method: 'POST',
dataType: 'json',
//async: true, //default async call
data: {action: 'get', id: ID },
success: function(response) {
//Data = response;
})
});
}
$.when(getData(YOUR_ID)).done(function(response){
//access response data here
});

jquery unable to access function parameter inside function with an ajax call?

hitUrl = function (searchUrl, nbCity) {
$.ajax({
context: this,
type: 'GET',
headers: { "sourceid": "1" },
url: '/webapi/xyz/abc/?' + searchUrl,
dataType: 'text',
success: function (json) {
D_usedSearch.similarCars.showSimilarCarLink(searchUrl);
});
When i put breakpoint on 1st line of success of this jquery success callback, i am unable to access 'searchUrl' in console. It is undefined.
How do i access this?
That's probably because Ajax is asynchronous: the code from the function is executed parallel from the code in the ajax call.
Take a look to this answer for the solution to your problem.

Calling a Success script if #Ajax call succeed

I have the following javascript which contains an ajax call:-
$.ajax({
type: "POST",
url: '#Url.Action("DeleteSelected"),
data: { ids: boxData.join(",") }
})
});
but is there a way to call a javaScript function is the above Ajax call succeed?
Thanks
function mySuccessFunction() {
alert('success');
}
$.ajax({
type: "POST",
url: '#Url.Action("DeleteSelected")',
data: {
ids: boxData.join(",")
},
success: function(data) {
// your code if AJAX call finished successfully
// call your function that already loaded from here:
mySuccessFunction();
// you can also process returned data here
}
});
You have three particular handlers you can use to process information returned with AJAX, .success(), .done(), and .fail(). With these methods, your code might look something like this:
$.ajax({
type: "POST",
url: '#Url.Action("DeleteSelected"),
data: { ids: boxData.join(",") }
}).success(function(data) {
// This callback is executed ONLY on successful AJAX call.
var returnedJSON = data; // The information returned by the server
yourSuccessFunction();
}).done(function() {
// This callback is ALWAYS executed once the AJAX is complete
yourDoneFunction();
}).fail(function() {
// This callback is executed ONLY on failed AJAX call.
});
Also see: jQuery AJAX Documentation

Categories

Resources