Capybara::Ambiguous 匹配,找到 2 个匹配 xpath 的元素 - 找到第一个 link

Capybara::Ambiguous match, found 2 elements matching xpath - Find 1st link

我正在执行 index 操作,其中我列出了所有博客 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 %>

在我的测试脚本中,为了访问 show 操作并查看单个 post 我有这个

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

但是当我尝试 运行 测试时,我得到了这个错误

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

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

as capybara 发现两个不同的 link 进入同一页面(一个在标题上,另一个在 "read more" link 上)。有没有办法告诉水豚使用找到的第一个 link?

您不必使用 xpath。

在您的示例中,您应该能够使用:

first('.blog-post-title > a').click

由于其中一个链接在标题 h2 中,您可以使用它来确定查找范围并消除歧义

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

您也可以 first(:link, href: post_path(post)).click,但 first(如 all)的缺点是没有 waiting/retrying 行为,因此除非您确定页面已完全调用时加载最好避免它(或通过指定计数选项之一 first(:link, href: post_path(post), minimum: 1).click 启用 waiting/retrying)。

如果您需要经常点击博客标题链接,您还可以创建一个自定义选择器,例如

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

这将允许你做

find(:title_link, post).click