小编典典

使用mount()的酶测试无法使用React模态对话框的内容

reactjs

我有一个带有模态对话框的React组件(使用构建reactstrap,但其他人也报告了类似的问题react- bootstrap以及其他类型的模态组件)。酶无法在模态中找到任何组件,即使它们在实际应用中呈现良好。最小示例:

import React from 'react'
import { Modal } from 'reactstrap'

export default class MyModal extends React.Component {

    render() {
        return (
            <div className="outside"> Some elements outside of the dialog </div>
            <Modal isOpen={this.props.modalOpen}>
                <div className="inside"> Content of dialog </div>
            </Modal>
         );
    } 
}

我想这样测试内容(在本例中使用jest

import React from 'react'
import MyModal  from './MyModal'
import { mount } from 'enzyme'

it('renders correctly', () => {
    const wrapper = mount( <MyModal modalOpen/> );

    expect(wrapper).toMatchSnapshot();

    // Passes
    expect(wrapper.find('.outside')).toHaveLength(1);

    // Fails, 0 length
    expect(wrapper.find('.inside')).toHaveLength(1);
});

该测试可以正确找到Modal外部的内容,但内部找不到任何内容。查看快照表明,确实没有<Modal>渲染任何内容。但是,如果我替换为mount,它确实可以工作shallow。问题是我需要mount测试生命周期方法,例如componentDidMount

为什么不mount渲染模态的内容?我认为重点是它渲染了整个子元素树。


阅读 205

收藏
2020-07-22

共1个答案

小编典典

编辑:这不再是React 16 +酶3中的问题,因为React
16支持门户组件

在React 15及之前版本中,问题在于模式对话框是(在大多数实现中)门户组件。这意味着它将创建直接附加到文档根目录的DOM元素,而不是父React组件的子元素。

create by
find方法以顶级组件创建的元素开头的DOM进行浏览,因此找不到模态的内容。但是,酶没有附加到DOM,而是建立了自己的包含模态内容的组件树。ReactWrappermount``shallow

要测试门户组件,首先需要找到附加到文档主体的DOM元素。然后,您可以ReactWrapper在它们周围创建一个新对象,以便所有常规的酶功能起作用:

import React from 'react'
import MyModal  from './MyModal'
import { mount, ReactWrapper } from 'enzyme'

it('renders correctly', () => {
    const wrapper = mount( <MyModal modalOpen/> );

    expect(wrapper).toMatchSnapshot();

    // Passes
    expect(wrapper.find('.outside')).toHaveLength(1);

    // Construct new wrapper rooted at modal content
    inside_els = document.getElementsByClassName("inside")[0]
    inside_wrapper = new ReactWrapper(inside_els, true)

    // Passes
    expect(inside_wrapper.find('.inside')).toHaveLength(1);
});

当前,这是酶中的一个开放错误

更新:似乎在测试完成后,酶也将模式附加在DOM上,因此您可能最终在以后的测试中打开多个对话框。如果有问题,可以在每次测试后清除DOM,如下所示:

afterEach(() => {
  var node = global.document.body;
  while (node.firstChild) {
    node.removeChild(node.firstChild);
  }
});
2020-07-22