问题描述
我有一个带有模态对话框的React组件(使用reactstrap
构建,但是其他人报告了react-bootstrap
和其他类型的模态组件类似的问题).酶无法找到模态中的任何组件,即使它们在实际应用中呈现良好.最小的例子:
I have a React component with a modal dialog (built using reactstrap
, but others have reported similar problems with react-bootstrap
and other types of modal components). Enzyme cannot find any of the components inside the modal, even though they render fine in the actual app. Minimal example:
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
)
I would like to test the contents (in this case using jest
) like this
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
之类的生命周期方法.
The test finds the contents outside of the Modal correctly, but does not find anything inside. Looking at the snapshot shows that, indeed, nothing inside the <Modal>
is rendered. However it does work if I replace mount
with shallow
. The problem with that is I need mount
to test lifecycle methods like componentDidMount
.
为什么mount
不渲染模态的内容?我认为重点在于,它渲染了整个子元素树.
Why doesn't mount
render the contents of the modal? I thought the whole point was that it rendered the entire tree of child elements.
推荐答案
这在React 16 + Enzyme 3中不再是问题,因为反应16支持门户组件.
This is no longer a problem in React 16 + Enzyme 3, because React 16 supports portal components.
在React 15及更低版本中,问题在于(在大多数实现中)模式对话框是门户组件.这意味着它将创建直接附加到文档根目录的DOM元素,而不是父React组件的子元素.
In React 15 and before, the problem is that a modal dialog is (in most implementations) a portal component. This means it creates DOM elements that are attached directly to the document root, rather than being children of the parent React component.
创建了 ReactWrapper
的find
方法mount
编写的DOM从顶级组件创建的元素开始浏览DOM,因此找不到模态的内容.但是Enzyme的shallow
不会附加到DOM,而是构建自己的包含模态内容的组件树.
The find
method of the ReactWrapper
created by mount
looks through the DOM starting with the element created by the top level component, so it can't find the contents of the modal. But Enzyme's shallow
doesn't attach to a DOM, and instead builds its own component tree which contains the modal contents.
要测试门户组件,首先需要找到附加到文档主体的DOM元素.然后,您可以在它们周围创建一个新的ReactWrapper
,以便所有常规的酶功能起作用:
To test a portal component, you first need to find the DOM elements that have been attached to the document body. Then you can create a new ReactWrapper
around them so that all the usual Enzyme functions work:
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,如下所示:
Update: It seems that Enzyme also leaves the modal attached to the DOM after the test finishes, so you may end up with multiple dialogs open in a later test. If this is a problem, you can clear the DOM after each test like this:
afterEach(() => {
var node = global.document.body;
while (node.firstChild) {
node.removeChild(node.firstChild);
}
});
这篇关于使用mount()的酶测试无法使用React模态对话框的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!