Hi I'm trying to find a component based on object props when doing full DOM rendering.
According to the docs, I should be able to find components and DOM nodes:
Enzyme allows you to find components and nodes based on a subset of their properties
However, I'm seeing that non-DOM components aren't passing the predicate. Relevant line in source filtering out non-DOM components: https://github.com/airbnb/enzyme/blob/master/src/MountedTraversal.js#L183
Is there a way to find components via an object property selector?
Test case:
class MyComponent extends React.Component {
render () {
return <div />
}
}
const wrapper = mount(<MyComponent foo="bar" />);
wrapper.debug() // <MyComponent foo="bar"><div /></MyComponent>
wrapper.findWhere((node) => node.prop('foo') === "bar").length // result is 1
wrapper.find({foo: "bar"}).length // result should be 1 but is 0
What is dom.render in your example (specifically, what is dom)?
Additionally, what renders is what MyComponent _renders_ - not what MyComponent _is_. So, the "foo" prop does not in fact exist in the render output of MyComponent - iow, this is working correctly.
Thanks for the reply!. Ah sorry, that was an internal helper. it should just be mount(). I've updated the test case above.
Also, two counterpoints:
If I do wrapper.debug(), I get
<MyComponent foo="bar">
<div />
</MyComponent>
Also, if I do wrapper.findWhere((node) => node.prop('foo') === "bar"), I get a MyComponent instance.
Both of those points tell me that what component _is_ does matter.
The debug is helpful output to figure out what you did - but you're right that the behavior of find with mount is a bit odd. Effectively it's two trees that are merged together: the React tree, and the resulting DOM tree.
Either way, the find and findWhere results should match up, especially with the object selector syntax, so this seems like a bug.
So the issue you're seeing here with find is because find explicitly filters out nodes that are not DOM elements MountedTraversal.js#L183.
export function instMatchesObjectProps(inst, props) {
if (!isDOMComponent(inst)) return false;
const node = getNode(inst);
return isSubset(propsOfNode(node), props);
}
See https://github.com/airbnb/enzyme/pull/538 and https://github.com/airbnb/enzyme/pull/377 for some discussion on this. If we _do_ match all nodes, we end up getting duplicate values for find since it matches the prop on the component and on the element itself, in cases where props may be passed down or spread on child components or elements.
Perhaps related, I'm struggling to check the checked state of a checkbox:
class Fixture extends React.Component {
render() {
return React.createElement(
'div',
null,
React.createElement('input', { id: 'checked', defaultChecked: true }),
React.createElement('input', { id: 'not', defaultChecked: false })
);
}
shallow()
el = shallow(React.createElement(Fixture, null)).find('#checked');
el.html() -> <input id="checked" checked=""/>
el.is('input[checked]') -> false
el.is('input[checked="checked"]') -> false
el.is('checked') -> false
el.is('[checked]') -> false
el.is(':checked') -> false
el.is('input[checked=""]') -> false
mount()
el = mount(React.createElement(Fixture, null)).find('#checked');
el.html() -> <input id="checked">
el.is('input[checked]') -> false
el.is('input[checked="checked"]') -> false
el.is('checked') -> false
el.is('[checked]') -> false
el.is(':checked') -> false
el.is('input[checked=""]') -> false
render()
el = render(React.createElement(Fixture, null)).find('#checked');
el.html() ->
el.is('input[checked]') -> true
el.is('input[checked="checked"]') -> false
el.is('checked') -> false
el.is('[checked]') -> true
el.is(':checked') -> true
el.is('input[checked=""]') -> true
Changing the docs would be good
I believe this is addressed in v3. Please file a new issue if not.
Most helpful comment
Changing the docs would be good