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_css('#ajax_indicator', :visible => true)
end
It's meant to force waiting until the ajax indicator disappears before proceeding with the next step.
Since the above returns a RSpec::Expectations::ExpectationNotMetError
, the synchronize doesn't rerun the block and instead just throws the error. Not sure why this was working in the version I was using before (I believe 2.1).
The synchronize
block only reruns blocks that return something like:
Capybara::ElementNotFound
Capybara::ExpectationNotMet
And whatever a certain driver adds to that list.
See Justin's response for a more comprehensive explanation and examples not using synchronize
, or look at my response for the direct solution.
The solution I've settled for is the following:
The
assert_no_selector
method properly throws aCapybara::ExpectationNotMet
error and appears to work in the same way ashas_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.
The
have_no_css
matcher already waits for the element to disappear. The problem seems to be using it within asynchronize
block. Thesynchronize
method only re-runs for certain exceptions, which does not includeRSpec::Expectations::ExpectationNotMetError
.Removing the
synchronize
seems to do what you want - ie forces a wait until the element disappears. In other words, just do: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.
The following spec shows that by using the
page.should have_no_css
without manually callingsynchronize
, 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.Since version of Capybara 2.0 you can customize inline wait time parameter to pass it into the
#have_no_css
method: