Do not use "find" on Capybara nodes from an array

Posted . Visible to the public.

In a nutshell: Capybara's find will not work properly on nodes from a list. Don't find on elements from a list.

Background

Consider this HTML:

<div class="message">
  <h2>Hello World</h2>
  Lorem ipsum...
</div>
<div class="message">
  <h2>Hello Universe</h2>
  Lorem ipsum...
</div>

Now let's say you obtain a list of all such message containers as an array:

messages = page.all('.message')

And then you look at their titles like this:

messages[0].find('h2').text
=> "Hello World"
messages[1].find('h2').text
=> "Hello Universe"

So far, so good. Now we want to find titles by their content, as usual:

messages[0].find('h2', :text => 'Hello World').text
=> "Hello World"

Now we search inside the same container as above, which contains "Hello World" as its headline. \
So expecting it to contain some other text should break, right? Wrong:

messages[0].find('h2', :text => 'Hello Universe').text
=> "Hello Universe"

It seems as if Capybara concatenates the selector "route" it took to get the initial elements to search for content, instead of search finding on the actual element as requested -- which is not what anyone would want. This is just plain crazy.

Solution

I could not come up with a solution to this other than "don't do it".

Instead, I'm now using a "full" selector to avoid the broken behavior:

page.find('.message:nth-of-type(1)', :text => 'Hello World').text
=> "Hello World"
page.find('.message:nth-of-type(2)', :text => 'Hello World').text
# Fails as expected (the element can not be found)

Mind that lists start on 1 (not 0) for nth-of-type.

Arne Hartherz
Last edit
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2012-06-26 19:20)