Skip to content

Refs with react-test-renderer (TypeError: Cannot read property 'ownerDocument' of null) #9244

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

Closed
aaronplanell opened this issue Mar 23, 2017 · 12 comments

Comments

@aaronplanell
Copy link

Do you want to request a feature or report a bug?
A bug in snapshots.

What is the current behavior?
It seems that there is a problem with the snapshots when you use other libraries like antd. The snapshot launch:

TypeError: Cannot read property 'ownerDocument' of null

If I mock all the library, the snapshot is almost empty.

If the current behavior is a bug, please provide the steps to reproduce and either a repl.it demo through https://repl.it/languages/jest or a minimal repository on GitHub that we can yarn install and yarn test.
You can download this example of my Github account: https://github.com/aaronplanell/ant-design-issue_5428

$ git clone https://github.com/aaronplanell/ant-design-issue_5428
$ cd ant-design-issue_5428
$ npm install
$ npm test

In the README.md you will find, step by step, the full proccess.

Besides, I opened an issue to antd: ant-design/ant-design#5428 and @yesmeck said me that was a problem of Jest/react-test-renderer.

Then I opened an issue to jest: jestjs/jest#3195. This time @thymikee confirmed what @yesmeck said, it's a problem of react-test-renderer.

What is the expected behavior?
I expect that the snapshot have the full HTML code in JSON format. It has no sense that snapshots fail if a library that you use (and works!) use refs.

Please provide your exact configuration and mention your Jest, node, yarn/npm version and operating system.
I use this dependencies:

  "devDependencies": {
    "react-scripts": "0.9.5"
  },
  "dependencies": {
    "antd": "^2.8.2",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-test-renderer": "^15.4.2"
  },

With this OS: Ubuntu 16.04

@yesmeck
Copy link

yesmeck commented Mar 23, 2017

I think it's a intended behavior, see #7371 . Try enzyme. :)

@gaearon
Copy link
Collaborator

gaearon commented Mar 23, 2017

No, #7371 is unrelated. #7371 is about using findDOMNode() but this is not what this issue is about.

The behavior is intentional but there's a workaround. You need to figure out which DOM nodes the library you're using expects, and mock them to the extent you care about (i.e. enough to make test pass).

You can read about mocking refs for snapshot testing here.

Hope this helps!

@gaearon gaearon closed this as completed Mar 23, 2017
@aaronplanell
Copy link
Author

Hello!

Thanks @gaearon for your quick answer. Then, if I'm not confused, not only I must check my refs. I have, besides, check the refs of the packages I will use. And then, if those packages are using packages that are using refs, repeate the process.

For instance, in my case:

  1. I have a project that uses antd.
  2. antd is a project that uses rc-tabs.
  3. rc-tabs is using refs.

Then I must check the sources of rc-tabs searching for the refs references and mock all of them.

For example, the file InkTabBarMixin have:

function componentDidUpdate(component, init) {
  const refs = component.refs;
  const wrapNode = refs.nav || refs.root;
  const containerOffset = offset(wrapNode);
  const inkBarNode = refs.inkBar;
  const activeTab = refs.activeTab;
  const inkBarNodeStyle = inkBarNode.style;
  const tabBarPosition = component.props.tabBarPosition;

If I'm not confused I must make a createNodeMock with nav, root, inkBar, activeTab,... (in fact, is the offset funcion that fails because of wrapNode is null).

Don't get me wrong, I'm a strong advocate or React & Jest, but I think this is getting seriously complicated when I just want to snapshot my component... It forces me to analyze not only my code, besides, the code of the packages, and the packages of the packages!

Probably I'm confused and there is a better way to avoid this.

Thanks for your patiente @gaearon , @yesmeck & @thymikee.

Best regards!!!

@aaronplanell
Copy link
Author

Well,... I'm sure that I won't get a solution, but at least I'm waiting for an answer 😢

Please, one last question, if I want to generate snapshots with Jest, then I must look for all the refs of the packages (and the packages of the packages) that I use and mock its nodes with createNodeMock. In the example above: refs.nav, refs.root, refs.inkBar, refs.activeTab,... Is that OK?

Thanks in advance.

@yesmeck
Copy link

yesmeck commented Mar 27, 2017

@aaronplanell See my comment.

@gaearon
Copy link
Collaborator

gaearon commented Mar 27, 2017

Thanks @gaearon for your quick answer. Then, if I'm not confused, not only I must check my refs. I have, besides, check the refs of the packages I will use. And then, if those packages are using packages that are using refs, repeate the process.

I don’t mean that you need to literally check every ref. I mean that you can write a snapshot test, and if it fails, look at which methods are expected on refs, and mock them. I don’t think you’ll find more than a few such places.

If I'm not confused I must make a createNodeMock with nav, root, inkBar, activeTab,... (in fact, is the offset funcion that fails because of wrapNode is null).

You don’t need to hardcode nav, root, etc, specifically. Just the DOM APIs that component relies on (e.g. getBoundingClientRect() and ownerDocument with a few properties on it).

If you use Jest, you can also mock any components, e.g.

jest.mock('third-party-library/ComponentThatReallyReliesOnDom', () => {
  return (props) => <div>{props.children}</div>; // Just pretend it renders children
});

This would let you “skip” components that are too coupled to the DOM.
Similarly you can try mocking away that particular mixin.

@aaronplanell
Copy link
Author

Thanks @gaearon for your answer!

I wrote:

jest.mock('rc-tabs/lib/ScrollableInkTabBar.js', () => {
  return (props) => <div>{props.children}</div>;
});

And then I found:

  ● snapshot matchs

    Invariant Violation: getNodeFromInstance: Invalid argument.
      
      at invariant (node_modules/fbjs/lib/invariant.js:44:15)
      at Object.getNodeFromInstance (node_modules/react-dom/lib/ReactDOMComponentTree.js:162:77)
      at findDOMNode (node_modules/react-dom/lib/findDOMNode.js:49:41)
      at Tabs.componentDidMount (node_modules/antd/lib/tabs/index.js:99:49)

I think I found another stone in my path 😢

If I am not confussed, working with ReactTestRenderer, refs can work but findDOMNode() can't (see #8324). I think I arrived to a cul-de-sac.

Thanks all of you for your help.

Best regards.

@gaearon
Copy link
Collaborator

gaearon commented Mar 29, 2017

If I am not confussed, working with ReactTestRenderer, refs can work but findDOMNode() can't (see #8324). I think I arrived to a cul-de-sac.

Yes. But you can mock it too.

jest.mock('react-dom', () => ({
  findDOMNode() { return {} /* or whatever */; },
  // if your tree depends on more methods add stubs here
}));

aaronplanell added a commit to aaronplanell/ant-design-issue_5428 that referenced this issue Mar 30, 2017
@aaronplanell
Copy link
Author

aaronplanell commented Mar 30, 2017

Perfect!!!

I wrote:

jest.mock('rc-tabs/lib/ScrollableInkTabBar.js', () => {
  return (props) => <div>{props.children}</div>;
});

jest.mock('react-dom', () => ({
  findDOMNode() { return null; },
  render() { return null; }
}));

As you said and now I have this snapshot:

<div
  className="App">
  <div
    className="ant-tabs ant-tabs-top ant-tabs-line"
    style={Object {}}>
    <div />
    <div
      className="ant-tabs-content ant-tabs-content-animated"
      style={
        Object {
          "marginLeft": "0%",
        }
      }>
      <div
        aria-hidden="false"
        className="ant-tabs-tabpane ant-tabs-tabpane-active"
        role="tabpanel"
        style={undefined}>
        Content of Tab Pane 1
      </div>
      <div
        aria-hidden="true"
        className="ant-tabs-tabpane ant-tabs-tabpane-inactive"
        role="tabpanel"
        style={undefined} />
      <div
        aria-hidden="true"
        className="ant-tabs-tabpane ant-tabs-tabpane-inactive"
        role="tabpanel"
        style={undefined} />
    </div>
  </div>
</div>

Now I can check that I have three tabas and make other snapshots for their children.

Thanks a lot @gaearon 👍

@gaearon
Copy link
Collaborator

gaearon commented Mar 30, 2017

Glad it helped!

@mrchief
Copy link

mrchief commented Jun 19, 2018

I think a far easier option would to be use Enzyme instead of react-test-renderer. Mocking can get out of hand pretty quickly if you're working on any libs that have a lot of components - (e.g. any material design based ones).

@jianwu
Copy link

jianwu commented Jun 17, 2023

I faced the same issue when write test for grafana plugin. Based on previous suggestion, I solve the issue with following mock:

jest.mock('@grafana/ui', () => ({
  ...jest.requireActual('@grafana/ui'),
  Tooltip(props:any) { return <div>{props.children}</div> },
}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants