Enzyme: Object Property Selector for Full DOM Rendering doesn't find non-DOM components

Created on 5 Sep 2016  路  7Comments  路  Source: enzymejs/enzyme

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

Most helpful comment

Changing the docs would be good

All 7 comments

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.

Was this page helpful?
0 / 5 - 0 ratings