Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there something like jQuery.active in angularjs?

I am using selenium to test my application. I have lots of ajax calls that use $resource or $http. It would be nice if there was a way to poll any active ajax requests in angular so that selenium could wait until those requests were completed.

I supposed I could place an element on the page (for selenium to look for) and hook it up to some flag that gets set on success but that could get pretty messy.

There is a very effective way to do this when using jQuery as described here.

Or does selenium have a way to do this that I haven't found?

Couldn't find anything in the docs? Any suggestions? Thanks.

EDIT: Caleb Boyd's answer is correct and a great solution to the problem of detecting angular ajax calls while using selenium web driver. Here is quick implementation of how I use this. I actually used a variation of caleb's code from this link, which included ajax errors. It is however, essentially the same thing. Thanks Caleb.

Add this script and element to the bottom of your page. Just remove 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>

I use NUnit for my testing framework.

[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
     }
}

Here 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);
            }
        }
}

Try testing the WaitForAjax extension by putting a Thread.Sleep(5000) at the bottom of your controller method. Hope this helps someone. Thanks again Caleb.

like image 817
trevorc Avatar asked Dec 04 '22 07:12

trevorc


1 Answers

Yes I believe there is a callback you can use on angular. I have used it in a large project for Test Automation using Ruby. Below is the call. We are waiting for 30 seconds until the pending Requests.length becomes 0. The string "0" because the return value is always string.

Watir::Wait.until(30) {
@browser.execute_script("return angular.element(document.body).injector().get(\'$http\').pendingRequests.length;") == "0"
}
like image 117
Selenium Framework Avatar answered Dec 06 '22 20:12

Selenium Framework