Capybara integration testing with asynchronous JavaScript Capybara integration testing with asynchronous JavaScript selenium selenium

Capybara integration testing with asynchronous JavaScript


Thoughtbot has a great blog post on waiting for AJAX, which you can read here, though it is based on Rspec, and it looks like you are using TestUnit.

It works great for situations when Capybara doesn't quite wait long enough, but doesn't add unnecessarily long timeouts. I work mostly in Rspec now, but I think you can modify it by doing this:

# Create this file in test/support/wait_for_ajax.rbmodule WaitForAjax  def wait_for_ajax    Timeout.timeout(Capybara.default_max_wait_time) do      loop until finished_all_ajax_requests?    end  end  def finished_all_ajax_requests?    page.evaluate_script('jQuery.active').zero?  endend

You can either include it when needed in the individual test file, or use one of the strategies provided in this SO post for automatically including it every time.

Then, whenever you have a test that is not properly waiting for AJAX to finish, just insert the line wait_for_ajax. Using your code as an example:

click_button("Remove stuff")wait_for_ajaxassert has_no_link?("This should be removed")


there was some method called wait_until, but it was deprecated recently and changed with synchronize method.

http://www.elabs.se/blog/53-why-wait_until-was-removed-from-capybara

https://github.com/jnicklas/capybara/blob/master/lib/capybara/node/base.rb#L44

For now I don't know how to use it exactly, but I'm waiting for answer for my question from the author, so I hope to resolve this problem soonly


There's a neat way to check that ajax requests are done, which I learned from this article. Instead of wait with some specific time, you can use the ajax $.active function (which is not in the actual API but is exposed so you can use it). $.active tells you the number of active connections to a server, so when it drops to zero you know the ajax request is done:

wait_until do  page.evaluate_script('$.active') == 0end

If that doesn't work, then the issue is somewhere else (which judging from what you wrote seems likely). If the change is only happening in the DOM, then you have to make sure that javascript is enabled for your test/spec. In rspec, for example, you set :js => true to do that; in Cucumber you add a line above the scenario with @javascript. I don't use rails' default tests but there must be a setting to do the same.