title: Capybara synchronize with has_no_css?
body: <p>Since upgrading to Capybara 2.4, I've been running into this issue. Previously, this block worked fine:</p>
  
  <pre><code>page.document.synchronize do
    page.should have_no_css('#ajax_indicator', :visible =&gt; true)
  end
  </code></pre>
  
  <p>It's meant to force waiting until the ajax indicator disappears before proceeding with the next step.</p>
  
  <p>Since the above returns a <code>RSpec::Expectations::ExpectationNotMetError</code>, 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).</p>
  
  <p>The <code>synchronize</code> block only reruns blocks that return something like:</p>
  
  <pre><code>Capybara::ElementNotFound
  Capybara::ExpectationNotMet
  </code></pre>
  
  <p>And whatever a certain driver adds to that list.</p>
  
  <p>See Justin's response for a more comprehensive explanation and examples not using <code>synchronize</code>, or look at my response for the direct solution.</p>
  
  <hr>
  
  <p><strong>Follow-up</strong>: I've since revisited this problem so here's a few tips:</p>
  
  <p>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 <code>wait: 0</code> when that makes sense.</p>
  
  <p>Note that due to this, the following are not equivalent:</p>
  
  <pre><code>!assert_css('#ajax_indicator')
  assert_no_css('#ajax_indicator')
  </code></pre>
  
  <p>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.</p>
  
  <p>2) Problems that lead to us initially inserting synchronize were due to a chicken and egg problem of sorts.</p>
  
  <p><code>#ajax_indicator</code> 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.</p>
  
  <p>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.</p>
  
  <pre class="lang-rb prettyprint-override"><code>do_thing_that_triggers_ajax
  find('#thing-that-should-exist')
  assert_no_selector('#ajax_indicator', visible: true)
  </code></pre>
  
  <p>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.</p>
  
  <p>Depending on your scripts, you could possibly find more reliable indicators.</p>