тестирование событий keydown в Jasmine с определенным кодом ключа

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

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

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

  • карма тестов
  • PhantomJS browser запускает тесты (но также пробовал 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 и увидеть, что событие создается С the keyCode свойство установлено в 40. Итак, кажется, что он должен работать.

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

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

2 ответов


я использовал следующее решение для его тестирования и его работы в Chrome, FF, PhantomJS и IE9+ на основе этого Так что ответ. Он не работает в 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);

надеюсь, что это помогает

обновление

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

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

вся заслуга принадлежит автору этой истории. Код поддерживает Safari, PhantomJS и IE9-протестирован для первых 2.


добавляя к ответу @MarcoL, я хотел бы указать будущим читателям, которые могут наткнуться на этот вопрос, что методы initKeyboardEvent и initKeyEvent являются устаревшими методами и больше не должны использоваться. См.здесь и здесь.

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