user1701153 user1701153 - 4 months ago 34
Ajax Question

How to detect when a web service has completed using Selenium Webdriver

I'm trying to do some intelligent verification to determine when a web page document finishes loading while executing automation through Selenium WebDriver.

Using IJavaScriptExecutor.ExecuteScript() with WebDriverWait() has proven very useful.

I'm first waiting for the document to tell me it has loaded with:

.ExecuteScript("return document.readyState == 'complete'");


I'm next waiting for all AJAX libraries like jQuery and Dojo to tell me they are inactive with:

.ExecuteScript("return jQuery.active == '0'");
.ExecuteScript("return Ajax.activeRequestCount == '0'");
.ExecuteScript("return dojo.io.XMLHTTPTransport.inFlight.length == '0'");


At this point i'm still noticing things that were loading before the ajax checks began, still running(spinners on screen to fill tables with rows of data, etc). I tracked one of them down and put a rough call stack below.

Is there any way beyond waiting for elements to exist, to intelligently tell when this (.asmx) web service is finished? It's coming from an ASP.NET app and calling the web method through a generated proxy class. I can also see client-side code accessing Sys.Net if that helps or can be used to do some detection.

// Target Web Page

// called from a script tag at the ending body tag
$("#@fillArea").bind({
"select_node.jstree": function (e, data) {
setTimeout(function() {
FillList();
}, 1);

return true;
}
});

// web service called by FillList()
Abc.Api.MyService.Fill(listParams, onFillSuccess, onFailure, param);

// web service code for Fill()
[WebService(Namespace = "http://abc.alphabet.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1]
[ScriptService]
public class ListService
{
[WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true)]
public string Fill(ListParams listParams)
{
// get database data
// return html markup
}
}


EDITED: One solution discovered how to detect AJAX traffic for Microsoft AJAX Library

The following code to wire up events for it is inserted immediately after document.ready == 'complete'

((IJavaScriptExecutor)driver).ExecuteScript
(
@"MsftAjaxRequestCount = 0;

Sys.Net.WebRequestManager.add_invokingRequest
(
function onInvoke(sender, args)
{
MsftAjaxRequestCount++;
}
);

Sys.Net.WebRequestManager.add_completedRequest
(
function onComplete(sender, args)
{
MsftAjaxRequestCount--;
}
);"
);


The following code to check that the value for this new variable is inserted along with the other checking the other AJAX libraries

.ExecuteScript("return MsftAjaxRequestCount == '0'");


This works. But there is a slight race condition. Sometimes the events are wired up late and the events are not triggered or one is causing the value to go -1. This is due to Selenium Webdriver's GotoUrl() not returning until document.readyState is complete.

Can GotoUrl() return asynchronously before complete to wire up the events early? Any other ideas on this?

Answer

OP answers most of the OP question. Answers will vary based on what AJAX libraries are in play.

To return from GotoUrl() at different rates of speed(document.readyState == loading or interactive or complete) a Selenium Page Load Strategy can be employed. "normal" returns when "complete", "eager" returns when "interactive" and "none" returns immediately.

An example using the FireFox Driver from C# is shown below.

var profile = new FireFoxProfile();
profile.SetPreference("webdriver.load.strategy", "eager");

var driver = new FireFoxDriver(profile);
Comments