如何使用特定的假“事件”参数调用triggerHandler?

时间:2014-03-11 17:37:08

标签: angularjs unit-testing

我正试图在链接上测试点击'preventDefault'被调用。但是,我很难用一个可以监视的实际“事件”对象替换:

以下是触发点击事件的方法:

var e = jasmine.createSpyObj('e', [ 'preventDefault' ]);
$element.triggerHandler('click', [e]);

但是,当运行指令代码时,事件元素不会被伪造的代替:

$element.on('click', function(event) {
    console.log(event);
}

我尝试了不同的方法向triggerHandler添加第二个参数 - 作为一个数组,作为一个对象,只是一些行等。都没有工作..它也不是很多triggerHandler的例子和其他参数,所以我觉得有点失落......

提前致谢!

2 个答案:

答案 0 :(得分:27)

当我们想要传递一个具有triggerHandler属性特定值的测试事件时,我们也遇到了这个问题。

正如c0bra所指出的,triggerHandler函数创建了自己的虚拟事件对象,然后将其传递给事件处理程序。但是,如果事件中存在值type属性,则可以利用triggerHandler: function(element, event, extraParameters) { ... // If a custom event was provided then extend our dummy event with it if (event.type) { dummyEvent = extend(dummyEvent, event); } ... } 函数扩展虚拟事件并传入事件对象这一事实: https://github.com/angular/angular.js/blob/v1.6.5/src/jqLite.js#L1043

element.triggerHandler

在检查Angular代码后,我们发现当您从测试中调用triggerHandler时,它将首先调用一个匿名函数,然后调用Angular的{{1}功能。当调用Angular的triggerHandler函数时,它将元素作为第一个参数传递,然后传递给测试中作为第二个参数的triggerHandler的第一个参数,然后是第二个参数您传递给triggerHandler作为第三个等https://github.com/angular/angular.js/blob/v1.6.5/src/jqLite.js#L1068

这意味着您可以将测试中的对象作为第一个参数传递给triggerHandler,并且该对象的属性将被附加到虚拟事件对象(如果已经存在,则会被覆盖虚拟对象上具有相同名称的属性),从而允许您传递特定值并添加间谍以进行测试。

请注意,事件类型需要作为对象的type属性传递给triggerHandler,以满足上面提到的if条件。例如,这就是我们在测试中使用triggerHandler的方式:

element.triggerHandler({
    type: 'keydown',
    which: 13
});

答案 1 :(得分:2)

文档说triggerHandler()将虚拟对象传递给处理程序:http://docs.angularjs.org/api/ng/function/angular.element

如果检查源代码,可以看到triggerHandler()创建了自己的事件对象,然后将第二个参数作为事件数据传递,而不是实际的事件对象:

https://github.com/angular/angular.js/blob/master/src/jqLite.js#L882

相关代码:

var event = [{
  preventDefault: noop,
  stopPropagation: noop
}];

forEach(eventFns, function(fn) {
  fn.apply(element, event.concat(eventData));
});

我使用jQuery的内部事件模拟器来创建自己的事件。这可能适合您:http://wingkaiwan.com/2012/09/23/triggering-mouse-events-with-jquery-simulate-when-testing-in-javascript/