8

我正在尝试为无处不在的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

4 回答 4

2

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

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

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

于 2011-09-29T01:35:26.800 回答
2

我对咖啡脚本不是很好,所以我可能会遗漏一些东西,但是你在哪里设置你的间谍?

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

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

it("should call edit when target is double clicked", function() {
  expect(view.edit).toHaveBeenCalled()
});
于 2012-09-21T12:03:18.267 回答
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 树的一部分,因此允许它具有焦点,并且还使得它是否具有可测试的焦点。

于 2013-02-19T02:13:20.183 回答
0

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

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

于 2015-06-23T00:46:03.317 回答