2

I'm having an index action where I list all blog posts

<% @posts.each do |post| %>
<div class="blog-post">
  <h2 class="blog-post-title"><%= link_to post.title, post_path(post) %></h2>
  <p><%= post.sort_description %></p>
  <p class="blog-post-meta">
     <%= link_to 'Read more', post_path(post) %>
  </p>
</div>
<% end %>

In my test script, in order to access the show action and view a single post I have this

find(:xpath, "//a[@href='/posts/1']").click
# or click_link(href: post_path(post)) 

But when I try to run the test I get this error

Failure/Error: find(:xpath, "//a[@href='/posts/1']").click

     Capybara::Ambiguous:
       Ambiguous match, found 2 elements matching xpath "//a[@href='/posts/1']"

as capybara finds two different links which go to same page (one on title and the "read more" link). Is there a way to tell capybara to use the first link that finds?

ltdev
  • 4,037
  • 20
  • 69
  • 129
  • Possible duplicate of [How to click first link in list of items after upgrading to Capybara 2.0?](https://stackoverflow.com/questions/14513377/how-to-click-first-link-in-list-of-items-after-upgrading-to-capybara-2-0) – fabdurso Jul 21 '17 at 07:30

2 Answers2

1

Since one of the links is in the title h2 you can use that to scope the find and remove the ambiguity

find(".blog-post-title > a[href=`#{post_path(post)}`]").click # always better to use post_path than hardcode the id

You could also do first(:link, href: post_path(post)).click but first (like all) has the disadvantage of not having waiting/retrying behavior so unless you're sure the page is fully loaded when called it's best to avoid it (or enable waiting/retrying on it by specifying one of the count options first(:link, href: post_path(post), minimum: 1).click).

If you need to click blog title links a lot you could also create a custom selector with something like

Capybara.add_selector(:title_link) do
  css do |post|
    ".blog-post-title > a[href=`#{post_path(post)}`]"
  end
end

which would then allow you to do

find(:title_link, post).click
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • Thank you! I'm accepting your answer as it was very detailed and also for giving this tip with the selector. I guess this script you put it somewhere in your `spec/support` dir or in `rails_helper` so it would be like a "global" setting? – ltdev Jul 20 '17 at 18:58
  • @Lykos correct - anywhere that gets loaded before your Capybara driven tests start to run. – Thomas Walpole Jul 20 '17 at 20:53
0

You don't have to use xpath.

In your example, you should be able to use:

first('.blog-post-title > a').click
Dan Kreiger
  • 5,358
  • 2
  • 23
  • 27