Wait for ajax with capybara 2.0
Since they removed wait_until from capybara 2.0 I had to work out a different way to wait for all the ajax requests in a test to finish.
This need comes since we have a backbone application and many of the ajax requests executed won't have direct side effects on the DOM.
So the solution looks like this:
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
active = page.evaluate_script('jQuery.active')
until active == 0
active = page.evaluate_script('jQuery.active')
end
end
end
Written by Jorge Dias
Related protips
10 Responses

Thanks for share.
I would like to add my 2 cents with a DRY version of your code.
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
loop do
active = page.evaluate_script('jQuery.active')
break if active == 0
end
end
end
Good solution, thanks!

Where exactly do you add this?

@dejancancarevic just add this in your spec_helper.rb

does this work for Selenium? I got a:
Failure/Error: wait_for_ajax
Capybara::NotSupportedByDriverError:
Capybara::Driver::Base#evaluate_script
after putting it in my spec_helper.rb

actually, not sure if this is necessary, see http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara

@mswieboda, I don't know why you would get such error. I normally use phantomjs but sometimes selenium.
In my project I have selenium-webdriver (2.38.0) just in case
An regarding your second command. We use this helper only in some special cases, normally you should check for DOM changes

I found this through thoughbot's blog. Here are some minor changes I made (from their version). In the application I'm testing the AJAX requests are potentially long. I've added the ability to set a custom wait time AND to ensure that jQuery
is defined before calling jQuery.active
# @see http://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara Automatically wait for AJAX with Capybara
def finished_all_ajax_requests?
return_value = page.evaluate_script <<-SCRIPT.strip.gsub(/\s+/,' ')
(function () {
if (typeof jQuery != 'undefined') {
return jQuery.active;
}
else {
console.log("Failed on the page: " + document.URL);
console.error("An error occurred when checking for `jQuery.active`.");
}
})()
SCRIPT
return_value and return_value.zero?
end
# @see http://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara Automatically wait for AJAX with Capybara
def wait_for_ajax(task: 'Waiting for AJAX', wait_time: nil)
DebugHelpers.time_execution(task) do
wait_time ||= Capybara.default_wait_time
Timeout.timeout(wait_time) do
loop until finished_all_ajax_requests?
end
end
end

Thanks for this. Of the various suggestions I found at stack overflow and elsewhere, this was the only one which worked (Rails 4.1, RSpec 2.14, Capybara Webkit 1.3).

Sometimes the ajax requests don't kick off the instant you perform an action. I use a modified version of the code to first wait for at least one ajax request, then wait for them all to end:
def wait_for_ajax
Timeout.timeout(Capybara.default_max_wait_time) do
loop while finished_all_ajax_requests? # Wait for first request,
loop until finished_all_ajax_requests? # then wait until they all finish.
end
end