Fixing the Jest Error, “Invariant Violation: addComponentAsRefTo”

I work on the Build.com React Native app. We’re currently on a push to dramatically increase our test coverage.

Recently, I came across a bug that affects some, but not all, of our tests. Tests fail with the message:

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

What does Facebook say about this error message?

If you follow the link in the error message, the official Facebook explanation of the error is:

This usually means one of two things:

  • You are trying to add a ref to an element that is being created outside of a component’s render() function.
  • You have multiple (conflicting) copies of React loaded (eg. due to a misconfigured NPM dependency)

Here’s a simplified copy of the test that I’m running:

jest.mock('BuildLibrary');
jest.mock('BuildNative');
jest.mock('../../../app/components/AnotherComponent', () => 'AnotherComponent');
jest.mock('react-native-star-rating', () => 'StarRating');
 
jest.unmock('react-native');
import 'react-native';
import React from 'react';
import renderer from 'react-test-renderer';
 
import MyComponent from '../../../app/components/MyComponent';
 
const defaultProps = {
  user: {
    firstName: 'Test',
    lastName: 'Test',
  },
};
 
describe('MyComponent', () => {
  it('should render with required props', () => {
    const tree = renderer.create(
      <MyComponent {...defaultProps} />
    ).toJSON();
    expect(tree).toMatchSnapshot();
  });
 
  it('should render with SEARCH_GRID', () => {
    const tree = renderer.create(
      <MyComponent
        {...defaultProps}
        viewStyle="FULL"
      />
    ).toJSON();
    expect(tree).toMatchSnapshot();
  });
});

Neither of two reasons provided by Facebook seem to answer the problem. I’m not going to post the component code but the app only has one copy of React (I checked all of the dependencies also) and there are no refs anywhere in the component declaration.

What is the real cause of the error?

Honestly, I’m not exactly sure what the real cause of the error is but I did figure out how to fix it.

For some reason,

import renderer from 'react-test-renderer';

will sometimes cause this Invariant Violation. It primarily seems to affect test suites that have multiple tests in them. However, this is not the full explanation because I’ve had other tests with the exact same setup that are testing components that more or less have the same imports and they do not experience this error.

How do I fix the error?

Fixing the error is pretty easy. We’ve now taken to writing all of our test suites this way, in part, to prevent this error from occurring.

The short explanation is that, rather than import the renderer once at the top of the file, you simply require the it in each test.

jest.mock('BuildLibrary');
jest.mock('BuildNative');
jest.mock('../../../app/components/AnotherComponent', () => 'AnotherComponent');
jest.mock('react-native-star-rating', () => 'StarRating');
 
jest.unmock('react-native');
import 'react-native';
import React from 'react';
 
import MyComponent from '../../../app/components/MyComponent';
 
const defaultProps = {
  user: {
    firstName: 'Test',
    lastName: 'Test',
  },
};
 
describe('MyComponent', () => {
  it('should render with required props', () => {
    const tree = require('react-test-renderer').create(
      <MyComponent {...defaultProps} />
    ).toJSON();
    expect(tree).toMatchSnapshot();
  });
 
  it('should render with SEARCH_GRID', () => {
    const tree = require('react-test-renderer').create(
      <MyComponent
        {...defaultProps}
        viewStyle="FULL"
      />
    ).toJSON();
    expect(tree).toMatchSnapshot();
  });
});

I imagine that the multiple requires will probably slow down your test suite a little bit. However, that’s a small price to pay for being able to run full automated test suites against your components.

If speed does become an issue, I’m sure we’ll try to research a better solution. Or we may only use this solution on the tests that specifically require it.

Leave a Comment