I've got a fairly straightforward function which returns a jQuery .ajax() promise as such:
CLAW.controls.validateLocation = function(val, $inputEl) {
return $.ajax({
url: locationServiceUrl + 'ValidateLocation/',
data: {
'locationName': val
},
beforeSend: function() {
$inputEl.addClass('busy');
}
}).done(function(result) {
// some success clauses
}).fail(function(result) {
// some failure clauses
}).always(function() {
// some always clauses
});
}
For the most part, this new promises interface works like a dream, and eliminating callback pyramids when using jQuery's .ajax() is great. However, I cannot for the life of me figure out how to properly test these promises using Jasmine and/or Sinon:
All of Sinon's documentation assumes you're using old-school
callbacks; I don't see a single example of how to use it with
promises/deferreds
When attempting to use a Jasmine or Sinon spy to spy on $.ajax, the
spy is effectively overwriting the promise, so its done
, fail
,
and always
clauses no longer exist on the ajax function, so the promise never resolves and tosses an error instead
I'd really just love an example or two of how to test these new jQuery .ajax() promises with the aforementioned testing libs. I've scoured the 'net fairly intensely and haven't really dredged up anything on doing so. The one resource I did find mentioned using Jasmine.ajax, but I'd like to avoid that if possible, seeing as Sinon provides most of the same capabilities out-of-the-box.
It is not that complex actually. It suffices to return a promise and resolve it according to your case.
For example:
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.resolve(data_you_expect);
return d.promise();
});
for a success, or
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.reject(fail_result);
return d.promise();
});
for a failure.
For Jasmine 2.0 the syntax has changed slightly:
spyOn($, 'ajax').and.callFake(function (req) {});
the method .andCallFake() does not exist in Jasmine 2.0
something along these lines / with sinon and jQuery deferreds
ajaxStub = sinon.stub($, "ajax");
function okResponse() {
var d = $.Deferred();
d.resolve( { username: "testuser", userid: "userid", success: true } );
return d.promise();
};
function errorResponse() {
var d = $.Deferred();
d.reject({},{},"could not complete");
return d.promise();
};
ajaxStub.returns(okResponse());
ajaxStub.returns(errorResponse());
Here's a simpler approach with just javascript.
quoteSnapshots: function (symbol, streamId) {
var FakeDeferred = function () {
this.error = function (fn) {
if (symbol.toLowerCase() === 'bad-symbol') {
fn({Error: 'test'});
}
return this;
};
this.data = function (fn) {
if (symbol.toLowerCase() !== 'bad-symbol') {
fn({});
}
return this;
};
};
return new FakeDeferred();
}
The if statements inside of each callback are what I use in my test to drive a success or error execution.
The solution given by @ggozad won't work if you use things like .complete()
.
But, hooray, jasmine made a plugin to do exactly this: http://jasmine.github.io/2.0/ajax.html
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
//in your tests
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');