Capybara与has_no_css同步?

时间:2014-08-12 00:48:41

标签: ruby capybara

自升级到Capybara 2.4以来,我一直在遇到这个问题。以前,这个块运行良好:

page.document.synchronize do
  page.should have_no_css('#ajax_indicator', :visible => true)
end

这意味着在继续下一步之前强行等待ajax指示消失。

由于上面的内容返回RSpec::Expectations::ExpectationNotMetError,因此同步不会重新运行该块,而只是抛出错误。不知道为什么这个在我之前使用的版本中工作(我相信2.1)。

synchronize块仅重新运行返回以下内容的块:

Capybara::ElementNotFound
Capybara::ExpectationNotMet

无论某个驱动程序添加到该列表中。

请参阅Justin的回复,了解更全面的解释和不使用synchronize的示例,或查看我对直接解决方案的回复。

3 个答案:

答案 0 :(得分:3)

have_no_css匹配器已经等待元素消失。问题似乎是在synchronize块内使用它。 synchronize方法仅针对某些例外重新运行,但不包括RSpec::Expectations::ExpectationNotMetError

删除synchronize似乎可以做你想要的 - 即强制等待直到元素消失。换句话说,就是这样做:

page.should have_no_css('#ajax_indicator', :visible => true)

工作示例

这是一个页面,比如说“wait.htm”,我认为它会重现你的问题。它有一个链接,当点击时,等待6秒,然后隐藏指标元素。

<html>
  <head>
    <title>wait test</title>
    <script type="text/javascript" charset="utf-8">
      function setTimeoutDisplay(id, display, timeout) {
          setTimeout(function() {
              document.getElementById(id).style.display = display;
          }, timeout);
      }
    </script>
  </head>

  <body>
    <div id="ajax_indicator" style="display:block;">indicator</div>
    <a id="hide_foo" href="#" onclick="setTimeoutDisplay('ajax_indicator', 'none', 6000);">hide indicator</a>
  </body>
</html>

以下规范显示,通过使用page.should have_no_css而无需手动调用synchronize,Capybara已经迫使等待。等待仅2秒时,规范失败,因为元素不会消失。当等待10秒时,规格通过,因为元素有时间消失。

require 'capybara/rspec'

Capybara.run_server = false
Capybara.current_driver = :selenium
Capybara.app_host = 'file:///C:/test/wait.htm'

RSpec.configure do |config|
  config.expect_with :rspec do |c|
    c.syntax = [:should, :expect]
  end
end

RSpec.describe "#have_no_css", :js => true, :type => :feature do
  it 'raise exception when element does not disappear in time' do
    Capybara.default_wait_time = 2

    visit('')
    click_link('hide indicator')
    page.should have_no_css('#ajax_indicator', :visible => true)
  end

  it 'passes when element disappears in time' do
    Capybara.default_wait_time = 10

    visit('')
    click_link('hide indicator')
    page.should have_no_css('#ajax_indicator', :visible => true)
  end
end

答案 1 :(得分:1)

从Capybara 2.0版本开始,您可以自定义内联等待时间参数,将其传递给#have_no_css方法:

page.should have_no_css('#ajax_indicator', visible: true, wait: 3)

答案 2 :(得分:-1)

我已解决的解决方案如下:

page.document.synchronize do
  page.assert_no_selector('#ajax_indicator', :visible => true)
end

assert_no_selector方法正确抛出Capybara::ExpectationNotMet错误,似乎与has_no_css的工作方式相同,因此我对此解决方案感到满意。

我仍然不知道为什么某些方法会抛出RSpec错误而不是其他方法。