Search code examples
javascriptbackbone.jsjasminebackbone-viewsjasmine-jquery

Testing results of an initial ajax request with Jasmine 2.0


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);
  });

});

Solution

  • 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);
      }
    });