However testing AJAX is not that straightforward because of asynchonous nature of these requests. In order to test effects of AJAX calls a web driver must wait until they finish which is difficult if not impossible to detect. However this can be worked around using some tricks.
Let’s say you want to test a link on the page that triggers an AJAX request which eventually inserts some element in DOM. This could be an “Edit” link that retrieves object’s data from database (via AJAX call) and then shows an HTML form on the page. Test scenario might look like this:
@selenium Scenario: Clicking "Edit" should show edit form Given I am on product's page And I click "Edit" link Then I should see form
The form will not appear immediately after the link is clicked because it takes some time for your app to process the AJAX request and return the response. Capybara is intelligent enough to acknowledge this and instead of expecting a form to appear immediately it periodically looks for it in page’s DOM. You can define for how many seconds it should keep looking by setting following option:
Capybara.default_wait_time = 5
If the form doesn’t appear in this specified time frame, the test fails. Note that Capybara doesn’t always wait full 5 seconds, it simply moves on to the next step as soon as the form appears.
Now you want to test a link that removes an element from DOM. This could be a “Save” link that saves object to database (via AJAX call) and then removes the form. Test scenario:
@selenium Scenario: Clicking "Save" should remove edit form Given I am on product's page And I click "Save" Then I should not see form
This test fails even if your app works as expected. I guess you see the problem. Capybara finds the form on first lookup which is performed immediately after the click, but at that point the AJAX call has not completed yet, so the form is still there.
Popular solution is to explicitely tell Capybara to wait until it starts looking for changes in DOM. In other words, give the AJAX calls chance to complete. Here’s an adequate cucumber step:
Given /^I wait (\d+) seconds?$/ do |sec| sleep(sec.to_i) end
Rebuilt scenario would look like this:
@selenium Scenario: Clicking "Save" should remove edit form Given I am on product's page And I click "Save" And I wait 5 seconds Then I should not see form
The downside is that it will always wait 5 full seconds now.
Neither explicit waiting with sleep, nor Capybara’s default_wait_time option guarantees 100% success. Your tests may still ocassionally fail if the AJAX requests they perform takes longer than you assume. The time it takes for the app to process such request may be quite random as it depends on many aspects like machine load or external services it hits (database, search engines, etc.). So remember to set the option to a value high enough for your app.