Enzyme: Using mount + find with a class selector in 3.x returns an extra element

Created on 8 Feb 2018  路  5Comments  路  Source: enzymejs/enzyme

Current behaviour

Using .find to locate a class on a mounted react element returns 1 extra element than expected: wrapper.find('.class').

class Icon extends React.Component {
  render(){
    return (<span className={this.props.className} />)
  }
}

const wrapper = mount(<Icon className='whatever-name' />)
expect( wrapper.html() ).to.equal('<span class="whatever-name"></span>')
expect( wrapper.find('.whatever-name').length ).to.eql(1)

wrapper.find('.whatever-name').length is equal to 2 though.

An mcve is here: https://github.com/deployable/issue-enzyme3-find-react15

Using .find with the selector span and span.whatever-name works as expected, as demonstrated in the mcve's additional test. Using .find('.class') with shallow also works as expected.

Reading the migration guide alludes to this type of behaviour but I don't understand how it can apply to this specific case of finding a class that should only exist once.

Expected behaviour

wrapper.find('.class') returns the elements with that class applied

Your environment

node v8.9.4 on darwin

API

  • [ ] shallow
  • [x] mount
  • [ ] render

Version

| library | version
| ---------------- | -------
| Enzyme | 3.3.0
| React | 15.6.2
| jsdom | 11.6.2

Adapter

  • [x] enzyme-adapter-react-16
  • [x] enzyme-adapter-react-15
  • [ ] enzyme-adapter-react-15.4
  • [ ] enzyme-adapter-react-14
  • [ ] enzyme-adapter-react-13
  • [ ] enzyme-adapter-react-helper
  • [ ] others ( )

Most helpful comment

This is expected behavior; it's finding both the Icon component and the rendered span. You can use hostNodes to filter the results down to only the host (DOM) nodes that match the query.

The docs and migration guide should probably be updated. Hope that helps!

All 5 comments

This is expected behavior; it's finding both the Icon component and the rendered span. You can use hostNodes to filter the results down to only the host (DOM) nodes that match the query.

The docs and migration guide should probably be updated. Hope that helps!

Thanks, yeah not obvious at first glance but that explains it.

Which is shallow finding then? I was expecting it to be the same for a component.

shallow only finds the rendered html span

A shallow wrapper is what the element renders; a mount wrapper is the component itself, and is children are what it renders.

gotcha, thanks!

So using .hostNodes() at the end of any .find() for a css class selector when using mount to limit the results to only html nodes gets it working as it did in 2.x.

expect( wrapper.find('.whatever-name').hostNodes().length ).to.equal(1)

I'll just add a note that my first steps to debug this test after the upgrade to 3.x were to print each matching element and then print the.html() of each element. In both cases the results were exactly the same for the component and html node. It might be useful include the type, or subclass ReactWrapper for each.

wrapper.find('.whatever-name').map((el,i) => debug(i, el, el.html()))
  test:unit:component:Icon 0 ReactWrapper { length: 1 } <span class="glyphicon glyphicon-new-window whatever-name"></span> +2ms
  test:unit:component:Icon 1 ReactWrapper { length: 1 } <span class="glyphicon glyphicon-new-window whatever-name"></span> +2ms

It didn't occur to me that a css selector would match a component. I see now that .debug() would have got me there.

Was this page helpful?
0 / 5 - 0 ratings