在 Reactjs 中测试 window keydown 事件

Test window keydown event in Reactjs

我正在编写的组件需要根据是否按下 ctrl 来更改其行为。

我使用 window.onkeydown 事件,但是 React Test Utils 中的 Simulate 不允许我针对 window 发送事件。我也试过 window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 17 })); 但 mocha/node 无法识别 KeyboardEvent.

有没有办法使用 React Test Utils 来测试 window.onkeydown?如果没有,有没有更好的方法在 node 的 mocha 中做到这一点?

下面是一些代码来说明这个问题:

describe('On Keydown', () => {
    it('fires the event', () => {
        // Component
        const Component = class extends React.Component {
            constructor(props) {
                super(props);
                this.state = { key: false };
                window.addEventListener('keydown', e => this.setState({ key: true }));
                window.addEventListener('keyup', e => this.setState({ key: false }));
            }
            render() {
                return <span>test</span>
            };
        };
        // Rendering
        const rendered = renderIntoDocument(<Component/>);
        // Firing event
        expect(rendered.state.key).to.equal(false);
        // Error here
        Simulate.keyDown(window, { keyCode: 17 });
        expect(rendered.state.key).to.equal(true);
    });
});

如果你像 window.addEventListener('keydown', myFunc) 那样设置监听器,那么你只需要测试 myFunc,你实际上不需要测试 addEventListener 在 [= 时调用你的函数13=] 发生了。

通过始终将事件绑定到函数(而不是在回调中进行工作),测试更加直接(您正在测试 您的 代码)并且您还可以在以下情况下删除事件侦听器你已经完成了它们。

由于 David 的评论,我通过忽略事件并将状态设置为测试所需的状态来解决它。我还发现了一种不同的方法来测试 window 事件。创建扩展 EventEmitter 的 window class,您可以接收 keydown/keyup 事件,例如 ctrlwindow.emit('keydown',{keyCode: 17}).

这是我的代码_test_helper.js:

import jsdom from 'jsdom';
import chai from 'chai';
import EventEmitter from 'events';

const doc = jsdom.jsdom('<!doctype html><html><body></body></html>');

const windowClass = class extends EventEmitter {
    constructor() {
        super(doc.defaultView);
        this.__defineSetter__('onkeydown', f => this.on('keydown', f));
        this.__defineSetter__('onkeyup', f => this.on('keyup', f));
    }
    addEventListener (e,f) {
        this.on(e,f);
    }
};

const win = new windowClass();

global.document = doc;
global.window = win;

Object.keys(window).forEach((key) => {
  if (!(key in global)) {
    global[key] = window[key];
  }
});