Content of React modal dialogs is not available to Enzyme tests using mount()

Viewed 9358

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.

3 Answers

try mocking the createPortal responsible for showing modals ReactDOM.createPortal = jest.fn(modal => modal);

In case you are using an older version of Enzyme, you can pass the container element to mount where you want your Modal to be rendered, like this:

import React from 'react'
import MyModal  from './MyModal'
import { mount } from 'enzyme'

describe(() => {
    let wrapper;
    beforeEach(() => {
        const container = document.createElement("div");
        document.body.appendChild(container);
        wrapper = mount( <MyModal modalOpen/> , {attachTo: container});
    });

    it('renders correctly', () => {
        expect(wrapper).toMatchSnapshot();

        // Passes
        expect(wrapper.find('.outside')).toHaveLength(1);

        // Passes now
        expect(wrapper.find('.inside')).toHaveLength(1);
    });

})
Related