Unable to find a childComponent by displayName when shallow rendering the parent while using wrapper.find("displayName") unless displayName includes ForwardRef(childComponent) || ForwardRef
I'm aware of some issues regarding forwardRef, and displayName so I've tried a few different approaches.
it("renders text", () => {
component = shallow(<Parent {...props} />).find("Button");
component.simulate("click");
expect(props.toggleText).to.have.been.called;
expect(component.children().text()).to.contain("text");
});
childComponent only discoverable via find by "ForwardRef"
const Button = forwardRef((props, ref) => (
return (
<button
className={props.className}
ref={ref}
>
<span>{children}</span>
</button>
)
));
export default Button;
childComponent only discoverable via find by "ForwardRef(Button)"
const Button = (props, ref) => {
const {
className,
} = props;
return (
<button
className={className}
ref={ref}
>
<span>{children}</span>
</button>
);
};
const buttonWithRefForwarding = forwardRef(Button);
buttonWithRefForwarding.displayName = "Button";
export default buttonWithRefForwarding;
<div className="container">
<ForwardRef(Button) className="btn">
Text here
</ForwardRef(Button)>
</div>
(Above test passes with this approach in the parentComponent unit test above, but fails right out of the gate for the Button unit tests)
const Button = function Button(Component) {
const returnedButton = (props) => {
const {
className,
} = props;
return (
<button
className={className}
ref={ref}
>
<span>{children}</span>
</button>
);
function forwardRef(props, ref) {
return returnedButton;
}
return React.forwardRef(forwardRef);
}
}
export default Button;
Failing Button Unit test:
describe("<Button />", () => {
let component;
let props = {
className: "class"
}
beforeEach(() => {
component = shallow(<Button {...props} >{children}</Button>);
});
These both fail -->
it("should have a displayName, () => {
console.log(component.displayName) <-- undefined
console.log(component.debug()) <-- '{{ $$typeof: Object(Symbol(react.forward_ref)_16.czyhiszjh),
render: [Function: forwardRef] }}'
})
it("should set displayName", () => {
const button = mount(
<div>
<Button {...props}>{children}</Button>
</div>
);
expect(button.find("Button")).to.have.length(1);
});
Console output on failure:
✗ should set displayName
Invariant Violation: Objects are not valid as a React child (found: object with keys {$$typeof, render}). If you meant to render a collection of children, use an array instead.
in Button
in div (created by WrapperComponent)
in WrapperComponent
<div className="container">
<Button className="btn">
Text here
</Button)>
</div>
ShallowWrapper()
''
ShallowWrapper()
ShallowWrapper()
Users should be able to use wrapper.find('displayName") to make assertions on a childComponent that uses React.forwardRef without having to set the displayName with ForwardRef(childComponent) || ForwardRef
Mac OS High Sierra 10.13.6
Mac Book Pro
shallow
| library | version
| ------------------- | -------
| enzyme | @3.6.0
| react | @16.5.2
| react-dom@ | 16.5.2
| react-test-renderer | @16.5.2
| library | version
| ------------------- | -------
|enzyme-adapter-react-16 | @1.5.0
| enzyme-adapter-utils | @1.8.0
Approach 1 fails because that's not how React.forwardRef works - approach 2 is correct.
With that approach, can you show the code for wrapper, wrapper.debug(), and then wrapper.find(Button) vs wrapper.find('Button')?
This has been resolved. The issue was needing a clean install after updating all dependencies.
Running rm -rf node_modules followed by npm i was the solution.
Appreciate your help.
This appears to be working for me with latest enzyme and the enzyme adapters. Can you try updating enzyme-adapter-react-16?
I'll close this with some more test cases :-)