Enzyme: Unable to find Component by displayName when using React.forwardRef

Created on 10 Nov 2018  Â·  4Comments  Â·  Source: enzymejs/enzyme

Current behavior

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.

Test:

  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");
  });

Default approach: (Above test fails)

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;

Approach #1: (Above test fails)

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;

Output of wrapper.debug():

<div className="container">
  <ForwardRef(Button) className="btn">
    Text here
  </ForwardRef(Button)>
</div>

Approach #2:

(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

Output of wrapper.debug() In the parentComponent:

<div className="container">
  <Button className="btn">
    Text here
  </Button)>
</div>

Output of wrapper in the childComponent:

ShallowWrapper()

Output of wrapper.debug() In the childComponent:

''

Output of wrapper.find('Button') In the childComponent:

ShallowWrapper()

Output of wrapper.find(Button) In the childComponent:

ShallowWrapper()

Expected behavior

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

Your environment

Mac OS High Sierra 10.13.6
Mac Book Pro

API

shallow

Version

| library | version
| ------------------- | -------
| enzyme | @3.6.0
| react | @16.5.2
| react-dom@ | 16.5.2
| react-test-renderer | @16.5.2

Adapter

| library | version
| ------------------- | -------
|enzyme-adapter-react-16 | @1.5.0
| enzyme-adapter-utils | @1.8.0

Need To Reproduce

All 4 comments

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

Was this page helpful?
0 / 5 - 0 ratings