2017-08-11 63 views
2

我有一个含模态对话框的React组件(使用reactstrap构建,但其他人已报告与react-bootstrap和其他类型的模块组件相似的问题)。酶无法找到模态内的任何组件,即使它们在实际应用程序中呈现良好。小例子:React模式对话框的内容不适用于使用mount()的酶测试

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>中的任何内容。但是,如果我用shallow替换mount,它确实有效。问题是我需要mount来测试生命周期方法,如componentDidMount

为什么mount渲染模态的内容?我认为整个问题是它渲染了整个儿童元素树。

回答

6

问题是模式对话框(在大多数实现中)是portal组件。这意味着它创建直接附加到文档根目录的DOM元素,而不是作为父React组件的子项。

mount创建的ReactWrapperfind方法从顶层组件创建的元素开始查看DOM,因此无法找到模态的内容。但Enzyme的shallow不附加到DOM,而是构建它自己的包含模式内容的组件树。

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

目前,这是一种酶open bug

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

afterEach(() => { 
    var node = global.document.body; 
    while (node.firstChild) { 
    node.removeChild(node.firstChild); 
    } 
}); 
相关问题