如何使用 Capybara 使用正确的错误消息断言元素数量?

Posted

技术标签:

【中文标题】如何使用 Capybara 使用正确的错误消息断言元素数量?【英文标题】:How to assert number of elements using Capybara with proper error message? 【发布时间】:2011-10-07 10:23:11 【问题描述】:

我知道在 Capybara 中,你可以这样做:

page.should have_css("ol li", :count => 2)

但是,假设页面例如只有一个匹配元素,错误描述性不是很强:

  1) initial page load shows greetings
 Failure/Error: page.should have_css("ol li", :count => 2)
 expected css "ol li" to return something

除了这个相当晦涩的错误消息之外,有没有一种方法可以编写断言,使错误输出类似于“当匹配'ol li'时,预期:2,找到:1”。显然,我可以自己为这种行为制作自定义逻辑 - 我在问有没有办法“开箱即用”?

不管怎样,我正在使用 Selenium 驱动程序和 RSpec。

【问题讨论】:

大家都知道,"page.should have_css("ol li", :count => 2)" 是在 capybara 中实现的。我认为它非常适用于范围:within("ol.users-list") do page.should have_css('li', :count => 3) end @rafaelkin,澄清一下:水豚现在是否报告例如?元素计数的不匹配更详细?我已经有一段时间没有关注 capybara 了,但是当时我提出问题时的问题是关于错误消息的格式,而不是 page.should have_css("ol li", :count => 2) 不会已经实现。 伙计们,我觉得当前接受的答案(=我自己的)不再是最好的,但没有时间(不再使用 Ruby)来评估哪个建议的解决方案是最好的。我会将接受的答案更改为 Richard 的答案,因为它包含解决原始问题的断言输出。 【参考方案1】:

好吧,似乎没有开箱即用的支持,我编写了这个自定义匹配器:

RSpec::Matchers.define :match_exactly do |expected_match_count, selector|
    match do |context|
        matching = context.all(selector)
        @matched = matching.size
        @matched == expected_match_count
    end

    failure_message_for_should do
        "expected '#selector' to match exactly #expected_match_count elements, but matched #@matched"
    end

    failure_message_for_should_not do
        "expected '#selector' to NOT match exactly #expected_match_count elements, but it did"
    end
end

现在,您可以执行以下操作:

describe "initial page load", :type => :request do
    it "has 12 inputs" do
        visit "/"
        page.should match_exactly(12, "input")
    end
end

并获得如下输出:

  1) initial page load has 12 inputs
     Failure/Error: page.should match_exactly(12, "input")
       expected 'input' to match exactly 12 elements, but matched 13

现在可以了,我会考虑制作 Capybara 的这一部分。

【讨论】:

看起来在 Capybara 中解决这个问题并不简单:github.com/jnicklas/capybara/issues/331【参考方案2】:

我更喜欢这个。

expect(page).to have_selector('input', count: 12)

https://github.com/jnicklas/capybara/blob/415e2db70d3b19b46a4d3d0fe62f50400f9d2b61/spec/rspec/matchers_spec.rb

【讨论】:

也适用于have_cssexpect(page).to have_css('input', count: 12)【参考方案3】:

我认为以下更简单,输出相当清晰,并且不需要自定义匹配器。

page.all("ol li").count.should eql(2)

然后在错误时打印出来:

      expected: 2
       got: 3

  (compared using eql?)
  (RSpec::Expectations::ExpectationNotMetError)

【讨论】:

这不会等待期望成真,例如当仍有待处理的 ajax 请求时。【参考方案4】:

Capybara 推荐的当前 (9/2/2013) 最佳实践如下 (source):

page.assert_selector('p#foo', :count => 4)

【讨论】:

【参考方案5】:

@pandaPower 的回答非常好,但语法对我来说略有不同:

expect(page).to have_selector('.views-row', :count => 30)

【讨论】:

使用哈希火箭不符合“不同的语法”。 我不是 ruby​​ 开发人员,也没有意识到这两种语法是等价的。 TBH 我不确定它是否值得被否决。这是一个有效的替代方案。对于那些没有 Ruby 背景的人来说,这似乎并不明显。它不适合我。【参考方案6】:

编辑:正如@ThomasWalpole 指出的那样,使用all 会禁用Capybara 的等待/重试,因此@pandaPower 上面的答案要好得多。

这个怎么样?

  within('ol') do
    expect( all('.opportunity_title_wrap').count ).to eq(2)
  end

【讨论】:

这完全打败了 Capybaras 等待/重试的方法,不应该成为推荐的解决方案。 @ThomasWalpole 我不确定你在说什么。在 Capybara 中以任何方式在另一个元素中寻找一个元素如何触及等待/重试? @ConstantMeiring 不是within,而是在all 的结果上调用.count 禁用等待/重试。通过在all 的结果上调用count(一个空的“数组”是一个有效的返回值),您可以将其转换为整数并进行比较。如果该比较失败,则期望失败。相反,如果您将 count 选项传递给 Capybara 的匹配器之一,capybara 将等待/重试查找指定的选择器,直到 count 选项匹配(或 Capybara.default_max_wait_time 到期)。

以上是关于如何使用 Capybara 使用正确的错误消息断言元素数量?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查表单域是不是使用 capybara 正确预填?

如何使用惰性加载器捕获 Capybara Feature JS 测试的服务器端错误?

成员相等在类型中不可用(库断言)

在 Rails 中使用 Capybara 和 Selenium 测试 Google 地图标记

Rspec和capybara选择了价值

如何使用 Capybara + Selenium 测试响应代码