Error when rendering React Portal with Storyshots

9.2k Views Asked by At

I'm trying to render a modal using a portal, it works fine in my application as well as in Storybook, but as soon as it is added to Storyshots I run into problems.

The first issue was to mock ReactDOM's createPortal API. I did it like:

ReactDOM.createPortal = element => element;

If this is not added, I get the following error:

Error: Uncaught [TypeError: parentInstance.children.indexOf is not a function]

I found this solution React Portal Error.

This solves this issue, but then when the component uses the portal it fails when trying to append the child. It doesn't find the 'modal-root' component, and thus can't append the element. I'm not sure how to get past this.

My portal looks pretty much the same as the example on the React website:

import React from 'react';
import { createPortal } from 'react-dom';
import { node } from 'prop-types';

class Portal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }

  componentDidMount() {
    // !!!!!!!fails here !!!!!!!!!
    document.getElementById('modal-root').appendChild(this.el);
  }

  componentWillUnmount() {
    document.getElementById('modal-root').removeChild(this.el);
  }

  render() {
    return createPortal(this.props.children, this.el);
  }
}

It now fails with this error:

Error: Uncaught [TypeError: Cannot read property 'appendChild' of null]

Position indicated in the code snippet above.

3

There are 3 best solutions below

0
On

Another approach. Place the following in your jest setup file:

jest.mock('react-dom', () => {
  const original = jest.requireActual('react-dom');
  return {
    ...original,
    createPortal: node => node,
  };
});

0
On

As mentioned here you can install rc-util and add the following to either the top of your test or (if you want it global) inside your jest.setup.js (or package.json jest section if that is what you use).

jest.mock('rc-util/lib/Portal')

PS. If you using CRA your jest setup file is in src/setupTests.js

0
On

You can do 2 different things:

In .storybook add a new DOM element:

let modalRoot = document.createElement("div")
modalRoot.setAttribute("id", "modal-root")
document.querySelector("body")!.appendChild(modalRoot)

Also another thing you can do is to mock document, since the problem is that you are trying to find a dom element that does no exist.