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.
Follow-up: I've since revisited this problem so here's a few tips:
1) document.synchronize more often than not does nothing useful, as mentioned by others most of the finders have built-in wait. You can manually force it to not wait using wait: 0
when that makes sense.
Note that due to this, the following are not equivalent:
!assert_css('#ajax_indicator')
assert_no_css('#ajax_indicator')
The former will wait until the element exists, while the latter will wait until the element doesn't exist, even if they are otherwise logically equivalent.
2) Problems that lead to us initially inserting synchronize were due to a chicken and egg problem of sorts.
#ajax_indicator
in this case will appear when there is active loading, then disappear after. We cannot distinguish from the indicator having not appeared yet, and having appeared then disappeared.
Although I have yet to 100% resolve this issue, what has improved our test reliability is looking for indicators to ensure page loading has reached a certain point, e.g.
do_thing_that_triggers_ajax
find('#thing-that-should-exist')
assert_no_selector('#ajax_indicator', visible: true)
This differents from asserting #ajax_indicator exists and then assert it doesn't exist, because in that case if the ajax happens too fast capybara may not catch it in action.
Depending on your scripts, you could possibly find more reliable indicators.
synchronize
directly. – Andrei Botalovnative
. Amount of such cases is very rare. And yes, you use it incorrectly. – Andrei Botalov