Semantic-ui-react: Error during Jest unit test run after upgrading to react 16.6.0: Invariant Violation: Unable to find node on an unmounted component

Created on 3 Nov 2018  ·  10Comments  ·  Source: Semantic-Org/Semantic-UI-React

Bug Report

Steps

I have upgraded to react 16.6.0 from 16.5.0. My unit tests were working fine on 16.5.0 but after the upgrade I received the following error caused by the component called Ref in Popup (see the entire stack trace below).

The code under test looks like this:

const reason = '...';
const outcomeView = (<Label size={size} >{text}</Label>);
return <Popup trigger={outcomeView} content={reason} />;

And the test code is like this:

const component = renderer.create(<OperationDetail {...data} />);
    const tree = component.toJSON();
    expect(tree).toMatchSnapshot();

I just included the relevant parts.

Expected Result

Tests run as normal.

Actual Result

Below error happened during the tset run.

Version

0.83.0

Testcase

 FAIL  src/components/shared/buildSummaries/InstallContentTask/OperationDetail.spec.jsx
  ● <OperationDetail /> › should display data of failure

    Invariant Violation: Unable to find node on an unmounted component.

      at invariant (../node_modules/react-dom/cjs/react-dom.development.js:55:15)
      at findCurrentFiberUsingSlowPath (../node_modules/react-dom/cjs/react-dom.development.js:4161:30)
      at findCurrentHostFiber (../node_modules/react-dom/cjs/react-dom.development.js:4269:23)
      at findHostInstanceWithWarning (../node_modules/react-dom/cjs/react-dom.development.js:18296:21)
      at findDOMNode (../node_modules/react-dom/cjs/react-dom.development.js:18774:14)
      at Ref.componentDidMount (../node_modules/semantic-ui-react/dist/commonjs/addons/Ref/Ref.js:49:56)
      at commitLifeCycles (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6955:22)
      at commitAllLifeCycles (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8164:7)
      at HTMLUnknownElement.callCallback (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2264:14)
      at invokeEventListeners (../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
      at HTMLUnknownElementImpl._dispatch (../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:126:9)
      at HTMLUnknownElementImpl.dispatchEvent (../node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
      at HTMLUnknownElementImpl.dispatchEvent (../node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:36:27)
      at HTMLUnknownElement.dispatchEvent (../node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
      at Object.invokeGuardedCallbackDev (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2314:16)
      at invokeGuardedCallback (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:2363:31)
      at commitRoot (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:8334:7)
      at completeRoot (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9699:3)
      at performWorkOnRoot (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9627:9)
      at performWork (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9531:7)
      at performSyncWork (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9503:3)
      at requestWork (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9391:5)
      at scheduleWork (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9186:5)
      at scheduleRootUpdate (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9795:3)
      at updateContainerAtExpirationTime (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9822:10)
      at updateContainer (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9833:10)
      at Object.create (../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10367:5)
      at Object.it (src/components/shared/buildSummaries/InstallContentTask/OperationDetail.spec.jsx:21:51)
          at new Promise (<anonymous>)
      at Promise.resolve.then.el (../node_modules/p-map/index.js:46:16)
      at process._tickCallback (internal/process/next_tick.js:68:7)

  <OperationDetail />
    ✕ should display data of failure (40ms)
    ✓ should display data of success (23ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        0.387s, estimated 14s
Ran all test suites matching /shared/buildSummaries/InstallContentTask/OperationDetail.spec/.

  console.error ../node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6820
    The above error occurred in the <Ref> component:
        in Ref (created by Portal)
        in Portal (created by Popup)
        in Popup (at OutcomeLabel/index.jsx:63)
        in OutcomeLabel (at OperationDetail.jsx:11)
        in ResultLabel (at OperationDetail.jsx:21)
        in div (created by ListItem)
        in ListItem (at OperationDetail.jsx:19)
        in div (created by List)
        in List (at OperationDetail.jsx:18)
        in Item (at OperationDetail.jsx:69)
        in div (created by AccordionContent)
        in AccordionContent (at ClosablePanel/index.jsx:86)
        in div (created by AccordionAccordion)
        in AccordionAccordion (created by Accordion)
        in Accordion (at ClosablePanel/index.jsx:75)
        in ClosablePanel (at OperationDetail.jsx:68)
        in div (created by GridColumn)
        in GridColumn (at ColumnedRow.jsx:9)
        in div (created by GridRow)
        in GridRow (at ColumnedRow.jsx:7)
        in ColumnedRow (at OperationDetail.jsx:67)
        in div (created by Grid)
        in Grid (at GridLayout/index.jsx:12)
        in GridLayout (at OperationDetail.jsx:66)
        in OperationDetail (at OperationDetail.spec.jsx:21)

    Consider adding an error boundary to your tree to customize error handling behavior.
    Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

needs engineering

Most helpful comment

Hi
I have the same issue :(.
I muss to return to the version react-dom: 16.5.2 and react: 16.5.0 because the component Popup from react-semantic is not working any more.

error:
Invariant Violation: Unable to find node on an unmounted component.

All 10 comments

👋 Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you've completed all the fields in the issue template so we can best help.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

I've reproduced the issue here: https://codesandbox.io/s/l4wmq19n2m

Digging a bit deeper, I see that it's caused by findDOMNode(this) on the Ref component: https://github.com/Semantic-Org/Semantic-UI-React/blob/master/src/addons/Ref/Ref.js

Usage of findDOMNode is deprecated in strictmode as of 16.6.0 See this link also this one. It won't work with the unmounted components.

Hi
I have the same issue :(.
I muss to return to the version react-dom: 16.5.2 and react: 16.5.0 because the component Popup from react-semantic is not working any more.

error:
Invariant Violation: Unable to find node on an unmounted component.

Ref component will support forwardRef() API in next release. This means that this code should not produce any warnings:

const ExampleButton = React.forwardRef((props, ref) => (
  <div>
    <button {...props} ref={ref} />
  </div>
))

render(<Popup trigger={<ExampleButton />} />)

See #3405 for more details.

i am seeing this error on production with 0.86.0 and react 16.8.1, even though i can't reproduce it unfortunately.

@layershifter are you suggesting that every trigger prop should be passed a React.forwardRef now to be safe?

if so, maybe the docs should be updated. or could semantic-ui-react take care of this and wrap whatever is passed in a forwardRef?

@jaynetics if you need to pass a Popup with trigger in your tests with react-test-renderer there are no any other way than wrap it with React.forwardRef() because findDOMNode() doesn't work correctly with it: https://github.com/facebook/react/issues/7371

Also you can try to use mock, https://github.com/facebook/react/issues/7371#issuecomment-323516392

jest.mock('react-dom', () => ({
    findDOMNode: () => ({
      getContext: jest.fn(),
    }),
  })
);

@layershifter i'm just seeing the error in error reports from production. i'm wondering whether i need to do the wrapping in my production code.

i can't even trigger the error in jest. i've tried various renderers including react-test-renderer, and <Popup trigger={<Label content='foo'/>} content='bar'/> doesn't throw console errors using the library versions mentioned above.

Sorry, I completely lost with it. This issue is related to issues with Popup and react-test-renderer. I've tested it with [email protected] and [email protected], it's not reproducible more: https://codesandbox.io/s/q9mo5o1z54

Local Jest passes, too. I don't understand how this issue is related to "seeing the error in error reports from production".

Hi I'm also having this issue on Dropdowninside a menu

import React from 'react';
import PropTypes from 'prop-types';
import { Menu, Dropdown, Icon } from 'semantic-ui-react';
import Nav from '../Nav';
import useLayout from 'shared-context/layout/useLayout.hook';
/**
 *
 * @todo I should update this into non-react version so
 * @param {*} props
 */
const SubMenuItem = props => {
  if (props.items && props.items.length >= 1) {
    return (
      <Dropdown
        item
        trigger={
          <div className="icon">
            <Icon name={props.icon} />
            {props.name || props.content}
          </div>
        }
      >
        <Dropdown.Menu>
          {props.items.map(({ name, icon, text, to, ...rest }, index) => {
            return (
              <Dropdown.Item
                as={Nav}
                to={to}
                icon={icon}
                key={`submenu-${index}`}
                name={name}
                text={name || text}
                {...rest}
              />
            );
          })}
        </Dropdown.Menu>
      </Dropdown>
    );
  } else {
    return <React.Fragment />;
  }
};

const M = props => {
  const { placement } = props;
  const [layout] = useLayout();
  const items = placement === 'top' ? layout.menu : layout.sideMenu;
  const menuStyle =
    placement === 'top'
      ? { attached: 'bottom' }
      : {
        pointing: true,
        vertical: true,
        fluid: true,
        style: { marginBottom: '1rem' }
      };
  if (!items || items.length < 1) {
    return <React.Fragment />;
  } else if (React.isValidElement(items)) {
    // if its an React element render
    return items;
  } else {
    return (
      <Menu {...menuStyle}>
        {items
          .map(n => ({ ...n, as: Nav }))
          .map(item => {
            if (React.isValidElement(item)) {
              return item;
            } else if (!!item.header) {
              return (
                <Menu.Item key={item.key || item.name}>
                  <Menu.Header>{item.content || item.name}</Menu.Header>{' '}
                  <Menu.Menu>
                    {item.items.map(i =>
                      React.isValidElement(i) ? (
                        i
                      ) : (
                        <Menu.Item key={i.key || i.name} {...i} />
                      )
                    )}
                  </Menu.Menu>
                </Menu.Item>
              );
            } else if (item.items && items.length >= 1) {
              return <SubMenuItem {...item} />;
            } else {
              return (
                <Menu.Item key={item.key || item.name} as={Nav} {...item} />
              );
            }
          })}
      </Menu>
    );
  }
};

M.defaultProps = {
  placement: 'side',
  items: []
};

const MenuShape = PropTypes.shape({
  /// array can take props
  exact: PropTypes.bool,
  header: PropTypes.bool,
  name: PropTypes.string.isRequired,
  content: PropTypes.string.isRequired,
  to: PropTypes.string.isRequired
});
M.propTypes = {
  placement: PropTypes.oneOf(['top', 'side']),
  items: PropTypes.oneOfType([
    PropTypes.element, // items can direct element
    PropTypes.arrayOf(
      PropTypes.oneOfType([
        PropTypes.element, // array can take an element,
        MenuShape
      ])
    )
  ])
};

export default M;

Sorry, but we don't have time to debug your code. If you experiencing an issue, please fill a new issue and create a minimal repro on CodeSandbox.

Was this page helpful?
0 / 5 - 0 ratings