简体   繁体   English

在茉莉花中模拟假按键

[英]Simulate fake keypress in jasmine

I'm trying to simulate a keypress in Jasmine (the test browser is PhantomJS) so I can unit test some of my functions that use key presses.我正在尝试在 Jasmine 中模拟按键(测试浏览器是 PhantomJS),因此我可以对一些使用按键的功能进行单元测试。 Unfortunately, I can't test it properly with Jasmine because I'm getting errors.不幸的是,我无法用 Jasmine 正确测试它,因为我遇到了错误。

Here's the code I'm trying to test:这是我要测试的代码:

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

(NOTE: The above code wraps the functions in the addEventListener with anon functions so that Jasmine will actually attempt to run my tests. Without the anonymous wrap, this results in another error: TypeError: 'undefined' is not a function (evaulating 'this.onKey.bind(this, true)' Solving this problem would be great too. ) (注意:上面的代码用匿名函数包装了 addEventListener 中的函数,以便 Jasmine 实际上会尝试运行我的测试。没有匿名包装,这会导致另一个错误: TypeError: 'undefined' is not a function (evaulating 'this.onKey.bind(this, true)'解决这个问题也很好。)

And this is my attempt at testing:这是我的测试尝试:

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

This results in an error from Jasmine:这会导致 Jasmine 出现错误:

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

I'm still very new to Jasmine (and for that matter, Javascript), so any help in general would be appreciated.我对 Jasmine 仍然很陌生(就此而言,Javascript),所以任何一般的帮助都会受到赞赏。

It looks like your problem is with how you're creating your event.看起来您的问题在于您如何创建活动。

The example code below shows how an event is created, triggered, and intercepted.下面的示例代码显示了如何创建、触发和拦截事件。

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

Here's a plunker too: http://plnkr.co/edit/TxGXcT0DnPa44C0PkHkN?p=preview这也是一个 plunker: http ://plnkr.co/edit/TxGXcT0DnPa44C0PkHkN?p=preview

As commented, see here for information regarding .keyCode deprecation.如评论所述,请参阅此处以获取有关 .keyCode 弃用的信息。

EDIT: This issue should be resolved as of PhantomJS 2. More information in the issue below.编辑:这个问题应该从 PhantomJS 2 开始解决。更多信息在下面的问题中。

So the reason所以原因

this.onKey.bind(this, true)

was returning an error is because as of the date of this post, PhantomJS doesn't support binds yet.返回错误是因为截至本文发布之日,PhantomJS 还不支持绑定。 You can find more information on that here:您可以在此处找到更多信息:

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

and a longer explanation from ariya here:以及来自 ariya 的更长解释:

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

A way around this issue is to create a polyfill as suggested by creationix:解决此问题的一种方法是按照 creationix 的建议创建一个 polyfill:

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

Given all of this information, it should make testing a little more manageable knowing that I can circumvent the prototype issue.鉴于所有这些信息,知道我可以绕过原型问题,它应该使测试更易于管理。 Thanks for all of the help!感谢所有的帮助!

The modern way:现代方式:

function keyPress(key: string, el: HTMLElement) {
  const event = new KeyboardEvent('keydown', { key });
  el.dispatchEvent(event);
}

Call it like this:像这样称呼它:

keyPress('space', el as HTMLElement);

It worked with the latest version of Devextreme components (v22.1.3).它适用于最新版本的 Devextreme 组件 (v22.1.3)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM