Jason Charnes

Use Capybara's #all to Select From Multiple Elements

Whether you’re writing feature specs using MiniTest, RSpec or Cucumber, you’re probably using Capybara to select elements. But, what happens when you’re trying to query a single selector and yet, there are multiples?

The Problem

Recently this question/example appeared on Reddit.

“How can I use Capybara’s within block on a page with multiple instances of a class?”

The example provided looked something like the following.

HAML view:

.page-header
%h4 Some Header
 
.page-header
%h4 Another Header

Capybara/RSpec test:

within '.page-header' do
expect(page).to have_content 'Some Header'
end
 
within '.page-header' do
expect(page).to have_content 'Another Header'
end

When the user tried to run the test, they’d get the following error:

Capybara::Ambiguous: Ambiguous match, found 2 elements matching visible CSS “.page-header”

The problem is, as the user stated, there are multiple elements in that view with the ‘page-header’ class. Capybara doesn’t know which one we want to use.

The Solution

Fortunately, there are multiple ways to combat this problem. Today, though, I just want to show an easy-to-use, built-in method to solve this problem.

#all

The #all method will return a Capybara::Result. The result is, essentially, an array of Node Elements. Result takes advantage of Ruby’s Enumerable Module.

Now, we can grab the specific header by getting its index in the result.

within all('.page-header')[0] do
...
end
 
within all('.page-header')[1] do
...
end

There are more ways to solve this problem. However, sometimes a simple method like this can be all you need.

Follow me on Twitter.