Jesper Kristiansen
Jesper Kristiansen

Reputation: 1979

How to create KeyboardEvent with specific keyCode

I'm trying to simulate a keydown event in a unit test (angular2/TypeScript). I do not always have a DebugElement available, so I'm trying to emit the event on a native element. The problem I have is how to define the keyCode when creating the KeyboardEvent. The keyCode is not defined as part of KeyboardEventInit definition, and on the KeyboardEvent itself it is only exposed as a readonly property.

Simply just adding a keyCode property (and set the obj type as ) doesn't work either.

    let elm = <HTMLElement>content.nativeElement;
    let ev = new KeyboardEvent('keydown', {
        code: '123',
        //keyCode: 345,
        key: 'a',
    });
    elm.dispatchEvent(ev);

Any suggestions ?

Edit: According to the mdn link, keyCode is deprecated and should not be used, instead 'code' should be used. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

Upvotes: 19

Views: 26949

Answers (5)

Kavinda Senarathne
Kavinda Senarathne

Reputation: 2014

Have a look :

<!DOCTYPE html>
<html>
<body>
  <script>
  function EventHandler(e) {
    e = e || window.event;
    var code = typeof e.which !== 'undefined' ? e.which : e.keyCode; 
    if(code == 112 || code == 113 
        || code == 114 || code == 115
        || code == 116 || code == 117
        || code == 118 || code == 119
        || code == 120 || code == 121
        || code == 122 || code == 123) {
      e.returnValue = false;
      var target2 = document.getElementById("iFrameId"); 
      var targetBody = target2.contentDocument.body; 
      var keyboardEvent = document.createEvent("KeyboardEvent");

      Object.defineProperty(keyboardEvent, 'keyCode', {
        get : function() {
          return this.keyCodeVal;
        }
      });

      Object.defineProperty(keyboardEvent, 'which', {
        get : function() {
          return this.keyCodeVal;
        }
      });

      var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";

      keyboardEvent[initMethod](
         "keydown", // event type : keydown, keyup, keypress
         true, // bubbles
         true, // cancelable
         window, // viewArg: should be window
         false, // ctrlKeyArg
         false, // altKeyArg
         false, // shiftKeyArg
         false, // metaKeyArg
         code, // keyCodeArg : unsigned long the virtual key code, else 0
         0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
      );
      keyboardEvent.keyCodeVal = code;
      targetBody.dispatchEvent(keyboardEvent);        
    }
  }
  </script>

  <form>
    <input type="text" name="first" onkeydown="EventHandler()" > <br>
    <iframe id="iFrameId" src="frame.html" > </iframe>
  </form>
</body>
</html>

Upvotes: 0

Kavinda Senarathne
Kavinda Senarathne

Reputation: 2014

or example, if you wanted to run a function when a user hit CTRL+ALT+D, your code would look something like this.

 window.addEventListener('keydown', (event: KeyboardEvent) => {
       // Fall back to event.which if event.keyCode is null
       const keycode = event.keyCode || event.which;
       if (keycode === 68 && event.ctrlKey && event.altKey) {
         // Do stuff here
       }
    });

Upvotes: 0

Garrett Manley
Garrett Manley

Reputation: 337

If you're using angular, you can set the keyboard event, and key in your HTML template and bind to your method.

See angular docs on this: https://angular.io/guide/user-input#key-event-filtering-with-keyenter

And since you don't need to test the angular API as it's not your system under test, you should simply write your unit tests by passing mocked data into the method you've bound the key event to.


All of this isn't particularly helpful though if you meant UI/Integration tests, as the above is really only valid for unit tests.

Upvotes: 0

Rambou
Rambou

Reputation: 1058

I still think that this is a bug from the Typescript's side because of the initializer LanguageEvent has. In any case, a workaround would be to use Object.define to set the keyCode.

let arrowRight = new KeyboardEvent('keydown');
Object.defineProperty(arrowRight, 'keyCode', {
    get : () => 39
});
console.log(arrowRight.keyCode, arrowRight.key, arrowRight.code);

No matter the fact that the keyCode is deprecated, that doesn't mean that the initializer shouldn't support it. The most strong argument is the fact that Internet Explorer 9 and 11 depends on that and they don't support the code https://caniuse.com/#search=event.code or fully support the key https://caniuse.com/#search=event.key So I think that LanguageEvent should allow keyCode in its initializer.

let arrowRight = new KeyboardEvent('keydown', { keyCode: 39 });

Upvotes: 4

waterplea
waterplea

Reputation: 3661

keyCode is deprecated, Angular itself operates with key — I suggest you rewrite your logic to use it too. Keep in mind that it is browser dependent — in IE space bar is Space and in other browsers it is . Also Esc and Escape are different. Don't remember any other ones that differ.

Upvotes: 1

Related Questions