Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest snapshots not working with some Semantic-UI-React components

When I try to create a Jest snapshot of my React component 'LoadingModal', which contains a Semantic-UI-React 'Modal' component, the snapshot ends up empty, with 'null' inside the .snap file. I've tested taking snapshots of other Semantic-UI-React components like 'Button', 'Dropdown', and 'Sidebar', which render and snapshot with the correct html output just fine.

This doesn't look like its an issue with Jest snapshotting itself, but rather react-test-renderer with its .create() and .toJson() methods returning null.

Why would react-test-renderer properly render some Semantic-UI-React components, but not others like 'Modal'? react-test-render seems to be the standard method of serializing React components for snapshotting, and is the method used in Jest's snapshotting docs.

I am using [email protected], [email protected], [email protected], and [email protected]


Update:

It looks like for some reason the Semantic-UI-React Modal component in particular is set to render null when not rendered inside a browser.

See my issue on the github repo for more information.


LoadingModal.test.js

import React from 'react'
import renderer from 'react-test-renderer'
import LoadingModal from './LoadingModal'

test('should render correctly', () => {
    const tree = renderer.create(
        <LoadingModal/>
    ).toJSON()
    expect(tree).toMatchSnapshot()
})

LoadingModal.test.js.snap

// Jest Snapshot v1

exports[`should render correctly 1`] = `null`;

LoadingModal.js

import React from 'react';
import PropTypes from 'prop-types'

import { Modal, Dimmer, Loader} from 'semantic-ui-react'

class LoadingModal extends React.Component {
    static propTypes = {
        header: PropTypes.func,
        content: PropTypes.func,
        loading: PropTypes.bool,
        onClose: PropTypes.func,
        size: PropTypes.string,
        height: PropTypes.string
    };
    static defaultProps = {
        size: 'tiny',
        height: '500px'
    }

    _render_content = (content) => {
        if (this.props.loading === true) {
            return <Dimmer active inverted><Loader active size='large' inline='centered'/></Dimmer>
        } else {
            return content && content()
        }
    }

    render () {
        const {
          header,
          content,
          loading,
          onClose,
          size,
          height
        } = this.props;

        return (
            <Modal size={size} dimmer='blurring' open={true} onClose={onClose}>
              {header && header()}
              <Modal.Content>
                <div style={{height: height}}>
                    {this._render_content(content)}
                </div>
              </Modal.Content>
            </Modal>
        );
    }
}

export default LoadingModal
like image 433
Roman Scher Avatar asked Jan 22 '18 01:01

Roman Scher


1 Answers

As you stated, this may be because you are testing outside a browser. However, this can be fixed using jsdom.

I'm going to assume you have jsdom setup, as react-test-renderer requires jsdom or some other setup that simulates window and document.

Given my assumption, Semantic-UI-React's modal will still render null. This is because it use's the Portal component and renders the modal on the document.body node.

Semantic-UI-React's solution

Look at how Semantic-UI-React tests the modal:

it('renders child components', () => {
  const child = <div data-child />
  wrapperMount(<Modal open>{child}</Modal>)

  document
    .querySelector('.ui.modal')
    .querySelector('[data-child]')
    .should.not.equal(null, 'Modal did not render the child component.')
})

They have to use DOM and css selectors to test, because react-test-renderer and enzyme can't test against document.body.

My solution

I have found another solution that allows the use of react-test-renderer and enzyme, which means you can do snapshots! I use jest.mock to mock the Portal component as a component that renders its children, instead of rendering onto the document.body node.

import React from 'react';
import renderer from 'react-test-renderer';
import Portal from 'semantic-ui-react/dist/commonjs/addons/Portal/Portal';
import { Modal } from 'semantic-ui-react';

jest.mock('semantic-ui-react/dist/commonjs/addons/Portal/Portal', () => ({ children }) => children);

describe('<Modal />', () => {
  test('snapshot', () => {
    const tree == renderer.create(<Modal open>Inside my modal!</Modal>).toJSON();

    expect(tree).toMatchSnapshot();
  });
});

And the snapshot looks like the following:

exports[`<CaptureModal /> snapshot 1`] = `
<div
  className="ui modal transition visible active"
  style={
    Object {
      "marginTop": undefined,
    }
  }
>
  Inside my modal!
</div>
`;
like image 179
Andrew Ferk Avatar answered Nov 09 '22 13:11

Andrew Ferk