【问题标题】:testing keydown events in Jasmine with specific keyCode使用特定的 keyCode 在 Jasmine 中测试 keydown 事件
【发布时间】:2014-04-29 17:53:26
【问题描述】:

我正在为 AngularJS 指令编写测试,该指令在按下某些键时触发 <textarea> 事件。根据我的手动测试,一切正常。我也想变得优秀并且拥有完整的单元测试套件,但是我遇到了一个我自己无法解决的问题:

我想在我的测试中的triggerHandler() 调用中发送一个特定的keyCode,但我找不到指定密钥实际工作的方法。我知道很多关于使用特定数据构建和发送事件的主题的问题和答案,但它们都不适用于我的设置:

我的设置

  • 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

奇怪的是,我可以在 Chrome 的控制台中输入前 3 行,然后看到正在创建事件 keyCode 属性设置为 40。 所以它似乎应该工作。

另外,当我像 textarea.triggerHandler("keydown"); 这样调用最后一行时,它可以工作并触发事件处理程序。但是,没有keyCode 可以使用,因此毫无意义。

我怀疑这可能与针对与在浏览器中运行的常规页面不同的 DOM 运行的测试的性质有关。但我想不通!

【问题讨论】:

  • 这显然是你需要的stackoverflow.com/questions/832059/…
  • 您好,该讨论专门针对我没有使用的 jQuery。我希望我不需要仅仅为此在我的单元测试中包含 jQuery。
  • 我想我已经为纯 JS 回答了这个问题,但显然这个问题被删除了。您应该可以在 MDN 上找到更多信息。
  • 在其他 [thread][1] 我添加了答案并描述了如何测试 keydown。 [1]:stackoverflow.com/questions/18001169/…

标签: javascript angularjs unit-testing jasmine karma-runner


【解决方案1】:

我使用以下解决方案对其进行了测试,并根据SO answer 让它在 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

所有功劳归于本 GIST 的作者。 该代码确实支持 Safari、PhantomJS 和 IE9 - 已针对前 2 个测试。

【讨论】:

  • 太好了,非常感谢!我稍作修改以返回事件对象,然后将其放入 Angular element.triggerHandler() 方法中,它运行良好。我已经放弃了这个;我现在正忙着完成我的测试套件!
  • @MarcoCI 你正在使用 PhantomJS?我不断收到 keyCode 不匹配的错误消息。
  • 这里也一样。解决这个问题?
  • 刚刚更新了一个更好的解决方案,涵盖了 Safari 和 PhantomJS。
  • 链接代码在 PhantomJS 1.9.8 中不起作用。 TypeError: 'undefined' is not a function (evaluating 'Function.prototype.call.bind(Object.prototype.hasOwnProperty)')
【解决方案2】:

除了@MarcoL 的答案,我想向可能偶然发现这个问题的未来读者指出,initKeyboardEventinitKeyEvent 方法已被弃用,不应再使用。见here here

正如 MDN 文档所建议的那样,事件应该通过它们各自的构造函数来创建。

【讨论】:

    猜你喜欢
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2016-07-25
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多