RSpec HaveSelector不能正常使用Capybara时的预期方式

时间:2013-03-28 00:24:32

标签: ruby rspec capybara

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缺少功能的示例
  • Capybara 2.0.2中的错误
  • 别的什么?

另外,我显然可以通过使用上面的2行版本来做我想要的,但我们的团队正试图在expect {}上进行标准化,那么有没有办法使用expect {}形式和得到它做我想要的?

修改

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

由于有些人似乎持怀疑态度,请允许我向您保证此代码工作正常:

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

对于那些对have_css()感到疑惑的人,这是has_css?的RSpec魔术。对于那些想知道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没有返回一个对象。如果我们升级到2.11并将click更改为返回page,则可能会有效。

2 个答案:

答案 0 :(得分:2)

expect { click('.special-div .submit') }.to have_css('.submitted')有几个问题,这就是为什么我这么困惑。

最令我困惑的是RSpec的expect {...}.to ...语法。我认为这种语法会导致匹配器在{}中运行代码并将匹配器应用于结果或类似的东西。在the example

,似乎有意义
expect { something }.to raise_error(SomeError)

事实证明这通常不正确。只有某些匹配者期望“实际”('expect'和'.to'之间的内容)为Proc然后调用它。大多数匹配者都希望“实际”成为一个对象。所以:

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

尝试将ProcFixnum进行比较时引发异常。

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

让我感到困惑的是,Capybara帮助提供了一个DSL,因此在我的示例中has_css?等同于page.has_css?,这使我期望have_css(css)将继续神奇地对抗{{1} 1}}。

开始编写测试的更好方法。 @deviousdodo大多是正确的,这就是我为这个答案授予奖金的原因。我想要的是

page

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

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 增量)但是我必须等待点击触发的AJAX调用才能完成,由Click.count完成。

答案 1 :(得分:1)

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

我最初说的是这段代码

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

相当于:

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

但这不是真的,因为传递给expect的proc实际上不会被评估(你可以阅读@ OldPro的答案以获取更多细节)。

解决方案是expect change

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

您可以在rspec website找到更多详细信息。