简体   繁体   中英

Using element.triggerHandler() in angularjs tests for paste and keypress events doesn't seem to have an effect

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:

  1. Event keydown is fired
  2. Event keypress is fired
  3. Value of input is changed to 1 and event input is fired
  4. Event keyup is fired

There 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM