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.
wrapper.find('.class') returns the elements with that class applied
node v8.9.4 on darwin
| library | version
| ---------------- | -------
| Enzyme | 3.3.0
| React | 15.6.2
| jsdom | 11.6.2
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.
Most helpful comment
This is expected behavior; it's finding both the
Iconcomponent and the renderedspan. You can usehostNodesto 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!