【问题标题】:Simulate fake keypress in jasmine在茉莉花中模拟假按键
【发布时间】:2014-11-17 05:21:43
【问题描述】:

我正在尝试在 Jasmine 中模拟按键(测试浏览器是 PhantomJS),因此我可以对一些使用按键的功能进行单元测试。不幸的是,我无法使用 Jasmine 正确测试它,因为我遇到了错误。

这是我要测试的代码:

function Controls() {
  'use strict';
  this.codes = {
    37: 'left',
    39: 'right',
    38: 'forward',
    40: 'backward'
  };
  this.states = {
    'left': false,
    'right': false,
    'forward': false,
    'backward': false
  };
  document.addEventListener('keydown', function() { this.onKey.bind(this, true); }, false);
  document.addEventListener('keyup', function() { this.onKey.bind(this, false); }, false);
}

Controls.prototype.onKey = function(val, e) {
  var state = this.codes[e.keyCode];

  if (typeof state === 'undefined') return false;

  this.states[state] = val;

  // Stop the key press from repeating
  e.preventDefault();
  e.stopPropagation();

  return true;
};

controls = new Controls();

(注意:上面的代码用匿名函数包装了 addEventListener 中的函数,这样 Jasmine 会真正尝试运行我的测试。没有匿名包装,这会导致另一个错误:TypeError: 'undefined' is not a function (evaulating 'this.onKey.bind(this, true)' 解决这个问题也很棒. )

这是我的测试尝试:

function keyPress(key) {
  var pressEvent = document.createEvent('KeyboardEvent');
  pressEvent.initKeyEvent('keydown', true, true, window,
                            false, false, false, false,
                            0, key);
  document.dispatchEvent(pressEvent);
}

describe("Controls", function() {
  var controls;

  it("should initialize properly", function() {
    controls = new Controls();
    expect(controls).not.toBe(null);
  });

  it("should reflect changes in state when arrow keys are used", function() {
    keyPress(37);
    expect(controls.states[state]).toBe(37);
  });
});

这会导致 Jasmine 出错:

TypeError: 'undefined' is not a function (evaluating 'pressEvent.initKeyEvent('keydown', true, true, window, false, false, false, false, 0, key)')

我对 Jasmine 还是很陌生(就此而言,Javascript),所以任何一般的帮助将不胜感激。

【问题讨论】:

    标签: javascript unit-testing jasmine


    【解决方案1】:

    您的问题似乎在于您创建活动的方式。

    下面的示例代码显示了如何创建、触发和拦截事件。

    var keyPressed = null;
    
    function keyPress(key) {
      var event = document.createEvent('Event');
      event.keyCode = key; // Deprecated, prefer .key instead.
      event.key = key;
      event.initEvent('keydown');
      document.dispatchEvent(event);
    }
    
    document.addEventListener('keydown', function(e){
       keyPressed = e.key;
    });
    
    keyPress(37)
    alert(keyPressed);
    

    这也是一个笨蛋:http://plnkr.co/edit/TxGXcT0DnPa44C0PkHkN?p=preview

    如评论所述,请参阅 here 了解有关 .keyCode 弃用的信息。

    【讨论】:

    • 因为这解决了手头的实际问题,所以我接受了这个答案;谢谢克里斯!但是,我最初的问题并不是我应该问的,所以我将在下面提供更多详细信息。
    • 嗨,这是一篇旧帖子,但很高兴知道 keyCode 现在已弃用 see the MDN article。所以代码应该使用keycode,因此会略有不同。
    • 我用新的event.key 版本而不是event.keycode 编辑了这个答案
    【解决方案2】:

    编辑:这个问题应该从 PhantomJS 2 开始解决。更多信息在下面的问题中。

    所以原因

    this.onKey.bind(this, true)
    

    返回错误是因为截至本文发布之日,PhantomJS 还不支持绑定。您可以在此处找到更多信息:

    https://github.com/ariya/phantomjs/issues/10522

    还有来自 ariya 的更长解释:

    https://groups.google.com/forum/#!msg/phantomjs/r0hPOmnCUpc/uxusqsl2LNoJ

    解决此问题的一种方法是按照 creationix 的建议创建一个 polyfill:

    https://github.com/c9/smith/blob/master/tests/public/test.js#L2-L7

    鉴于所有这些信息,知道我可以规避原型问题,应该会使测试更易于管理。感谢大家的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 2016-11-01
      • 1970-01-01
      • 2018-12-17
      相关资源
      最近更新 更多