Describe the bug
Ref is not being forwarded by WrappedComponent to the wrapped component
To Reproduce
// A.js
class A extends React.PureComponent {
render () {
return <div>FOO</div>
}
}
// B.js
class B extends React.PureComponent {
render () {
return <A ref={this.props.forwardedRef} />
}
}
const BForwarded = React.forwardRef((props, ref) => (
<B {...props} forwardedRef={ref} />
))
// B.test.js
it('should forward ref to A', () => {
const ref = React.createRef()
mount(<BForwarded ref={ref} />)
expect(ref.current).toBeInstanceOf(A)
})
FAIL B.test.js
โ should forward ref to A
expect(value).toBeInstanceOf(constructor)
Expected constructor: A
Received constructor: WrapperComponent
In the example above, ref.current is an instance of WrapperComponent which is an internal enzyme class returned by the createMountWrapper HOC.
library | version
-- | --
Enzyme | 3.6.0
React | 16.4.2
Expected behavior
The ref should be passed from B to A therefore the test above should not fail
Possible solution
A way to fix this issue would be to forward refs in the createMountWrapper HOC:
export default function createMountWrapper(node, options = {}) {
const { adapter } = options;
class WrapperComponent extends React.Component {
// ...
render() {
const { Component, forwardedRef } = this.props;
const { mount, props } = this.state;
if (!mount) return null;
return (
<Component {...props} ref={forwardedRef} />
);
}
}
// ...
return React.forwardRef((props, ref) => {
return <WrapperComponent {...props} forwardedRef={ref} />
});
)
While that fixes things for your test, it ends up breaking hundreds of other ones :-/
You mean the fix I suggested? It is a breaking change so I understand it might. I'm curious about which hundreds of other tests it might break. I'm saying that because, by not forwarding refs, you'll always get instances of WrappedComponent which is probably useless, I can't believe someone is actually expecting to get those.
I don't think people are directly looking at that instance, but the component stack changes, which means traversals change, etc.
I've added failing tests here: https://github.com/airbnb/enzyme/compare/forward_ref_tests
Just got hit by this today when testing component by mounting it as root in mount. I had other tests with forwardRef successfully passed though, because I wrapped it under other component.
// this will fail
it('should forward ref to A', () => {
const ref = React.createRef()
mount(<BForwarded ref={ref} />)
expect(ref.current).toBeInstanceOf(A)
});
// while this is a success!
it('should forward ref to A', () => {
const ref = React.createRef()
mount(<div><BForwarded ref={ref} /></div>)
expect(ref.current).toBeInstanceOf(A)
});
So it can be a workaround for now while waiting for the fix
Thanks!
@panjiesw Works for me, thanks! A React.Fragment is also sufficient.
Useful to me, thank!
Somehow these tests are passing now, yay!
Awesome o/
Most helpful comment
Just got hit by this today when testing component by mounting it as root in
mount. I had other tests withforwardRefsuccessfully passed though, because I wrapped it under other component.So it can be a workaround for now while waiting for the fix