Read more

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

Arne Hartherz
June 26, 2012Software engineer at makandra GmbH

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


Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show snapshot

Consider this HTML:

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

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:

=> "Hello World"
=> "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.


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.

Posted by Arne Hartherz to makandra dev (2012-06-26 21:20)