React: Test Utils renderIntoDocument issue with refs. Invariant Violation: addComponentAsRefTo(...)

Created on 11 Jan 2017  路  3Comments  路  Source: facebook/react

Below is my simple demo app to showcase the issue I am experiencing.

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';

var jsdom = require("jsdom").jsdom;

global.document = jsdom("hello world");
global.window = document.defaultView;

TestUtils.renderIntoDocument(<div><div ref="test">test</div></div>);

Basically when I have a ref on any element found in the TestUtils.renderIntoDocument function the following error is being thrown:

Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).
      at invariant (test/node/index.test.js:108:16)
      at Object.addComponentAsRefTo (test/node/index.test.js:60386:48)
      at attachRef (test/node/index.test.js:60612:17)
      at Object.ReactRef.attachRefs (test/node/index.test.js:60631:6)
      at ReactCompositeComponentWrapper.attachRefs (test/node/index.test.js:3156:13)
      at CallbackQueue.notifyAll (test/node/index.test.js:28619:23)
      at ReactReconcileTransaction.close (test/node/index.test.js:60498:27)
      at ReactReconcileTransaction.closeAll (test/node/index.test.js:22529:26)
      at ReactReconcileTransaction.perform (test/node/index.test.js:22476:17)
      at batchedMountComponentIntoNode (test/node/index.test.js:31777:16)
      at ReactDefaultBatchingStrategyTransaction.perform (test/node/index.test.js:22463:21)
      at Object.batchedUpdates (test/node/index.test.js:59478:20)
      at Object.batchedUpdates (test/node/index.test.js:1095:21)
      at Object._renderNewRootComponent (test/node/index.test.js:31940:19)
      at Object._renderSubtreeIntoContainer (test/node/index.test.js:32019:33)
      at Object.render (test/node/index.test.js:32040:24)
      at Object.renderIntoDocument (test/node/index.test.js:60838:22)
      at Context.<anonymous> (test/node/index.test.js:35876:53)

I checked if I have multiple copies of React in my project but as you can see from my package.json only React 15.4.1 is installed.

{
  "name": "demo-project",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "react": "^15.4.1",
    "react-addons-test-utils": "^15.4.1",
    "react-dom": "^15.4.1"
  },
  "devDependencies": {
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-stage-0": "^6.16.0",
    "jsdom": "^9.9.1"
  }
}

Additionally this is the babelrc

{ "presets": ["react", "stage-0", "es2015"] }

Is this the intended behaviour or a bug since using refs in the context of TestUtils.renderIntoDocument is an important feature.

Most helpful comment

The error message contains description of the problem:

You might be adding a ref to a component that was not created inside a component's render method

That's just how string refs work. They only work inside classes (and are discouraged anyway).
Otherwise, where would you expect the ref to be set? How would you read it?

Callback refs don't suffer from that problem. You can use them just fine:

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';

var jsdom = require("jsdom").jsdom;

global.document = jsdom("hello world");
global.window = document.defaultView;

var div;
TestUtils.renderIntoDocument(<div><div ref={el => div = el}>test</div></div>);

// You can do something with div now.

I hope this helps!

All 3 comments

The error message contains description of the problem:

You might be adding a ref to a component that was not created inside a component's render method

That's just how string refs work. They only work inside classes (and are discouraged anyway).
Otherwise, where would you expect the ref to be set? How would you read it?

Callback refs don't suffer from that problem. You can use them just fine:

import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';

var jsdom = require("jsdom").jsdom;

global.document = jsdom("hello world");
global.window = document.defaultView;

var div;
TestUtils.renderIntoDocument(<div><div ref={el => div = el}>test</div></div>);

// You can do something with div now.

I hope this helps!

@gaearon What if the goal is to add a ref to a component that wasn't created a component's render method? For example, a "click-outside" component like this one.

You can use callback refs for this use case, just like that component already does.
That's the nice thing about callback refs: they don't care where element is created.

Was this page helpful?
0 / 5 - 0 ratings