Do you want to request a feature or report a bug?
Bug
What is the current behavior?
If you try to access the .root of a component tree of a component created with forwardRef, you will get an error
Unexpected object passed to ReactTestInstance constructor
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
A minimal example is simply a component created with forwardRef:
import React from "react";
export default React.forwardRef(() => <div>hello</div>);
Now if you try to use create from react-test-renderer and access .root, you will get
Unexpected object passed to ReactTestInstance constructor (tag: 14). This is probably a bug in React.
import React from "react";
import { create } from "react-test-renderer";
import Hello from "./Hello";
it("test forwardRef component", () => {
const tree = create(<Hello />);
expect(tree.root);
});
https://codesandbox.io/s/vm98x95wx5
What is the expected behavior?
You should be able to create components created with forwardRef with the test renderer.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
16.3 using jest (forwardRef did not exist previously).
I am running into a similar problem with testing components that render forwardRef nodes. I am using this feature to forward refs through HOCs.
In my use-case, I am working in a library that exports components returned by a HOC using forwardRef. Consumers import these components and use them in their codebase. Unfortunately, when the consumer writes a test that uses create from react-test-renderer and tries to findByType, nothing is found. I have created a codesandbox example but I'll illustrate the problem below.
library/theme
const withTheme = WrappedComponent =>
React.forwardRef((props, ref) => <WrappedComponent ref={ref} theme="light" {...props} />);
library/button
const InternalButton = props => <button {...props} />
const ButtonWithTheme = withTheme(InternalButton);
export default ButtonWithTheme;
consumer.js
import Button from 'library/button';
const App = () => <Button>Click me</Button>;
consumer.test.js
import Button from 'library/button';
import App from './consumer';
it('should render button that says Click me', () => {
const { root } = TestRenderer.create(<App />);
// this will not find anything
const button = root.findByType(Button);
expect(button.props.children).toEqual('Click me');
});
I had a look at what is returned by toTree() and there is no entry for Button in the above example. This means that consumers cannot write tests that find and assert things about these components. Without using forwardRef the test works as expected.
I am not very familiar with the react-test-renderer package, but my feeling is that it should treat components created by forwardRef in a more similar way to functional/class components. Let me know if I can help out with a fix for this.
Thanks, the use case for this is clear. It's not that we don't want it鈥攊t was just an omission.
A PR to fix this is welcome!
@petegleeson up for it? it should be essentially a tweak of your PR to my enzyme PR (lol)
Appreciate the speedy response @gaearon !
@jquense it would be great to talk about how enzyme could use react-test-renderer directly rather than it's own version.
I agree! Tho that's more of conversation to be had with an enzyme maintainer, I'm just a guy who sends PRs some times. Practically at the moment it's not feasible as the toTree behavior is different from enzes format
Thanks everyone. I would have been happy to create a PR for this but it got done so quickly!
Most helpful comment
Fixed by https://github.com/facebook/react/pull/12725