testing keydown events in Jasmine with specific ke

2019-01-18 23:31发布

I am writing tests for an AngularJS directive which fires events of a <textarea> when certain keys are pressed. It all works fine per my manual testing. I want to be good and have a full unit-test suite too, but I have run into a problem I can't solve on my own:

I want to send a specific keyCode in my triggerHandler() call in my test, but I can't find a way to specify the key that actually works. I am aware of a lot of questions and answers on the topic of building and sending events with specific data, but none of them work on my setup:

My setup

  • Karma test runner
  • PhantomJS browser running the tests (but also tried Firefox and Chrome without success)
  • I'm not using jQuery and I'm hoping there is a regular JS solution. There must be!

Test code

var event = document.createEvent("Events");
event.initEvent("keydown", true, true);
event.keyCode = 40; // in debugging the test in Firefox, the event object can be seen to have no "keyCode" property even after this step
textarea.triggerHandler(event); // my keydown handler does not fire

The strange thing is, I can type the first 3 lines into the console in Chrome and see that the event is being created with the keyCode property set to 40. So it seems like it should work.

Also, when I call the last line like this textarea.triggerHandler("keydown"); it works and the event handler is triggered. However, there is no keyCode to work with, so it is pointless.

I suspect it may be something to do with the nature of the test running against a DOM that is different to a regular page running in the browser. But I can't figure it out!

2条回答
SAY GOODBYE
2楼-- · 2019-01-19 00:28

Adding to @MarcoL answer, I'd like to point out for future readers who might stumble on this question, that the methods initKeyboardEvent and initKeyEvent are deprecated methods, and should no longer be used. See here and here.

Instead as the MDN docs suggested, events should be created via their respective constructor.

查看更多
神经病院院长
3楼-- · 2019-01-19 00:32

I've used the following solution to test it and having it working in Chrome, FF, PhantomJS and IE9+ based on this SO answer. It doesn't work in Safari - tried millions of other solution without any success...

function jsKeydown(code){
  var oEvent = document.createEvent('KeyboardEvent');

  // Chromium Hack: filter this otherwise Safari will complain
  if( navigator.userAgent.toLowerCase().indexOf('chrome') > -1 ){
    Object.defineProperty(oEvent, 'keyCode', {
      get : function() {
        return this.keyCodeVal;
      }
    });     
    Object.defineProperty(oEvent, 'which', {
      get : function() {
        return this.keyCodeVal;
      }
    });
  }

  if (oEvent.initKeyboardEvent) {
    oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, code, code);
  } else {
    oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, code, 0);
  }

  oEvent.keyCodeVal = code;

  if (oEvent.keyCode !== code) {
    console.log("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ") -> "+ code);
  }

  document.getElementById("idToUseHere").dispatchEvent(oEvent);
}

// press DEL key
jsKeydown(46);

Hope it helps

Update

Today I've found and tested this solution which is offers a much wider coverage of browsers (enabling the legacy support):

https://gist.github.com/termi/4654819

All the credit goes to the author of this GIST. The code does support Safari, PhantomJS and IE9 - tested for the first 2.

查看更多
登录 后发表回答