Alex Rivera | Logout

Capybara integration testing with asynchronous JavaScript

Asked 2012-09-23T20:08:52.927
13

I have a Rails integration test that's failing, and I can't figure out why. I'm using Capybara with Selenium as the driver.

The test checks that page content has been removed after an AJAX call takes place. The relevant action is that a button is clicked, and that button click causes a section of the page to be removed via a jQuery remove() call. Here's an approximation of the integration testing code:

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

The assertion fails, implying that the link still exists.

I've been reading up on Capybara, and I know that you can extend the default wait time. I've extended it to a ridiculous value (20 seconds), and still the assertion fails.

When I follow the test process myself manually, the source of the page still shows the content, but the DOM does not (by viewing Firefox's DOM Inspector and looking for the element). Is this the issue? I've even tried inspecting the DOM while the tests are running in Firefox to check if the content was there, and it doesn't appear to be.

I have no idea how Capybara is still finding this link that no longer exists in the DOM. Is Capybara examining the source instead of the DOM and finding the link there? If so, I have no idea how to fix this test to make sure that the test passes. Refreshing the page would fix the issue, but that's not exactly what a user would do, so I hesitate to change the page just to make the test pass...

Would love any recommendations on how to approach this problem.

Edit
Report

1 Answer

0

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') == 0
end

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.

answered 2012-09-23T22:16:11.600

Your Answer