Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
laplacesdemon opened this issue Nov 2, 2018 · 10 comments

Comments

@laplacesdemon
Copy link

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.

@welcome
Copy link

welcome bot commented Nov 2, 2018

👋 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.

@laplacesdemon
Copy link
Author

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.

@dsernahiguita
Copy link

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.

@layershifter
Copy link
Member

layershifter commented Jan 29, 2019

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.

@jaynetics
Copy link

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?

@layershifter
Copy link
Member

@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: facebook/react#7371

Also you can try to use mock, facebook/react#7371 (comment)

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

@jaynetics
Copy link

@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.

@layershifter
Copy link
Member

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".

@muratbeser
Copy link

muratbeser commented Apr 2, 2019

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;

@layershifter
Copy link
Member

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.

@Semantic-Org Semantic-Org locked as off-topic and limited conversation to collaborators Apr 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants