React 模态对话框的内容不可用于使用 mount() 的酶测试 [英] Content of React modal dialogs is not available to Enzyme tests using mount()

查看:16
本文介绍了React 模态对话框的内容不可用于使用 mount() 的酶测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

从 'react' 导入 React从'reactstrap'导入{模态}导出默认类 MyModal 扩展 React.Component {使成为() {返回 (<div className="外面">对话框之外的一些元素</div><Modal isOpen={this.props.modalOpen}><div className="里面">对话框内容

</模态>);}}

我想像这样测试内容(在这种情况下使用jest)

从 'react' 导入 React从 './MyModal' 导入 MyModal从酶"导入 { mount }it('正确渲染', () => {const wrapper = mount( <MyModal modalOpen/> );期望(包装器).toMatchSnapshot();//通过期望(wrapper.find('.outside')).toHaveLength(1);//失败,长度为 0期望(wrapper.find('.inside')).toHaveLength(1);});

测试正确找到了Modal外的内容,但没有找到里面的任何内容.查看快照表明,实际上, 中没有任何内容被渲染.但是,如果我将 mount 替换为 shallow,它确实有效.问题是我需要 mount 来测试生命周期方法,比如 componentDidMount.

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

解决方案

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

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

find方法mount 创建的 ReactWrapper 从顶层组件创建的元素开始遍历 DOM,所以找不到 modal 的内容.但是 Enzyme 的 shallow 不附加到 DOM,而是构建自己的包含模态内容的组件树.

要测试门户组件,首先需要找到已附加到文档正文的 DOM 元素.然后你可以在它们周围创建一个新的 ReactWrapper 以便所有常用的 Enzyme 函数都可以工作:

从 'react' 导入 React从 './MyModal' 导入 MyModal从酶"导入 { mount, ReactWrapper }it('正确渲染', () => {const wrapper = mount( <MyModal modalOpen/> );期望(包装器).toMatchSnapshot();//通过期望(wrapper.find('.outside')).toHaveLength(1);//构建以模态内容为根的新包装器inside_els = document.getElementsByClassName("inside")[0]inside_wrapper = new ReactWrapper(inside_els, true)//通过期望(inside_wrapper.find('.inside')).toHaveLength(1);});

目前,这是酶中的开放性错误.

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

afterEach(() => {var node = global.document.body;而(节点.firstChild){node.removeChild(node.firstChild);}});

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>
         );
    } 
}

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);
});

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.

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.

解决方案

Edit: This is no longer a problem in React 16 + Enzyme 3, because React 16 supports portal components.

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.

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.

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);
});

Currently, this is an open bug in Enzyme.

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);
  }
}); 

这篇关于React 模态对话框的内容不可用于使用 mount() 的酶测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆