4

Capybara没有按照我期望的方式HaveSelector使用 RSpec 。expect我是 Capybara 和 RSpec 的新手,所以这很可能是我对 RSpec 或 Capybara 的误解,或者它可能是 Capybara(2.0.2 版)的缺陷。请帮助我理解我的错误或制作错误报告/功能请求。

在我的 RSpec 中,我写道:

expect { click('.special-div .submit') }.to have_css('.submitted')

我希望这在功能上等同于

click('.special-div .submit')
page.should have_css('.submitted')

但事实并非如此。相反,匹配器have_css尝试匹配 proc 对象的字符串转换,而不是调用 proc 对象的结果。(换句话说,click('.special-div .submit')永远不会被执行。)

是水豚的行为:

  • 很合理
  • Capybara 中缺失功能的示例
  • Capybara 2.0.2 中的一个错误
  • 还有什么?

另外,我显然可以通过使用上面的 2 行版本来做我想做的事,但是我们的团队正在尝试标准化expect {},那么有没有办法使用expect {}表格并让它做我想做的事?

编辑

我继承了我正在使用的代码,所以我没有意识到,正如 Andrey Botalov 指出的那样,click它不是 Capybara 的标准部分。看起来应该是这样,但又click已经被大量用于其他事情,所以 Capybara 最好不要添加另一个定义。

由于有些人似乎持怀疑态度,因此我向您保证,这段代码运行良好:

click('.special-div .submit')
page.should have_css('.submitted')

对于那些想知道的人来说have_css(),这就是 RSpec 的魔力has_css?。对于那些想知道的click人,在我的项目中,有人方便地创建了click如下功能:

  def click(css)
    page.execute_script("$('#{css}').first().trigger('click');")
  end

为什么?因为没有一个明显的替代方案奏效。

click_on('.special-div .submit')  # Fails because click_on does not take CSS
# Cannot use click_button() because we are clicking on a <div>
find('.special-div .submit').click # Raises exception because there are more than one
first('.special-div .submit').click # Fails because the div is not visible

继续前进,@zetetic 询问是否

expect(click('.special-div .submit')).to have_css('.submitted')

会工作。不,它对我们不起作用,因为我们仍在使用 RSpec 2.9 并且该语法是在 2.11 中引入的,但即使我们升级它仍然无法工作,因为click它不返回对象。click如果我们升级到 2.11 并更改为 return ,它可能会起作用page

4

2 回答 2

2

有几个问题,expect { click('.special-div .submit') }.to have_css('.submitted')这就是我如此困惑的原因。

最让我困惑的是 RSpec 的expect {...}.to ...语法。我认为这种语法会导致匹配器运行代码{}并将匹配器应用于结果或类似的东西。给定示例似乎是有道理的:

expect { something }.to raise_error(SomeError)

事实证明,这通常不是真的。只有某些匹配器期望“实际”(介于 'expect' 和 '.to' 之间)是 aProc然后调用它。大多数匹配器期望“实际”是一个对象。所以:

expect { 1 + 1 }.to eq(2)

Proc尝试将 a与 a进行比较时引发异常Fixnum

因此,Capybara 的has_css?匹配器完全合理地期望“实际”是响应has_selector?而不是响应的对象Proc。这确实是我的主要问题,因此,Capybara 摆脱了困境。

进一步让我感到困惑的是,Capybara 提供了一个 DSL,因此在我的示例 has_css?中,它等同于page.has_css?让我期望它have_css(css)会继续神奇地针对page.

关于编写测试的更好方法。@deviousdodo 大部分是正确的,这就是为什么我要奖励这个答案。我想要的是

expect {
  click('.special-div .submit') 
}.to change { page.has_css?('.submitted') }.from(false).to(true)

实际上,虽然它超出了原始问题的范围,但我真正想要的是

expect { 
  click('.special-div .submit')
  page.should have_css('.submitted')
}.to change { Click.count }.by 1

我想要这个的原因是因为我最想检查的是点击记录在数据库中(Click.count增量),但我必须等待点击触发的 AJAX 调用完成,这是由has_css?.

于 2013-04-08T01:51:29.627 回答
1

编辑:答案的第一部分是错误的,所以我改变了它。

我最初说这段代码

expect { click('.special-div .submit') }.to have_css('.submitted')

相当于:

click('.special-div .submit').should have_css('.submitted')

但这不是真的,因为传递给的 procexpect实际上不会被评估(您可以阅读@OldPro 的答案以获取更多详细信息)。

解决方案是expect change

expect {
  click_button('Button label')
}.to change { page.has_css?('.submitted') }.from(false).to(true)

您可以在rspec 网站上找到更多详细信息。

于 2013-04-06T23:11:26.310 回答