Enzyme: Enzyme does not render DOM tree of higher order components with mount

Created on 1 Jun 2017  路  7Comments  路  Source: enzymejs/enzyme

Version 2.7.1.

I have defined a higher-order component called persistChanges, and am using mount to test lifecycle calls around a mock object called WrappedComponent in a Node environment (i.e. without jsdom).

This is the code that's generating the issue, in a nutshell:
```jsx
const simpleComponent = mount();
console.log(simpleComponent.debug())

// correctly yields the expected DOM output:
//
//


// Default text to display when no data is available.
//

//

const enhancedComponent = persistChanges(WrappedComponent);
// enhancedComponent merely renders WrappedComponent
const renderedComponent = mount();
console.log(enhancedComponent.debug());
// yields just

**Subsequent tests for children on enhancedComponent, including `.find()`, `.children()`, `.text()`, etc. all return empty.** The tests in question (using Jest as the assertion library):
```jsx
// fails with count 0 for enhancedComponent, but passes with count 1 for WrappedComponent
test('check length of children', () => {
  expect(renderedComponent.children().length)
  .toBe(1);
});

// fails with received response "" for enhancedComponent, but passes with WrappedComponent
test('fires a request and receives no data from cache', () => {
  expect(renderedComponent.text())
  .toBe('Default text to display when no data is available.');
});

The same tests pass for the WrappedComponent, even though enhancedComponent merely renders WrappedComponent. I can't find the div className='test' /> component in enhancedComponent, and, worse, .children() seems to think nothing is there.

This is the code for the HOC (with lifecycle methods removed - removing them did not alter this behaviour):

function persistChanges(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: {},
      };
   }

    render() {
      return <WrappedComponent {...this.state.data} />;
    }
  };
}

This is the WrappedComponent (also with lifecycle methods removed):

class WrappedComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      textToSave: 'This is the data we want to save',
      currentText: 'Default text to display when no data is available.',
    };
  }

  getDataToPersist() {
    return { currentText: this.state.textToSave };
  }

  render() {
    return (<div className="test">{this.state.currentText}</div>);
  }
}

I am fairly certain there must be something I am doing wrong, as support for HOCs with mount should be straightforward. I have scoured the documentation, and cannot find any similar resolved issue (everything with HOCs appears to be about usage with shallow, which I am not using).

invalid question

Most helpful comment

Thanks for confirming.

One more guess: components with a lowercased name are DOM elements; custom elements must start with an uppercase letter - ie, if you name it "EnhancedComponent", not "enhancedComponent", what happens?

All 7 comments

(updated your OP to include triple backticks, so there's proper syntax highlighting)

When you say "correctly yields the expected DOM output:" but then it contains "", it seems like your expectations are off. debug doesn't contain DOM output, or else it wouldn't contain "WrappedComponent", which isn't a DOM element.

What does .html() look like?

Thanks!

With .html(), enhancedComponent looks as so:

<enhancedcomponent></enhancedcomponent>

and for WrappedComponent, it prints

<div class="test">Default text to display when no data is available.</div>

My point about 'expected DOM structure' was that the full render tree seems to be correctly generated in one case, and not so in the other.

Gotcha, that makes sense.

Any chance if you add a displayName to the persistChanges HOC that it changes things? Currently you're returning an anonymous class with no displayName.

It makes no difference.

function persistChanges(WrappedComponent) {
  const generatedComponent = class extends Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: {},
      };
    }

    render() {
      return <WrappedComponent {...this.state.data} />;
    }
  };
  generatedComponent.displayName = `foo`;
  return generatedComponent;
}

still prints with .html

<enhancedcomponent></enhancedcomponent>

Thanks for confirming.

One more guess: components with a lowercased name are DOM elements; custom elements must start with an uppercase letter - ie, if you name it "EnhancedComponent", not "enhancedComponent", what happens?

That fixes it. I can't believe I overlooked that. Thank you!

I finally found a very good solution to get a wrapper from a decorated component. For shallowed components you can use dive() but there is no similar method for mounted components. This is the solution I did:

const wrapper = mount(shallow(<MyComponent />).get(0))

Works like a charm :)

Was this page helpful?
0 / 5 - 0 ratings