使用jasmine测试backbone.js查看事件

时间:2011-09-28 23:14:42

标签: backbone.js jasmine jasmine-jquery

我正在尝试为无处不在的backbone.js'todo'示例的Coffeescript实现实现视图测试(请参阅github.com/rsim/backbone_coffeescript_demo。)

上述演示的茉莉花测试工作非常顺利,除了视图事件。我希望我被困在以下一个或两个上面i)我不理解视图代码中的事件绑定,ii)我不明白如何正确设置视图代码事件的Jasmine测试。

以下是“编辑”事件的示例...

class TodoApp.TodoView extends Backbone.View
  tagName: "li"
  template: TodoApp.template '#item-template'
  events:
    "dblclick div.todo-content" : "edit"
     ...

  initialize: ->
    _.bindAll this, 'render', 'close'
    @model.bind 'change', @render
    @model.bind 'destroy', => @remove()

  render: ->
    $(@el).html @template @model.toJSON()
    @setContent()
    this

  edit: ->
    $(@el).addClass "editing"
    @input.focus()
  ...

...现在这是对双击是否获得焦点的测试:

    describe "edit state", ->
      li = null

    beforeEach ->
       setFixtures('<ul id="todo-list"></ul>')
       model = new Backbone.Model id: 1, content: todoValue, done: false
       view = new TodoApp.TodoView model: model, template: readFixtures("_item_template.html")
       $("ul#todo-list").append(view.render().el)
           li = $('ul#todo-list li:first')
       target = li.find('div.todo-content')
       expect(target).toExist()
               target.trigger('dblclick') # here's the event!

    it "input takes focus", ->
       expect(li.find('.todo-input').is(':focus')).toBe(true)

期望i)间谍和ii)焦点都得到满足。

测试我在Jasmine中应该注意的backbone.js事件代码是否有特殊性?

4 个答案:

答案 0 :(得分:2)

你正在监视视图的edit方法。这将使用间谍对象替换该方法,这意味着不会调用实际的编辑方法。因此,你@input.focus永远不会开枪。

因为您希望测试实际调用您的编辑方法,我会删除它的间谍。

旁注:不要在beforeEach中调用expect方法。如果你真的需要对它们设定期望,请为它们创建一个it块。

答案 1 :(得分:2)

我对coffescript不太好,所以我可能会遗漏一些东西,但你在哪里设置你的间谍?

为了测试事件调用,您可能需要在设置间谍后刷新视图的事件。

spyOn(view, 'edit');
view.delegateEvents();
target.trigger('dblclick');

it("should call edit when target is double clicked", function() {
  expect(view.edit).toHaveBeenCalled()
});

答案 2 :(得分:0)

我没有在coffeescript中写我的测试,但我确实有同样的问题,所以我希望你能原谅我在javadcript中回答。我最终将你的测试分解为两个不同的测试。首先,我测试了如果调用视图的编辑功能将焦点设置在输入框上。之后,我测试了双击标签时是否调用了编辑,还没有通过测试。但这是我测试编辑功能是如何工作的方式。

 describe ("A todo item view", function(){
    var my_model;
    var todo_view;

    beforeEach(function(){
       my_model = new Todo({content:"todo value", done:false});
       todo_view = new TodoView({model:my_model});

    });


   it("should set the focus on the input box when the edit function is called", function(){ 
        $('body').append( todo_view.$el ); //append the view to Specrunner.html
        todo_view.edit(); //call the view's edit function
        var focus= document.activeElement;  //finds what element on the page has focus
        expect(focus).toBe('.todo-input');  //jasmine-jquery matcher checks if focused element has the .todo-input class
});

可能导致问题的是您的模型和您的视图在beforeEach之前声明。在beforeEach中声明它们意味着它们只存在于beforeEach的范围内,并且在运行它时不再存在。

另外,setFixtures能做你认为的吗?无法在不属于DOM树的元素上设置焦点,因此我将视图的el附加到jasmine规范本身的主体上。 (我使用的是html specrunner,而不是命令行版本)这使得它成为dom树的一部分,因此允许它具有焦点,并且还使它具有焦点可测试性。

答案 3 :(得分:0)

这个问题是Backbone.View events对象正在使用event delegation。要使事件能够被称为工作,元素必须是DOM的一部分,您可以通过在$('body').append(someView.el)中执行beforeEach之类的操作来完成此操作。就个人而言,我尽量不测试Backbone是否正确设置events并手动触发点击,对于单元测试更直接调用回调处理程序直接避免DOM完全可能会减慢你的测试速度更为实用。

对于:focus是同样的问题,DOM中必须有一个元素,以便jQuery可以判断元素是否被聚焦。在这种情况下,最好将某个状态设置为组件的一部分,而不是通过查询DOM来检查状态,例如:someView.hasFocus === true。或者,您可以监视元素focus实现,并检查它是否被调用。

相关问题