在Reactjs中测试窗口的keydown事件

6
我正在编写的组件需要根据是否按下Ctrl键来改变其行为。
我使用了 window.onkeydown 事件,但是来自React Test Utils的Simulate不允许我对window进行调度事件。我还尝试过window.dispatchEvent(new KeyboardEvent('keydown',{ keyCode: 17 }));,但是mocha / node不会识别KeyboardEvent
是否有一种方法可以使用React Test Utils测试window.onkeydown?如果没有,那么在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);
    });
});
2个回答

1
如果您像这样设置侦听器 window.addEventListener('keydown', myFunc),那么您只需要测试myFunc,实际上不需要测试addEventListener是否在发生keydown时调用您的函数。

始终将事件绑定到函数(而不是在回调中执行操作),这样测试更直接(您正在测试您的代码),并且在完成后可以删除事件侦听器。


1
测试组件是否能够监听keydown事件怎么样?也许这应该成为规范的一部分。如果不是,可以删除addEventListener,组件仍然可以通过测试。 - jokka
有道理。就我个人而言,我会依赖自动化测试来处理这些事情,并让单元测试来测试逻辑。 - David Gilbertson
很好。只是有点烦恼的是事件处理程序基本上是一个私有方法,并且测试依赖于它。但这不是什么大问题。 - jokka
1
你有没有尝试手动分派一个普通的 Event 而不是 KeyboardEvent - David Gilbertson
我需要keydown事件来触发状态改变,从而影响另一个方法的行为,但你给了我两个想法。第一个是使用rendered.setState({key: true})绕过事件,第二个是在test_helper.js中创建一个类,使用节点Events来重现窗口上的事件。我将第二个解决方案作为备选答案添加进去。 - Javier Conde

1
我因为David的评论解决了这个问题,只需要忽略事件并将状态设置为我需要测试的状态即可。我还发现了一种在未来测试窗口事件的不同方法。创建一个继承EventEmitter的窗口类,可以像ctrl这样通过window.emit('keydown',{keyCode: 17})接收keydown/keyup事件。

这是我的_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];
  }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接