Selenium wait for AJAX (the right way!!!) - Agile Software Testing

 
Ajax! Ajax! Ajax!!!!
You cannot go to a website without running into some form of Ajax. It’s great and all, but if you are trying to test a website with Selenium, this becomes an issue. Selenium will wait for the page to load, but is rather clueless when it comes to Ajax.
After spending several painful hours looking for a way to make a “wait_for_ajax” function, I found several solutions that do not work.
1 – Put sleep in your test.
Well obviously this is the simplest solution, but also the worst. We don’t know how long a request will take to load, what if the server is slow?
2- Use “waitForElement” command built into selenium
This is a better solution; we wait for a certain element, which is part of the Ajax response to appear before moving on. The problem with this solution is that we need to always know which element needs to load. This becomes a headache for us normal people with extra large web applications to support.
SOLUTION!
Here is the solution I stopped on. I won’t take credit for making it, but I’ll take some credit for compiling it all in one place. To be honest I have not seen it done yet, the only thing I’ve seen was for bits and pieces but not the whole problem.
To solve this problem, what we have to do is ask the browser to tell us how many active connections to the server are present. Then we sit and wait for that number to become 0. At this point we know that all Ajax requests went through and done, and we can move on in the test. (If you have a webapp that contains non-stop Ajax request to constantly update everything, you have my sympathy.)

Step 1: Figure out which Javascript library your application uses
This is important one, which had me stomped for a long time. Different libraries (Prototype, Dojo, jQuery) use different methods to retrieve the connection info.

Step2: Create the wait_for_ajax method
def wait_for_ajax(timeout=5000)
js_condition = “”
$selenium.wait_for_condition(js_condition, timeout)
end

Let’s break this one down.
  • We have a default value of 5000 milliseconds for this method, but user can up or down it as they need.
  • js_condition will be a string, which will contain a selenium call to the browser’s javascript. It will be a javascript conditional that will wait for active connections to be 0, and then return “true”
  • $selenium.wait_for_condition is the method that will sit and wait for the javascript query to return “true” before letting you move on.
Step 3: Getting the right JS query for your library.
This part was the one, which took me the longest to figure out. But I’ll give you all the answers here. Different libraries use different functions to check incoming connection, so pick the right one for you.
jQuery: “jQuery.active”
Prototype: “Ajax.activeRequestCount”
Dojo: “dojo.io.XMLHTTPTransport.inFlight.length”

Step 4: Put together the JS search string
“selenium.browserbot.getCurrentWindow().” + library specific string + “ == 0”
Final string for jQuery will look like this
js_condition = “selenium.browserbot.getCurrentWindow().jQuery.active == 0”

Step 5: Put the method all together and enjoy :)
def wait_for_ajax(timeout=5000)
js_condition = “selenium.browserbot.getCurrentWindow().jQuery.active == 0”
$selenium.wait_for_condition(js_condition, timeout)
end
UPDATE: Thanks TIM!!
If using Selenium IDE, here is a way to access the AJAX Libraries
selenium.browserbot.getUserWindow()
And to check the JQuery active records
selenium.browserbot.getUserWindow().$.active == 0

Source: Agile Software Testing - Dima Kovalenko

Comments

  1. see update for selenium2
    http://agilesoftwaretesting.com/selenium2-wait-for-ajax-with-webdriver/
    Posted by Dima on Apr 15, 2011

    ReplyDelete

Post a Comment

Popular posts from this blog

Software Testing @ Microsoft

Trim / Remove spaces in Xpath?