我相信你想要的 XPath 是
page.should have_xpath("//a[text()='#{link}' and @href='#{url}']")
我不熟悉 Cucumber,但如果它依赖has_link?
Capybara,@shioyama 建议的替代方案更容易阅读:
page.should have_link(link, :href => url)
然而,它也看似简单。使用has_link?
,请记住:
- 它搜索子字符串(您的 XPath 示例搜索完全匹配)。
- 它在文本值中搜索“链接”,但也在id、title 和 img alt 字段中搜索。
- 如果您将其他属性指定为选项,例如
:text
or :class
,它们将被静默忽略。您可能认为您正在缩小测试范围,但事实并非如此。
考虑以下 HTML:
<a href="/contacts/3" data-confirm="Are you sure?" data-method="delete"
title="Delete Contact 3">Delete</a>
我很惊讶地发现,因为has_link?
搜索 的子字符串 title
,以下两个条件都匹配该链接:
has_link?("Contact 3", href: "/contacts/3")
has_link?("Delete", href: "/contacts/3")
我目前正在试验一个自定义has_exact_link
匹配器,它通过显式格式化 XPath 来消除歧义。它只搜索文本值的完全匹配,而不是子字符串,以及:href
引发错误以外的任何选项:
规范/支持/matchers.rb
# Check for an <a> tag with the exact text and optional :href and :count.
# Same param syntax as has_link, but it only matches the link's TEXT, not id,
# label, etc., and it doesn't match substrings.
def has_exact_link?(locator, options={})
# Subtract :href, :count from array of options.keys
# Raise error if any options remain
raise ArgumentError.new \
"options, if supplied, must be a hash" if !options.is_a?(Hash)
raise ArgumentError.new \
"has_exact_link only supports 'href' and 'count' as options" unless
(options.keys - [:href] - [:count]).empty?
href = options[:href]
xpath = href ? "//a[normalize-space(text())='#{locator}' and @href='#{href}']" :
"//a[normalize-space(text())='#{locator}']/@href"
# pass original options has so test results will show options if present
# has_xpath apparently ignores :href in options but will use :count.
has_xpath?(xpath, options)
end
2012 年 9 月 19 日更新:在上面 添加了“normalize-space” has_exact_link
,因此它会像 HTML 一样忽略前导和尾随空格。这是必需的,例如,您的链接文本与<a>
标签位于不同的行,例如
<a href="/contacts/3">
Contact 3
</a>
它仍然不匹配子字符串。要匹配上述内容,您必须指定has_exact_link("Contact 3")
,而不仅仅是has_exact_link("Contact")
。
2012 年 9 月 20 日更新另一个has_exact_link
更新,同上。现在它对options
参数进行类型检查,并处理:count
选项以及:href
.