首页 > 解决方案 > 在 componentDidMount() 中设置时如何模拟 eventListener

问题描述

那是我的组件

class Foo extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            ...
        };

        this.input = React.createRef();
    }

    componentDidMount() {
        const id = 'bar';
        let element = document.getElementById(id);
        element.addEventListener('transitionend', () => {
            this.setState({ ... });
        }, false);
    }

    ...

当我这样设置测试时

import React from 'react';
import { mount } from 'enzyme';
import 'jsdom-global/register';

import Foo from './';

it('renders the component correctly', () => {
    const component = mount(
        <Foo />
    );

    component
        .unmount();
});

我明白了

console.error node_modules/react-dom/cjs/react-dom.development.js:16647 组件出现上述错误:in Foo (created by WrapperComponent) in WrapperComponent

考虑向树中添加错误边界以自​​定义错误处理行为。● 正确渲染组件 TypeError: Cannot read property 'addEventListener' of null

我试过

ReactDOM.render(<Foo />, document.body);

或添加这个

const map = {};
Window.addEventListener = jest.genMockFn().mockImpl((event, cb) => {
  map[event] = cb;
});

还有这个

const map = {};
    document.addEventListener = jest.fn((event, cb) => {
      map[event] = cb;
    })

在测试中安装之前<Foo />。但这一切都带来了同样的错误。这是为什么?

标签: javascriptreactjsjestjsenzyme

解决方案


在 React 中不鼓励直接访问 DOM 的原因之一是因为它使测试变得更加复杂和不可预测。

可以在安装组件之前完全模拟 DOM:

const elementMock = { addEventListener: jest.fn() };
jest.spyOn(document, 'getElementById').mockImplementation(() => elementMock);

可以测试被正确调用的存根:

expect(elementMock.addEventListener).toBeCalledWith('transitionend', expect.any(Function), false);

并且可以测试事件侦听器是否按预期更改状态:

const handler = elementMock.mock.calls[0][1];
handler();
...

推荐阅读