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
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.
wait test
indicator
hide indicator
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