I am testing a Backbone View with Jasmine 2.0. The View makes an initial ajax request on load to populate its form field with values. I want my Jasmine test (in the it
function below) to run only after those values are received.
The test currently fails because it seems the ajax request is received after the test runs, even though I am stubbing the ajax request.
How should I be writing this test?
describe('View', function() {
var formFieldValues = [/* blah */];
var view;
beforeEach(function(done) {
jasmine.Ajax.install();
jasmine.Ajax.stubRequest('/form-fields').andReturn({
responseJSON: formFieldValues
});
view = new View({el: $('<main></main>')}); // makes ajax call on initialization
$('body').append(view.el);
});
afterEach(function() {
view.remove();
jasmine.Ajax.uninstall();
});
it('form fields have values', function(done) {
// PROBLEM IS HERE: THE FOLLOWING RUNS BEFORE VIEW'S AJAX CALL FINISHES
expect(view.$('[name="fieldName"]').children().length).toEqual(formFieldValues.length);
});
});
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);
}
});