Last Updated: June 26, 2017
·
27.43K
· diasjorge

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

10 Responses
Add your response

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
over 1 year ago ·

Good solution, thanks!

over 1 year ago ·

Where exactly do you add this?

over 1 year ago ·

@dejancancarevic just add this in your spec_helper.rb

over 1 year ago ·

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

over 1 year ago ·
over 1 year ago ·

@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

over 1 year ago ·

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
over 1 year ago ·

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).

over 1 year ago ·

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
over 1 year ago ·