Error when rendering React Portal with Storyshots
Asked Answered
N

3

8

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.

Newport answered 4/9, 2018 at 9:57 Comment(2)
Just in case, maybe it is a silly comment but just to be sure: in your markup(html) do you have a element with id = 'modal-root'?Sade
Did you got the answer for this? It will be great to update and close this questionDigitalism
D
6

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.

Digitalism answered 3/3, 2020 at 8:44 Comment(0)
L
1

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

Lipase answered 5/7, 2019 at 12:1 Comment(0)
P
1

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

Prerogative answered 20/4, 2021 at 7:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.