I am new to mocha/chai unit testing. I have following ajax call which is making a service call. I have added .fail() and .done() as a part of ajax call.
So I am not sure what I am missing here. Sorry if I am missing basic things here. Can someone please describe what's wrong here?
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
$.ajax({
type: method,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: endPointurl,
headers: search_headers,
xhrFields: {
withCredentials: true
},
success: function success(results, xhr, XMLHttpRequest) {
successCallback();
},
error: function (xhr, textStatus, error) {
callErrorFunc();
}
}).fail(function (xhr, textStatus, errorThrown) {
callFailFunc();
}).done(function () {
callDoneFunction();
});
}
I have written following unit test:
describe.only('Testing searchdoctorAPIcall function', function () {
var testurl = 'https://abc.serve.org/getData';
beforeEach(function() {
sinon.stub($, 'ajax');
});
afterEach(function() {
$.ajax.restore();
});
it('should make an ajax call', function(done) {
searchAPIcall(testurl, "GET", {"Content-Type":"application-json;charset=utf-8",X-Id":"1da9b0c8-bb52"}, "baseSearch");
expect($.ajax.calledOnce).to.be.true;
done();
});
});
I am always getting the following error while executing unit test.
undefined is not an object (near '...} }).fail(function (xhr,...')
But When I change my searchAPIcall function and remove the .dail() and .done() unit test is passing.
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
$.ajax({
type: method,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: endPointurl,
headers: search_headers,
xhrFields: {
withCredentials: true
},
success: function success(results, xhr, XMLHttpRequest) {
successCallback();
},
error: function (xhr, textStatus, error) {
callErrorFunc();
}
})
}
Now if I run the unit test then it is passing.
should make an ajax call (passed)
You need to weave the test done call into your code so that it is run after the async call and your tests finish:
function searchAPIcall(endPointurl, method, search_headers, search_identifier) {
return $.ajax({ // return the call so it can be chained
...
});
}
it('should make an ajax call', function(done) {
searchAPIcall(
testurl,
"GET",
{"Content-Type":"application-json;charset=utf-8","X-Id":"1da9b0c8-bb52"}, // Note: you are missing a " before the 'X' in this line
"baseSearch"
).done(() => {
expect($.ajax.calledOnce).to.be.true;
done();
}).fail(done); // Equivalent to: .fail(error => done(error))
});
Related
I am trying to make an http request like:
function foo() {
$.ajax({
async: true,
crossDomain: true,
url: "https://192.168.xxx.xxx/api/Domains/GetDomains/false",
type: "GET",
contentType: false,
success: function (data, textStatus, jqXHR) {
console.log(data);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR.responseText);
}
});
}
$(document).ready(function () {
foo();
});
But Im getting error:
I tried with postman and it worked, why Im getting this error when I try via code?
This question already has answers here:
jQuery - Execute 2 functions synchronously
(2 answers)
Closed 5 years ago.
In my asp.net mvc app, I have button click that points to a javascript which calls
function OnButtonClick(s, e, startUrl, progressUrl) {
Fetch(progressUrl);
ImportUpdate(startUrl);
}
Fetch and ImportUpdate are ajax jquery to a controller action.
function Fetch(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
$.ajax({
type: 'POST',
url: "#Url.Action("BloombergFet", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpBloomberg.Show(); },
success: function (msg) {
ImportSuccessMessage.SetText(msg);
lpBloomberg.Hide();
lpImport.Show();
},
error: function (xhr, textStatus, errorThrown) {
lpBloomberg.Hide()
}
});
}
function ImportUpdate(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
myProgressBar.Show;
$.ajax({
type: 'POST',
url: "#Url.Action("ProcessImportRecord", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpImport.Show(); },
success: function (msg) {
ImportDataGridView.PerformCallback();
ImportSuccessMessage.SetVisible(true);
ImportSuccessMessage.SetText(msg);
lpImport.Hide();
},
error: function (xhr, textStatus, errorThrown) {
ImportErrorMessage.SetVisible(true);
ImportErrorMessage.SetText(xhr.statusText)
}
});
}
Currently both the methods Fetch(progressUrl) and ImportUpdate(progressUrl) are called at the same time. I want Fetch(progressUrl) to complete and then ImportUpdate to run.
How do I achieve this. Appreciate all help.
Call your second function ImportUpdate(progressUrl) in the success block of the first function Fetch(progressUrl) like so:
function Fetch(progressUrl) {
positionDate = ReportingPositionDate.GetDate().toDateString();
$.ajax({
type: 'POST',
url: "#Url.Action("BloombergFet", "ImportData")",
data: JSON.stringify({ positionDate: positionDate }),
dataType: "text",
contentType: "application/json; charset=utf-8",
beforeSend: function () { lpBloomberg.Show(); },
success: function (msg) {
ImportSuccessMessage.SetText(msg);
lpBloomberg.Hide();
lpImport.Show();
//Place call for ImportUpdate function here, like so
ImportUpdate(startUrl);
},
error: function (xhr, textStatus, errorThrown) {
lpBloomberg.Hide()
}
});
}
However, like James pointed out, if you want to call ImportUpdate after every time that Fetch is called, it makes more sense to just combine them UNLESS you call ImportUpdate independently somewhere else, when Fetch is not called first.
BTW, the callbacks Kevin B. is probably referring to are used with the jQuery .post() function, which you can use like this:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
// Perform other work here ...
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second finished" );
});
so instead of putting your function call in the success callback of your current Fetch function you'd put it in .done callback like so:
.done(function() {
ImportUpdate(startUrl);
})
.fail(function() {
//handle errors
})
Put ImportUpdate(progressUrl) inside your success callback function for Fetch(progressUrl)
I'm using ajax successives requests and I need do a callback when all the successives requests are done
function doAjaxRequest(data, id) {
// Get payment Token
return $.ajax({
type: "POST",
url: 'exemple1.php',
data: data
success: function(msg){
$.ajax({
type: "POST",
url: 'exemple2.php',
data: msg,
success: function(msgr) {
document.getElementById(id).value=msgr;
},
error:function (xhr, status, error) {
//Do something
}
});
},
error:function (xhr, status, error) {
//Do something
}
});
}
$.when(
doAjaxRequest(data, "input-1"),
doAjaxRequest(otherData, "input-2")
).done(function(a1, a2){
//Need do something when both second ajax requests (example2.php) are finished
}
With this code, the done function is call before my calls to "exemple2.php" are succeeded.
How can I wait for that?
Thanks for answering!
function doAjaxRequest(data, id) {
// Get payment Token
return new Promise(function(resolve,reject){
$.ajax({
type: "POST",
url: 'exemple1.php',
data: data
success: function(msg){
$.ajax({
type: "POST",
url: 'exemple2.php',
data: msg,
success: function(msgr) {
document.getElementById(id).value=msgr;
resolve();
},
error:function (xhr, status, error) {
//Do something
reject();
}
});
},
error:function (xhr, status, error) {
//Do something
reject();
}
});
});
}
Promise.all([
doAjaxRequest(data, "input-1"),
doAjaxRequest(otherData, "input-2")])
.then(function(values){
//Need do something when both second ajax requests (example2.php) are finished
}
Your sub ajax request is independant of the first ajax result, then the call to example2 is completely separated from the $.when() promise.abort
Just try to use the fact that jquery $.ajax return promise like object
Here my code from plnkr
// Code goes here
function doAjaxRequest(data, id) {
// Get payment Token
return $.ajax({
type: "GET",
url: 'example1.json',
data: data
}).then(function(msg, status, jqXhr) {
return $.ajax({
type: "GET",
url: 'example2.json',
data: msg
});
}).done(function(msgr) {
console.log(msgr);
return msgr;
});
}
var data = {foo:'bar'};
var otherData = {foo2:'bar2'};
$.when(
doAjaxRequest(data, "input-1"),
doAjaxRequest(otherData, "input-2")
).done(function(a1, a2) {
console.log(a1, a2);
//Need do something when both second ajax requests (example2.php) are finished
});
Attention, I replace POST by GET and use exampleX.json files for my tests on plnkr
You can test it here : https://plnkr.co/edit/5TcPMUhWJqFkxbZNCboz
Return a custom deferred object, e.g:
function doAjaxRequest(data, id) {
var d = new $.Deferred();
// Get payment Token
$.ajax({
type: "POST",
url: 'exemple1.php',
data: data
success: function(msg){
$.ajax({
type: "POST",
url: 'exemple2.php',
data: msg,
success: function(msgr) {
document.getElementById(id).value=msgr;
d.resolveWith(null, [msgr]); // or maybe d.resolveWith(null, [msg]);
},
error:function (xhr, status, error) {
//Do something
d.reject();
}
});
},
error:function (xhr, status, error) {
//Do something
d.reject();
}
});
return d;
}
Now, i'm not sure what is your expected datas passed to $.when().done() callback.
I'm having trouble getting the error callback getting called when I pass the error function as an object parameter in a function. However, when I declare it within the ajax code it works.
var ajaxSettings = new Object();
ajaxSettings.error = function(request, status, error){ console.log('bad failure');};
ajaxSettings.success = function(result) { console.log('good success');};
uploadFile(contents, ajaxSettings)
function uploadFile(contents, settings) {
$.ajax({
url: uri,
type: "PUT",
data: contents,
processData: false,
dataType: "json",
success: settings.success,
error: settings.error
});
}
In this case the error callback doesn't get fired. However if I write the error function declaration in the ajax code it works.
function uploadFile (contents, settings) {
$.ajax({
url: uri,
type: "PUT",
data: contents,
processData: false,
dataType: "json",
success: settings.success,
error: function(request, status, error) { console.log('bad failure'); },
});
}
I also tried making success: settings.error and it will call that function when it succeeds. What is the reason the error callback is not getting called?
I created a fiddle using your code check it Fiddle
You should initialize the ajaxSettings before use it
Try to declare your callbacks like below:
var ajaxSettings = {}
ajaxSettings.error = function(request, status, error){ console.log('bad failure');};
ajaxSettings.success = function(result) { console.log('good success');};
... because they are probably not visible in "uploadFile" function scope.
I want to do a chain of $.when().then($when().then(...)) in jquery. I'm not used to the defered functions, first time using them.
I changed my code a bit my code to represent this situation:
function setenum(e)
{
return $.ajax({
url: SetPathUrl1(),
type: 'GET',
data: { isNew: e.isNew() },
contentType: 'application/json; charset=utf-8',
success: function (data, status, xhr) {
/*My stuff*/
},
error: function (xhr, status, error) {
/*My stuff*/
}
});
}
function setdropdown1(e)
{
return $.ajax({
url: SetPathUrl2(),
type: 'GET',
data: { isNew: e.isNew() },
contentType: 'application/json; charset=utf-8',
success: function (data, status, xhr) {
/*Fill my first ddl based on enum*/
},
error: function (xhr, status, error) {
/*My stuff*/
}
});
}
function setdropdown2(e)
{
return $.ajax({
url: SetPathUrl3(),
type: 'GET',
contentType: 'application/json; charset=utf-8',
success: function (data, status, xhr) {
/*Fill my second ddl based on enum*/
},
error: function (xhr, status, error) {
/*My stuff*/
}
});
}
function DoOtherStuff(e)
{
/**/
}
function MainNotWorking(ImportantModel)
{
$.when(setenum(ImportantModel))
.then(
$.when(setdropdown1(ImportantModel),setdropdown2(ImportantModel))
.then(
function () {
DoOtherStuff(e);
}
)
);
}
function MainWorking(ImportantModel)
{
$.when(setenum(ImportantModel),setdropdown1(ImportantModel),setdropdown2(ImportantModel))
.then(
function () {
DoOtherStuff(e);
}
);
}
MainNotWorking : the order is not respected at all, set setdropdown1 and setdropdown2 are called sometimes before the setenum.
MainWorking:
When I have only one level of when, then the function DoOtherStuff is called before all other functions, but it's only one level. I want to do multiple chain setenum before setdropdown1 and setdropdown2 and then finally DoOtherStuff.
Use $.when().done(callback)
function MainNotWorking(ImportantModel) {
$.when(
setenum(ImportantModel)
).done(function() {
$.when(
setdropdown1(ImportantModel),
setdropdown2(ImportantModel)
).done(DoOtherStuff);
});
}
First, you should pass a function reference to then:
.then(function() { ... })
What you are passing is executed immediately, instead of when the first function is finished.
That alone would be enough, but if you wanted to "flatten" out the chaining, you could do something like this:
$.when(
setenum(ImportantModel)
).then(function() {
return $.when(
setdropdown1(ImportantModel),
setdropdown2(ImportantModel)
)
}).then(function() {
DoOtherStuff();
});
Here's a demo: http://jsfiddle.net/44e5Y/