Leahcim
Leahcim

Reputation: 41949

how to test a view that calls fetch on a collection in its constructor?

I have a BackboneView which I pass a collection upon creation

  var my_collection = new Collection();
  new MyView({temp: template, collection: my_collection });

Inside the view, the fetch() method is called on the collection in the constructor like this

export class MyView extends Backbone.View {

    constructor(options){

      this.collection = options.collection;
      super();
      this.collection.fetch().done(function(resp){
      that.render();
      })
    }
    render(){
    }

}

I had (past tense) a series of tests that tested the UI/template of the View like this

  describe('testing my view', function() {
    it('should have one main child - div 6 ', function() {
      expect(myview.el.children.length).to.equal(1);
    });
  });

However, since I have now added code that passed the collection to the view, and called the fetch method on the collection in the constructor, all of my tests fail because the view tries to call the fetch method every time I run the tests. Even if I pass a stub collection, I have to set a urland the view will try to fetch on the stub collection resulting in a 404

 var gs = class StubCollection extends Backbone.Collection{

   constructor(options){
    this.url = '/blah';
   }
 }

  const drv =   new MyView({temp: template, collection: new gs()});

I need to call fetch on the collection in the view (i.e. I can't not use that code). How can I continue to test the view in this situation?

Upvotes: 0

Views: 423

Answers (2)

Creynders
Creynders

Reputation: 4583

Not the easiest solution, but in the long term definitely the best: You shouldn't call fetch on a collection from a view.

A view really has no business telling a collection or model what to do. A view only presents data and/or captures user input. The call for loading said data should be someplace else. Depending on what paradigm you like to follow this could be in a controller or command. It will make testing a lot easier, since your views will be more system agnostic, i.e. they have less knowledge of what's happening when. Views, models, collections and services should always be as dumb as possible: it's easier to test, reuse, extend and modify. All application-specific code should go into your controllers and commands. I.e. they are the glue that combine your application agnostic views, models and services into the specific application your working on.

Upvotes: 2

Spike
Spike

Reputation: 741

You can stub the fetch method itself. Inside StubCollection define it as:

function fetch() {
    return $.Deferred().resolve().promise();
}

According to the Backbone's documentation, fetch returns a jqXHR which represents the request that is sent.

jqXHR is a Promise, which is an object that represents an ongoing process that may either succeed or fail, and has methods called done and fail for registering callbacks to be called when it succeeds or fails, respectively. (jqXHR succeeds if the request is successful and fails it could not be sent or the server returned an error code).

In the above code, we manually create a Deferred object (used to create promises), and immediately change its state to successful (with resolve). Then we return its promise. Because the promise is immediately considered successful, the done callback will be called immediately.

Upvotes: 3

Related Questions