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

Jon*_*ray 7 unit-testing modal-dialog reactjs jestjs enzyme

我有一个带有模态对话框的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>
         );
    } 
}
Run Code Online (Sandbox Code Playgroud)

我想像这样测试内容(在这种情况下使用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);
});
Run Code Online (Sandbox Code Playgroud)

测试正确地找到了Modal之外的内容,但是没有在里面找到任何内容.查看快照显示,实际上,内部没有任何<Modal>内容呈现.但是它确实,如果我更换工作mountshallow.问题是我需要mount测试生命周期方法componentDidMount.

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

Jon*_*ray 8

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

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

创建的find方法通过从顶级组件创建的元素开始查看DOM,因此无法找到模态的内容.但Enzyme 没有附加到DOM,而是构建自己的包含模态内容的组件树.ReactWrappermountshallow

要测试门户组件,首先需要找到已附加到文档主体的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);
});
Run Code Online (Sandbox Code Playgroud)

目前,这是Enzyme中的一个漏洞.

更新:似乎Enzyme在测试完成后也会将模态附加到DOM上,因此您可能会在稍后的测试中打开多个对话框.如果这是一个问题,您可以在每次测试后清除DOM,如下所示:

afterEach(() => {
  var node = global.document.body;
  while (node.firstChild) {
    node.removeChild(node.firstChild);
  }
}); 
Run Code Online (Sandbox Code Playgroud)