我正在尝试为无处不在的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事件代码是否有特殊性?
答案 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
实现,并检查它是否被调用。