Testing backbone.js application with jasmine - how to test model bindings on a view?

前端 未结 6 1598
-上瘾入骨i
-上瘾入骨i 2020-12-24 02:48

I had some interesting tribulations in trying to test whether views were correctly bound to events.  In backbone, we typically bind to events in the initialize method, using

相关标签:
6条回答
  • 2020-12-24 03:22

    I solved this problem by spying on a function called by my render function. So in your example:

    myView = Backbone.View.extend({
      initialize: function(){
          _.bindAll(this, "render");
          something.bind("change", this.render);
      },
      someOtherFunction: function(){},  //this function only called from render
      render: function(){ this.someOtherFunction(); /* rest of render function */ }
    });
    

    test looks like:

    this.myView = new MyView();
    spyOn(this.myView, "someOtherFunction");
    this.myView.something.trigger("change");
    expect(this.myView.someOtherFunction).toHaveBeenCalled();  
    

    then I wrote a separate test for whatever someOtherFunction does.

    0 讨论(0)
  • 2020-12-24 03:30

    This may be too closely coupled with Backbone internals, but you can check the callback chain manually:

    expect(this.legendView.groupData._callbacks['change']).toContain(this.myView.render)
    
    0 讨论(0)
  • 2020-12-24 03:35

    I ran into the same problem and changed my Views code from:

    this.model.on('change', this.render, this);
    

    to:

    this.model.on('change', function () {
        this.render();
    }, this);
    

    And my jasmine tests worked as expected.

    0 讨论(0)
  • 2020-12-24 03:40

    Instead of spying on the callback you might try spying on something.bind. Then test that bind was called w/ the appropriate arguments. This is working for me so far. I'm using sinon.js instead of jasmine's built-in spies. sinon.js makes it a bit easier to test for args passed to a method call in a stack of same method calls (eg a bunch of calls to bind in a view init). So I haven't tested this idea w/ jasmine alone but believe it should be possible.

    spyOn(this.legendView.groupData, 'bind');
    this.myView = new MyView();
    expect(this.legendView.groupData.mostRecentCall.args).toEqual('change', this.myView.render); // example!! only works if testing a single call to bind or the last call in a series (ie mostRecentCall)
    

    And w/ sinon.js

    sinon.spy(this.legendView.groupData, 'bind');
    this.myView = new MyView();
    expect(this.legendView.groupData.bind.calledWith('change', this.myView.render); // works w/ any number of calls to bind
    
    0 讨论(0)
  • 2020-12-24 03:43

    I have managed to achieve this using prototype patching. Before you create the instance of the view, spyOn the constructor's prototype.

    spyOn(MyView.prototype, 'changeSelected');
    var view = new MyView();
    view.selectSomething();
    expect(view.changeSelected).toHaveBeenCalled();
    
    0 讨论(0)
  • 2020-12-24 03:47

    You should consider looking at Sinon.js. You could stub/mock the render() call and not even have to worry about 'someOtherFunction()'.

    0 讨论(0)
提交回复
热议问题