I'm trying to test that on a link click 'preventDefault' is called. However, I have difficulties to replace a real 'event' object with one I can spy on:
Here is how I trigger the click event:
var e = jasmine.createSpyObj('e', [ 'preventDefault' ]);
$element.triggerHandler('click', [e]);
However, when the directive code is being run, the event element is not replaced with a fake one:
$element.on('click', function(event) {
console.log(event);
}
I tried different ways of adding a second parameter to triggerHandler - as an array, as an object, just some line, etc. Neither worked.. It is also not that many examples of triggerHandler together with additional parameters, so I feel a little bit lost...
Thanks in advance!
We also ran into this issue when we wanted to pass an event for testing that had a specific value for the which
property.
As c0bra pointed out, the triggerHandler
function creates its own dummy event object which it then passes on to the event handler. However, you can take advantage of the fact that the triggerHandler
function will extend the dummy event with an event object passed in if there is a valued type
property on the event:
https://github.com/angular/angular.js/blob/v1.6.5/src/jqLite.js#L1043
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);
}
...
}
After inspecting the Angular code, we found that when you call element.triggerHandler
from your test, it will first call an anonymous function which then calls Angular's triggerHandler
function. When Angular's triggerHandler
function is called, it is passed the element as the first argument, then the first argument that you passed to triggerHandler
in your test as the second argument, then your second argument that you passed to triggerHandler
as the third etc. https://github.com/angular/angular.js/blob/v1.6.5/src/jqLite.js#L1068
What that then means is you can pass an object to triggerHandler
in your test as the first argument, and that object's properties will be appended to the dummy event object (or overwritten if there was already a property on the dummy object with the same name), thus allowing you to pass specific values and add spies for testing.
Note that the event type will need to be passed to triggerHandler
as the type property on your object so as to satisfy the if condition mentioned above. As an example, this is how we used triggerHandler
in our test:
element.triggerHandler({
type: 'keydown',
which: 13
});
The docs say that triggerHandler()
passes a dummy object to the handler: http://docs.angularjs.org/api/ng/function/angular.element
If you check the source, you can see that triggerHandler()
creates its own event object, and then passes your second argument as the event data, not the actual event object:
https://github.com/angular/angular.js/blob/master/src/jqLite.js#L882
Relevant code:
var event = [{
preventDefault: noop,
stopPropagation: noop
}];
forEach(eventFns, function(fn) {
fn.apply(element, event.concat(eventData));
});
I've used jQuery's internal event simulator for creating my own events. That may work for you: http://wingkaiwan.com/2012/09/23/triggering-mouse-events-with-jquery-simulate-when-testing-in-javascript/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With