Waiting for page loads and AJAX requests to finish with Capybara

Updated . Posted . Visible to the public. Deprecated.

This cards needs to be rewritten.

capybara already retries command chains and capybara-lockstep fixes most other issues.

If you're using the Capybara webdriver, steps sometimes fail because the browser hasn't finished loading the next page yet, or it still has a pending AJAX request. You'll often see workarounds like

When I wait for the page to load
Then ...

Workarounds like this do not work reliably, will result in flickering tests and should be avoided. There is no known reliable way to detect if the browser has finished loading the page.

Solution

Instead you should wait until you can observe the result of a page load. E.g. if you make an AJAX requests to populate autocomplete suggestions, wait until you can see the suggestions box:

# Please note: wait_until was removed in Capybara 2
wait_until do
  page.has_css?('.suggestions')
end

You don't need to do this if you're using Spreewald Show archive.org snapshot 's web steps, because the steps take care of this automatically. They do this by wrapping all assertions into a helper called patiently do, like this:

Then /^I should see "([^\"]*)" in the HTML$/ do |text|
  patiently do
    body = page.body
    expect(body).to have_content(text)
  end
end

This works by rerunning the inner block several times till it succeeds or a timeout is reached, when we're inside a @javascript feature.

You're encouraged to use this for all of your own steps that check for page content. If a step does not actually access the page object, they do not need this, of course.

Grouping retriable statements

Note that you must wrap patiently around groups of statements that need to be retried together. For instance, the following might not work:

Then /^I should see "([^\"]*)" in the HTML$/ do |text|
  body = page.body
  patiently do
    expect(body).to have_content(text)
  end
end

In this case we might have fetched body from the page, then body is removed from the DOM. The patiently call will then always fail since we never re-fetch a fresh body.

Prevent stray javascript requests between steps and scenarios

We're using the gem capybara lockstep Show archive.org snapshot for that.

Tobias Kraze
Last edit
Michael Leimstädtner
Keywords
selenium
License
Source code in this card is licensed under the MIT License.
Posted by Tobias Kraze to makandra dev (2012-10-26 13:18)