开发者

waitForElement with Cucumber + Selenium

Hey all, I'm trying to fix up my numerous scenarios that test out pages with advanced AJAX and client side screen building via JQuery and having a ton of issues.

Mainly, I'm having trouble knowing when certain AJAX requests are done. I've tried just putting in sleep delays but that's a bad idea long term. I've also tried a couple methods I found online to check to see if the AJAX calls are all done, but these methods don't seem stable enough.

I started exploring Selenium more and found the waitForXXX functions. Excited I threw them into my cucumber steps but no luck. My current test case is a dynamically loaded grid that gets its data over AJAX. (Jquery Datagrid plugin). I'm looking for data to be there by looking for the first non-header row, then I click it. The code to click the element is:

page.all(:css, "#{arg1} tr")[1].click();

Sometimes this works, often it doesn't because the row hasn't loaded yet. So I was trying:

waitForElementPresent("css=#{arg1} tr:nth-child(1)")

before clicking the row, but whenever it gets to that line of code I get a wonderful error from ruby:

stack level too deep (SystemStackError)

What am I doing wrong, and is there a better way to write these kinds of steps t开发者_如何学编程o make sure they really wait for the AJAX call to finish?

Note that the app itself works fine - this is just to get my testing code to go green reliably.


I've had very good luck with the step below (which we pulled from someone else). It was originally geared towards culerity/celerity (which we used for a time), but it's been quite good for plain cucumber/capybara:

When /^I wait for the AJAX call to finish$/ do
  keep_looping = true
  while keep_looping do
    sleep 0.10
    begin
      count = page.evaluate_script('window.running_ajax_calls')
      keep_looping = false if count.respond_to?(:to_i) && count.to_i == 0
    rescue => e
      raise e
    end
  end
  sleep 0.20
end

You may have to tweak the looping sleep and after sleep. These values work great for a Mac Pro that runs 12 cores of tests at the same time. In a very small number of circumstances, we've added an additional 1 second wait.


I tend to call the has_css? method before attempting to interact with the element e.g.

page.should have_css("#{arg1} tr")

Capybara will retry until the (configurable) default wait time has expired. Once this step has passed, you should then be able to click the element as expected - alternatively the step will fail if the element does not appear before the wait time expires.


Thanks to Alistar's hint about page.should have_css, I worked up a generic example. This probably won't work if there are multiple AJAX going on at once, but its pretty lightweight for me.

In my application.html.erb I included a simple blank div:

<div id="ready"/>

Then in my javascript file that's loaded when the app starts, I added this line to hide the div when there is an AJAX call going on.

$('#ready').ajaxStart(function(){$(this).hide();}).ajaxStop(function(){$(this).show();});

Then in my common steps for Cucumber, I have a very simple "Wait for AJAX" step definition:

When /^I wait for AJAX$/ do
page.should have_css("#ready")

end

At first test, this seems to work. Its yet another way to skin the cat, so it may not work all the time, but it is nice and lightweight for me in my situation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜