aklybw

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

9 Responses
Add your response

8384
5009d470b40e5f3aefb5515559c8745d

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 ·
9512

Good solution, thanks!

over 1 year ago ·
11889
483f1b98648c3e9b2c75fb6bb7ad2ed9

Where exactly do you add this?

over 1 year ago ·
11930
84687433fbeed3d44d0298b7032f9780

@dejancancarevic just add this in your spec_helper.rb

over 1 year ago ·
12880
D4d312a34cfa93a577373558f8c34da8

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 ·
12881
D4d312a34cfa93a577373558f8c34da8
over 1 year ago ·
12945
84687433fbeed3d44d0298b7032f9780

@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 ·
14231
3915eeaee91d96525e3e4e0fcdf93343

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 ·
19340
None

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 ·