Capybara Ambiguity Resolution
My solution is
first(:link, link).click
instead of
click_link(link)
Such behavior of Capybara is intentional and I believe it shouldn't be fixed as suggested in most of other answers.
Versions of Capybara before 2.0 returned the first element instead of raising exception but later maintainers of Capybara decided that it's a bad idea and it's better to raise it. It was decided that in many situations returning first element leads to returning not the element that the developer wanted to be returned.
The most upvoted answer here recommend to use first
or all
instead of find
but:
-
all
andfirst
don't wait till element with such locator will appear on the page thoughfind
does wait -
all(...).first
andfirst
won't protect you from situation that in future another element with such locator may appear on the page and as the result you may find incorrect element
So it's adviced to choose another, less ambiguous locator: for example select element by id, class or other css/xpath locator so that only one element will match it.
As a note here are some locators that I usually consider useful when resolving ambiguity:
-
find('ul > li:first-child')
It's more useful than
first('ul > li')
as it will wait till firstli
will appear on the page. -
click_link('Create Account', match: :first)
It's better than
first(:link, 'Create Account').click
as it will wait till at least one Create Account link will appear on the page. However I believe it's better to choose unique locator that doesn't appear on the page twice. -
fill_in('Password', with: 'secret', exact: true)
exact: true
tells Capybara to find only exact matches, i.e. not find "Password Confirmation"