enzyme: can't find() element but wrapper.contains() it

Current behavior

I cannot find(Component|".selector") but I can see it via html() and via .contains()

Here are the most important parts of code. (I am using ava, t.log is the test logger)

I am using a styled component here but it is the same when I add a custom className, id or data-attribute to attempt finding the element/Component.

code

const RetryButtonId = RetryButton.styledComponentId;
const retrySelector = `.${RetryButtonId}`;

t.log(retrySelector);
const retry = wrapper.find(RetryButton);
const _retry = wrapper.find(retrySelector);
const html = wrapper.html();
const match = html.match(new RegExp(`<button class="${RetryButtonId}.*?">Retry</button>`));
t.log(`match: ${match && match[0]}`);
t.log(`length "${retrySelector}": ${_retry.length}`);
t.log(`length "RetryButton": ${retry.length}`);
t.log(`exists "${retrySelector}": ${wrapper.exists(retrySelector)}`);
t.log(`contains "RetryButton": ${wrapper.contains(RetryButton)}`);

The logs show inconsistencies. While contains() returns true, exists() returns false.

The html() matches the element but find() and exists() ignore it.

Logs

ℹ .sc-jTzLTM
ℹ match: <button class="sc-jTzLTM dlKhUw sc-bdVaJa kgpquR">Retry</button>
ℹ length ".sc-jTzLTM": 0
ℹ length "RetryButton": 0
ℹ exists ".sc-jTzLTM": false
ℹ contains "RetryButton": true

Expected behavior

contains(), find(), exists(), html() should return matching results.

Your environment

OS X 10.13.6

node: v10.10.0 npm: 6.4.1 yarn 1.12.3

API

  • shallow
  • mount
  • render

Version

library version
enzyme 3.8.0
react 16.7.0
react-dom 16.7.0
react-test-renderer
adapter (below)

Adapter

  • enzyme-adapter-react-16
  • enzyme-adapter-react-16.3
  • enzyme-adapter-react-16.2
  • enzyme-adapter-react-16.1
  • enzyme-adapter-react-15
  • enzyme-adapter-react-15.4
  • enzyme-adapter-react-14
  • enzyme-adapter-react-13
  • enzyme-adapter-react-helper
  • others ( )

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 19
  • Comments: 20 (9 by maintainers)

Most upvoted comments

I get the expected results if I call wrapper.update() beforehand but this shouldn’t be needed, right?

I suppose I hit a similar issue, but perhaps due to different reason as wrapper.update() makes no difference:

it.each(['foo', 'bar'])(
 'lorem ipsum',
 (value) => {
    // Logs 1
    console.log(wrapper.find({ value }).length);
    // Shows the nodes with matching `value`
    // <mockConstructor>
    // <WithStyles(MyElem) checked={true} value="foo" />
    // <WithStyles(MyElem) checked={true} value="bar" />
    // </mockConstructor>
    console.log(wrapper.debug());
    // Fails with: Method “props” is meant to be run on 1 node. 0 found instead.
    expect(wrapper.find({ value }).props()).toMatchObject({ checked: true }); 
  }
);

Any suggestions?

I’d be happy to accept a PR that made the docs more clear.

Sorry I can’t share the code since it’s private. I’d have to set up a MVP for reproduction (probably won’t have time).

Inspecting the debug tree is pretty hard. I tried it and wasn’t very successful since the output is too cluttered (nested & extended components.). I gave up after a while and don’t think I will try this method again in the near future.

I think I did notice that the “conditional section” wasn’t in the tree. I’m not fully sure (cluttered output) and I moved on to try other methods.

My main concern was, that contains and html return absolutely different results than exists and find. This should simply not be an issue. If you suggest not to use html then this should be noted or be removed. What use is a method if it returns the wrong output? especially if several methods aside have conflicting output.

If I ever find the time… I am currently writing docs for another big library. (enquirer) so right now I’m rather busy.

I enjoy writing docs (mostly because I value them so much) so I might get back to this, … no promises.

I usually write easy to follow guides alongside documentation. I might suggest a format (in January). I’ve had good responses to that format.

The purpose of .html is that it uses the render API, and produces HTML output. I agree that it should probably be removed.

contains, exists, and find should definitely agree - although it’s worth noting as well that simulate doesn’t actually simulate anything, it’s just sugar for invoking a prop function - so you might indeed need a wrapper.update() before things are consistent.