How do I use jasmine-ajax to verify that the send method was called?
Yes you are not calling ajax.send()
, but you are triggering the ajax.onreadystatechange
event because of this piece of code:
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"contentType": 'application/json',
"responseText": '[1, 2, 4, 3, 5]'
});
Which changes the readystate and sets the readystate to done. This is actually exactly as the documentation also states: https://jasmine.github.io/2.6/ajax.html
As for how to check if xhr.send is actually being called, this SO answer explains you can spy on it doing the following in your beforeEach:
spyOn(XMLHttpRequest.prototype, 'send');
After uncommenting the xhr.send() part in your loader you could check for method calls like this:
describe("#loadNames", function () {
it("Makes a success callback with the data when successful", function () {
Loader.loadNames("someURL", successFunction, failFunction);
jasmine.Ajax.requests.mostRecent().respondWith({
"status": 200,
"contentType": 'application/json',
"responseText": '[1, 2, 4, 3, 5]'
});
expect(XMLHttpRequest.prototype.open).toHaveBeenCalled();
});
});
How do I test a function that calls an AJAX function without firing it using jasmine?
I suggest mocking out the call rather than actually calling it. The granularity is up to you, you can either stub the ajax call, or stub the whole submit function.
Here is how you can stub the submit function:
spyOn(controller, 'submit').and.callFake(function() {
DataService.ticketNumber = somevalue;
});
Place that code prior to the actually call to the controller which caller.clickSubmit().
You can then follow up with expectations on the spy, such as:
expect(controller.submit).toHaveBeenCalled()
Or any of the other expectations related to spyOn.
Here are the jasmine docs: http://jasmine.github.io/2.0/introduction.html
Look down in the 'spies' area.
If you want to mock up the ajax call, you will have to mock a promise like this:
spyOn($, 'ajax').and.callFake(function() {
var deferred = $q.defer();
deferred.resolve(someResponse);
return deferred.promise;
});
Also, in order to get the code waiting on the promise to resolve, after the submit call has been made, you need to run a $scope.$digest() so that angular can handle the promise resolution. Then you can check your expectations on code that depended on the resolution or rejection of the promise.
Testing a function that is called from an jQuery AJAX callback with Jasmine
This all boils down to how you spy on your objects and writing code that is more testable. Let's work through a few strategies.
Strategy 1
Given your current code is not within an object, you could test that these functions are called by simply testing their implementation directly.
Instead of testing that the functions were called, you would test their implementation directly.
Example
describe("strategy 1", function () {
var ajaxSpy;
beforeEach(function () {
ajaxSpy = spyOn($, 'ajax');
ajaxCall();
});
describe("error callback", function () {
beforeEach(function() {
spyOn(window, 'alert');
var settings = ajaxSpy.calls.mostRecent().args[0];
settings.error();
});
describe("when there is an error", function() {
it("should alert an error message", function() {
expect(window.alert).toHaveBeenCalledWith('Error');
});
});
});
});
Strategy 2
While the above works, it can be cumbersome to write tests. Ideally, you want to test the invocation and implementation separately.
To do so, we can spy on these functions. Since these are in the global namespace, you can spy on them through the window
object.
Example
describe("strategy 2", function () {
var ajaxSpy;
beforeEach(function () {
ajaxSpy = spyOn($, 'ajax');
ajaxCall();
});
describe("error callback", function () {
beforeEach(function() {
spyOn(window, 'displayError');
var settings = ajaxSpy.calls.mostRecent().args[0];
settings.error();
});
describe("when there is an error", function() {
it("should alert an error message", function() {
expect(window.displayError).toHaveBeenCalled();
});
});
});
});
Strategy 3 (Recommended)
The final strategy, and what I recommend, has a similar setup to the second strategy, except we encapsulate our implementation into a custom object.
Doing so makes the code more testable by wrapping functionality in objects and avoids the global namespace (i.e. window
).
Example
describe("solution 3", function() {
var ajaxSpy;
beforeEach(function() {
ajaxSpy = spyOn($, 'ajax');
ajaxService.ajaxCall();
});
describe("error callback", function() {
beforeEach(function() {
spyOn(ajaxService, 'displayError');
var settings = ajaxSpy.calls.mostRecent().args[0];
settings.error();
});
it("should alert an error message", function() {
expect(ajaxService.displayError).toHaveBeenCalled();
});
});
});
Jasmine test values returned by Ajax during success
Try adding a callback function to your original AJAX call, then use Jasmine's asynchronous support to test it when the call has completed.
myFunction(done) {
$.ajax(){
method: "GET"
url: "/myTest"
success: function(test){
$("#htmlElem").html(test);
done();
}
};
};
it("specifying response when you need it", function(done) {
// ...
myFunction(function() {
var testVal = $("htmlElem").val();
expect(testVal).toBe('awesome response');
done();
});
});
Testing results of an initial ajax request with Jasmine 2.0
It doesn't look like you're actually running async specs. I notice your beforeEach
and it
both receive a done
callback, but neither of them call that. And if you're stubbing out ajax, then you probably don't need to be running an async spec, because the stub will
effectively make the ajax request be synchronous.
When I run the following code, everything works fine.
Spec:
describe('View', function() {
var formFieldValues = [{name: 'foo'}, {name: 'bar'}];
var view;
beforeEach(function() {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest('/form-fields').andReturn({
responseText: JSON.stringify(formFieldValues)
});
view = new View(); // makes ajax call on initialization
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
it('form fields have values', function() {
// PROBLEM IS HERE: THE FOLLOWING RUNS BEFORE VIEW'S AJAX CALL FINISHES
expect(view.$('[name="fieldName"]').children().length).toEqual(formFieldValues.length);
});
});
My dummy implementation:
Collection = Backbone.Collection.extend({
url: '/form-fields'
});
View = Backbone.View.extend({
initialize: function() {
this.collection = new Collection();
this.collection.on('reset', this.render, this);
this.collection.fetch({reset: true});
},
render: function() {
var innerEl = $('<div name="fieldName"></div>')
this.collection.each(function(item) {
innerEl.append('<span></span>');
});
this.$el.append(innerEl);
}
});
Jasmine testing ajax request after click()
Thanks to Andreas Koberle's answer I got it working.
Here is the code:
window.addEvent = ->
$("#save-search").click ->
# Do stuff like define value here...
$.ajax
type: "POST"
url: "/your/url/here"
data:
key: value
dataType: "json"
success: (msg) ->
alert "Your message here"
false
jQuery -> addEvent()
Here is the test:
setUpHTMLFixture = ->
loadFixtures "your_fixture"
describe "save_search", ->
beforeEach ->
setUpHTMLFixture()
it "should call ajax with your url", ->
addEvent()
spyOn jQuery, "ajax"
$("#save-search").click()
expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/your/url/here")
The fixture: your_fixture.html
<a id="save-search">Save Search</a>
<div class="ui-draggable">some stuff</div>
<div class="ui-draggable">some stuff</div>
Related Topics
How to Skip Over an Element in .Map()
React - Getting a Component from a Dom Element for Debugging
Jquery Function Not Binding to Newly Added Dom Elements
Where Should Ajax Request Be Made in Flux App
How to Get the Last Character of a String
How to Send a Message to a Particular Client with Socket.Io
Moment.Js Transform to Date Object
How to Scroll the Window Using Jquery $.Scrollto() Function
Setting Div Width and Height in JavaScript
How to Use Redis Publish/Subscribe with Nodejs to Notify Clients When Data Values Change
Keycode Values for Numeric Keypad
How to Filter by Object Property in Angularjs
JavaScript Es6 Cross-Browser Detection
How JavaScript Closures Are Garbage Collected
Understanding React-Redux and Mapstatetoprops()
What Does Variable Declaration with Multiple Comma Separated Values Mean (E.G. Var a = B,C,D;)
How to Make a Div Element Editable (Like a Textarea When I Click It)