Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

I have SPA application on on stack ASP MVC + AngularJS and i'd like to test UI. For a now i'm trying for Selenium with PhantomJS and WebKit drivers.

Testing page - view with single element - the list of <li> which loads dynamically from server and bind by Angular.

<div id="items">
    <li>text</li>
    <li>text2</li>
</div>

I'm trying to pass test

_driver.FindElements(By.TagName('li'))

The problem is that at this moment there is no elements loaded, and _driver.PageSource doesn't contain elements too.

How can i wait for items loaded? Please do not suggest Thread.Sleep()

share|improve this question

6 Answers 6

If you're using AngularJS then using Protractor is a good idea.

If you use protractor you can use it's waitForAngular() method which will wait for http requests to complete. It's still good practise to wait for elements to be displayed before acting on them, depending on your language and implementation it might look this in a synchronous language

WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));

Or in JS you can use wait method which executes a function until it returns true

browser.wait(function () {
    return browser.driver.isElementPresent(elementToFind);
});
share|improve this answer

Beside eddiec's suggest. If you test an AngularJS app, I strongly suggest you to think about protractor

Protractor will help you solve the waiting matter (sync, async). However, there are some notes

1 - You need to develop your test in javascript

2 - There are some different mechanism in handling flow

share|improve this answer
    
and what about E2E testing? i'd like to get "happy path". For unit tests i'm using Jasmine. Is it possible to test UI with Jasmine? – deeptowncitizen Aug 1 '14 at 8:36
    
protractor is used for e2e. You can use it with Jasmine, Cucumber and Mocha test framework. However, Mocha has limited beta support. You will need to include your own assertion framework if working with mocha. – Nguyen Vu Hoang Aug 1 '14 at 9:00
    
I'm using ASP MVC, AngularJS, Jasmine. Can i use 'protractor' without Node.JS? – deeptowncitizen Aug 1 '14 at 10:05
    
I'm afraid nope. – Nguyen Vu Hoang Aug 1 '14 at 10:07

I added this code and it works

WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));
share|improve this answer
1  
If you copy code from the top answer, then please write something to distinguish your answer from the other answer. – Artjom B. Jan 14 at 7:49

This will wait for page loads / jquery.ajax (if present) and $http calls, and any accompanying digest/render cycle, throw it in a utility function and wait away.

/* C# Example
 var pageLoadWait = new WebDriverWait(WebDriver, TimeSpan.FromSeconds(timeout));
            pageLoadWait.Until<bool>(
                (driver) =>
                {
                    return (bool)JS.ExecuteScript(
@"*/
try {
  if (document.readyState !== 'complete') {
    return false; // Page not loaded yet
  }
  if (window.jQuery) {
    if (window.jQuery.active) {
      return false;
    } else if (window.jQuery.ajax && window.jQuery.ajax.active) {
      return false;
    }
  }
  if (window.angular) {
    if (!window.qa) {
      // Used to track the render cycle finish after loading is complete
      window.qa = {
        doneRendering: false
      };
    }
    // Get the angular injector for this app (change element if necessary)
    var injector = window.angular.element('body').injector();
    // Store providers to use for these checks
    var $rootScope = injector.get('$rootScope');
    var $http = injector.get('$http');
    var $timeout = injector.get('$timeout');
    // Check if digest
    if ($rootScope.$$phase === '$apply' || $rootScope.$$phase === '$digest' || $http.pendingRequests.length !== 0) {
      window.qa.doneRendering = false;
      return false; // Angular digesting or loading data
    }
    if (!window.qa.doneRendering) {
      // Set timeout to mark angular rendering as finished
      $timeout(function() {
        window.qa.doneRendering = true;
      }, 0);
      return false;
    }
  }
  return true;
} catch (ex) {
  return false;
}
/*");
                });*/

share|improve this answer

I did the following code and it helped me for the async race condition failures.

$window._docReady = function () {
        var phase = $scope.$root.$$phase;
        return $http.pendingRequests.length === 0 && phase !== '$apply' && phase !== '$digest';
    }

Now in selenium PageObject model, you can wait for

Object result = ((RemoteWebDriver) driver).executeScript("return _docReady();");
                    return result == null ? false : (Boolean) result;
share|improve this answer

If your web app is indeed created with Angular as you say, the best way to do end-to-end testing is with Protractor.

Internally, Protractor uses its own waitForAngular method, to ensure Protractor waits automatically until Angular has finished modifying the DOM.

Thus, in the normal case, you would never need to write an explicit wait in your test cases: Protractor does that for you.

You can look at the Angular Phonecat tutorial to learn how to set up Protractor.

If you want to use Protractor seriously, you will want to adopt . If you want an example of that have a look at my page object test suite for the Angular Phonecat.

With Protractor you write your tests in Javascript (Protractor is indeed based on Node), and not in C# -- but in return Protractor handles all waiting for you.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.