As I utilize selenium to conduct tests on my application, I am encountering numerous ajax calls that utilize $resource or $http. It would be convenient if there was a method in angular to monitor active ajax requests so that selenium could wait until they are completed.
I have considered placing an element on the page for selenium to locate and connecting it to a flag that is set upon successful completion, but this approach might become unwieldy.
An effective way to accomplish this using jQuery is detailed here.
Is there a feature within selenium that can achieve this task which I may have overlooked?
After scouring through the documentation without success, I am open to any suggestions. Thank you.
EDIT: Caleb Boyd's solution is spot-on for detecting angular ajax calls while utilizing selenium web driver. Here is a brief overview of how I implemented this. I adapted Caleb's code variation from this link, which also accounts for ajax errors. Essentially, it achieves the same outcome. Many thanks to Caleb.
Add the following script and element to the bottom of your page. Remember to remove them before deployment:
<html>
<head><!--My Angular Scripts--></head>
<body ng-app="MyApp">
<!--Your Html -->
<script>
MyApp.config(function($httpProvider) {
$httpProvider.interceptors.push('requestInterceptor');
})
.factory('requestInterceptor', function($q, $rootScope) {
$rootScope.pendingRequests = 0;
return {
'request': function(config) {
$rootScope.pendingRequests++;
return config || $q.when(config);
},
'requestError': function(rejection) {
$rootScope.pendingRequests--;
return $q.reject(rejection);
},
'response': function(response) {
$rootScope.pendingRequests--;
return response || $q.when(response);
},
'responseError': function(rejection) {
$rootScope.pendingRequests--;
return $q.reject(rejection);
}
};
});
</script>
<span id="http-status">{{pendingRequests}}</span>
</body>
</html>
NUnit serves as the testing framework in my case.
[TestFixture]
public class MyTestClass
{
[Setup}
public void Setup()
{
_webDriver = new ChromeDriver(@"...path to chromedriver.exe")
//any other properties you need
}
[TearDown]
public void TearDown()
{
if(_webDriver == null)
return;
_webDriver.Quit();
_webDriver.Dispose();
}
[Test]
public void Test_my_page_functionality()
{
var pageBtn = _webDriver.FindElement(By.Id("my-btn-id"));
pageBtn.Click();
_webDriver.WaitForAjax();//see extension below
//test whatever result you want after ajax request has come back
}
}
Below is the WaitForAjax Extension
public static class WebDriverExtensions
{
public static void WaitForAjax(this IWebDriver webDriver)
{
while (true)
{
//Note: FindElement is another extension that uses a timer to look for an element
//It is NOT the one that selenium uses - the selenium extension throws exceptions on a null element
var ajaxIsComplete = webDriver.FindElement(By.Id("http-status"), 5);
if (ajaxIsComplete != null && ajaxIsComplete.Text.Equals("0"))
{
//optional wait for angularjs digest or compile if data is returned in ajax call
Thread.Sleep(1000);
break;
}
Thread.Sleep(100);
}
}
}
To test the WaitForAjax extension, insert a Thread.Sleep(5000) at the end of your controller method. I hope this information proves useful to someone. Once again, thank you Caleb.