我有一个带有模态对话框的React组件(使用构建reactstrap,但其他人也报告了类似的问题react- bootstrap以及其他类型的模态组件)。酶无法在模态中找到任何组件,即使它们在实际应用中呈现良好。最小示例:
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)
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。
<Modal>
mount
shallow
componentDidMount
为什么不mount渲染模态的内容?我认为重点是它渲染了整个子元素树。
编辑:这不再是React 16 +酶3中的问题,因为React 16支持门户组件。
在React 15及之前版本中,问题在于模式对话框是(在大多数实现中)门户组件。这意味着它将创建直接附加到文档根目录的DOM元素,而不是父React组件的子元素。
create by 的find方法以顶级组件创建的元素开头的DOM进行浏览,因此找不到模态的内容。但是,酶没有附加到DOM,而是建立了自己的包含模态内容的组件树。ReactWrappermount``shallow
find
ReactWrapper
mount``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); } });