Capybara synchronize with has_no_css?

前端 未结 3 1347
耶瑟儿~
耶瑟儿~ 2020-12-20 03:36

Since upgrading to Capybara 2.4, I\'ve been running into this issue. Previously, this block worked fine:

page.document.synchronize do
  page.should have_no_c         


        
相关标签:
3条回答
  • 2020-12-20 04:10

    Since version of Capybara 2.0 you can customize inline wait time parameter to pass it into the #have_no_css method:

    page.should have_no_css('#ajax_indicator', visible: true, wait: 3)
    
    0 讨论(0)
  • 2020-12-20 04:19

    The solution I've settled for is the following:

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

    The assert_no_selector method properly throws a Capybara::ExpectationNotMet error and appears to work in the same way as has_no_css, so I'm satisfied with this solution.

    I still have no idea why the RSpec error is being thrown for some methods but not others.


    Edit: While this works it isn't actually a good idea to do so, see other responses.

    0 讨论(0)
  • 2020-12-20 04:21

    The have_no_css matcher already waits for the element to disappear. The problem seems to be using it within a synchronize block. The synchronize method only re-runs for certain exceptions, which does not include RSpec::Expectations::ExpectationNotMetError.

    Removing the synchronize seems to do what you want - ie forces a wait until the element disappears. In other words, just do:

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

    Working Example

    Here is a page, say "wait.htm", that I think reproduces your problem. It has a link that when clicked, waits 6 seconds and then hides the indicator element.

    <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>
    

    The following spec shows that by using the page.should have_no_css without manually calling synchronize, Capybara is already forcing a wait. When waiting only 2 seconds, the spec fails since the element does not disappear. When waiting 10 seconds, the spec passes since the element has time to disappear.

    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
    
    0 讨论(0)
提交回复
热议问题