使用 Jasmine 测试对象中的事件处理程序
Testing event handlers in objects with jasmine
我在我的CoffeeScript ala Spinejs中使用了一个简单的MVC模式。它允许我通过在实例化之前指定事件对象来添加事件侦听器:
class Controller extends Module
@include Events
eventSplitter: /^('S+)'s*(.*)$/
events: {}
constructor: (view = '<div/>') ->
@view = $(view)
@delegate key, func for key, func of @events
delegate: (key, func) ->
match = key.match @eventSplitter
if match[2] is ''
@view.on( match[1], $.proxy(@[func], @) )
else
@view.on( match[1], match[2], $.proxy(@[func], @) )
快速解释 - 您传入分配给视图属性的选择器、元素或 html 字符串。然后,delegate 方法获取事件对象并循环并将事件侦听器分配给视图节点本身,或者它将事件处理程序从子元素委托给视图节点:
class Con extends Controller
events:
'click' : 'parent'
'mouseover span' : 'child'
parent: (e) ->
console.log('div was clicked')
child: (e) ->
console.log('span was moused over')
con = new Con('<div><span>test</span></div>')
con.view.trigger('click') // --> 'div was clicked'
con.view.find('span') // --> 'span was moused over'
我正在努力用茉莉花测试这一点。以下测试将通过:
expect( con.view ).toHandle('mouseover')
expect( con.view ).toHandle('click')
这至少允许我测试设置了某种处理程序,但我想测试正在设置的实际处理程序。我试图监视事件处理程序,但它们似乎从未被调用过。
spyOn(con, 'parent')
con.view.trigger('click')
expect( con.parent ).toHaveBeenCalled() // fails!
我还试图监视原型中的实际方法。
spyOn( Con.prototype, 'parent' )
con.view.trigger('click')
expect( Con.prototype.parent ).toHaveBeenCalled() // fails!
如果我显式调用该方法,我可以让测试通过:
con.parent();
expect( con.parent ).toHaveBeenCalled() // passes!
我认为间谍在由事件执行时失败,因为事件处理程序是如何通过 jQuery 'on' 方法引用的。 就像它是一个函数一样,但它不是 con 对象上的实际方法。
任何帮助将不胜感激。也欢迎任何一般测试建议。
解决方案似乎是定义对象之外的间谍。我刚刚发现了jasmine.createSpy()方法,它创建了一个裸露的间谍,这正是我所需要的:
describe "Controller", ->
clickSpy = jasmine.createSpy()
mouseSpy = jasmine.createSpy()
class Con extends CRDGN.Controller
events:
'click' : 'parent'
'mouseover span' : 'child'
parent: clickSpy
child: mouseSpy
con = new Con('<div><span>test</span></div>')
it "should attach listeners through an events object", ->
con.view.trigger('click')
expect( clickSpy ).toHaveBeenCalled()
con.view.find('span').trigger('mouseover')
expect( mouseSpy ).toHaveBeenCalled()
Jasmine实际上有一个spyOn
方法,它允许您在不覆盖被测系统的情况下执行此操作。
我承认没有运行这个特定的代码,但这里是你的答案的重构,它使用spyOn
并拆分了你的两个测试。
describe 'CRDGN.Controller', ->
it 'should attach a click listener', =>
clickSpy = spyOn(CRDGN.Controller, 'parent')
controller = @_buildController()
controller.view.trigger('click')
expect(clickSpy).toHaveBeenCalled()
it 'should attack a mouseover listener for <span>', =>
mouseSpy = spyOn(CRDGN.Controller, 'child')
controller = @_buildController()
controller.view.find('span').trigger('mouseover')
expect(mouseSpy).toHaveBeenCalled()
_buildController: () ->
new CRDGN.Controller('<div><span>test</span></div>')
相关文章:
- keyup事件处理程序更改焦点不适用于快速键入
- 提示使用服务器端事件处理程序激活JavaScript
- 将事件处理程序绑定到任何可能的事件
- 正在将事件处理程序添加到不存在的类
- 在循环中附加事件处理程序时出现浏览器性能问题
- 在同一个javascript事件处理程序中调用不同的函数
- 有没有一种方法可以让内联事件处理程序在元素创建后立即执行
- 检查事件处理程序参数
- 实现延迟的jquery更改事件处理程序
- 如何使用Node.js在JavaScript模块文件之间使用事件处理程序
- 如何使jQuery的“bind”或“on”事件处理程序幂等
- 带有参数的Javascript事件处理程序
- Jquery事件处理程序仅适用于匿名函数
- 如何从另一个处理程序内部取消JavaScript事件处理程序函数的执行
- 如何在jQuery事件处理程序中存储和重用超时
- 如何向onClick事件处理程序传递一个接受参数的函数,并且仍然将该函数绑定到组件's”;这个“;上下文
- 异步处理所有事件处理程序的方法
- jsplumb中的Click事件处理程序丢失“;这个“;对象
- 构造函数中的事件处理程序与构造函数外的事件处理函数的行为不同
- 如何在事件处理程序的回调中防止Default