Wondering if someone out there can shed some light on how to properly use element.triggerHandler()
for the paste
and keypress
events inside of an angularjs unit test.
I have two directives, one for limiting the ability of a user to continue firing keypress
events in an element once a length limit has been reached. The second is to prevent the user from pasting text into an element if the length of the text would exceed a limit.
See the following plunker for a full example including my failing tests: https://plnkr.co/edit/5Yyv2cnn3dRKzsj2Lj61?p=preview
For the paste
test I know I'm not using the correct syntax but have been unable to find how to properly do this. Any suggestions?
element.triggerHandler('paste', 'astring')
For the keypress
test, I believe I'm firing the event correctly but it doesn't seem to be updating the value of the element (retrieved using element.val()
)
Been stuck on this for a bit, any help would be greatly appreciated. Thanks!
Let's us start with a short breakdown of what might happen (really up to the browser implementation) when a user presses and releases the 1
key with the focus on an input:
keydown
is firedkeypress
is fired1
and event input
is firedkeyup
is firedThere is no way in JS to actually simulate a user pressing a key. What you can simulate are the things that (usually) happen when a user does so, for example the steps above.
The triggerHandler
function executes all handlers bound with jQuery for the specified event type on the specific element.
So using triggerHandler
with keypress
will not simulate a user pressing a key, it will only fire the event, like step 2 above. The value will not be changed, since that happens in another step.
Now, one would think that in your tests for the limitKeypressLength
directive, you can simply simulate the first part of step 3 above yourself (just setting the value manually):
for (var i = 0; i < 10; i++) {
element.triggerHandler({type: 'keypress', keyCode: 49});
element.val(element.val() + '1');
}
expect(element.val()).toBe('1111111111');
element.triggerHandler('keypress', {which: 49});
element.val(element.val() + '1');
expect(element.val()).toBe('1111111111');
This will not work however, since even if the eleventh keypress event is caught in your directive, the code below will still execute and update the value.
The basic functionality of the limitKeypressLength
directive is to listen on the keypress event and either call event.preventDefault
or not based. This is what you want to test.
For example:
// Set value to something longer than allowed
element.val('123456789123456789');
// Create the event
var e = jQuery.Event('keypress', {
keyCode: 49
});
// Create a spy
spyOn(e, 'preventDefault');
// preventDefault should not have been called yet
expect(e.preventDefault).not.toHaveBeenCalled();
// Trigger the event
element.triggerHandler(e);
// Assert that preventDefault has been called
expect(e.preventDefault).toHaveBeenCalled();
Demo: https://plnkr.co/edit/ktmcBGSuTdMnvqVRlkeQ?p=preview
Now you can as easily test for when the elements value is set to equal/below the allowed value.
Basically the same goes for the limitPasteLength
directive, since its purpose is also to call preventDefault
based on a condition, only that there is some additional mocking to do.