Тестирование событий keydown в Jasmine с помощью специального keyCode

Я пишу тесты для директивы AngularJS, которая запускает события <textarea> при нажатии определенных клавиш. Все это прекрасно работает при моем ручном тестировании. Я хочу быть хорошим и иметь полный набор модулей тестирования, но у меня возникла проблема, которую я не могу решить самостоятельно:

Я хочу отправить конкретный keyCode в мой вызов triggerHandler() в моем тесте, но я не могу найти способ указать ключ , который действительно работает. Я знаю много вопросов и ответов на тему создания и отправки событий с конкретными данными, но никто из них не работает над моей настройкой:

Моя настройка

  • Тест-драйв Karma
  • PhantomJS-браузер, выполняющий тесты (но также безуспешно использовал Firefox и Chrome)
  • Я не использую jQuery, и я надеюсь, что есть регулярное решение JS. Должно быть!

Тестовый код

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

Странно то, что я могу ввести первые 3 строки в консоль в Chrome и увидеть, что событие создается с свойством keyCode, установленным в 40.  Похоже, он должен работать.

Кроме того, когда я вызываю последнюю строку, подобную этой textarea.triggerHandler("keydown");, она работает, и обработчик события запускается. Тем не менее, нет keyCode для работы, поэтому это бессмысленно.

Я подозреваю, что это может быть связано с характером теста, выполняющегося с DOM, который отличается от обычной страницы, запущенной в браузере. Но я не могу понять это!

Ответ 1

Я использовал следующее решение для тестирования и работу в Chrome, FF, PhantomJS и IE9 + на основе этого SO-ответа. Он не работает в Safari - без проблем пытался миллионы других решений...

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);

Надеюсь, что это поможет

Update

Сегодня я нашел и протестировал это решение, которое предлагает гораздо более широкий охват браузеров (включая поддержку старых):

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

Весь кредит принадлежит автору этого GIST. Код поддерживает Safari, PhantomJS и IE9 - проверен на первые 2.