Removing sleeps from your AngularJS Protractor tests

sleep()

The Protractor framework does a great job of shielding you from the inherent difficulties of testing your asynchronous Angular app. Using ControlFlow it keeps the list of pending promises hence executing the test in a logical manner. However this is not always enough. Sometimes the tests outrun browser! In such cases you might just be tempted to put in a browser.sleep(2000) to allow everything to get back on track.

wait()

Sleeps are brittle. Sleeps put your tests at the mercy of changes in your test environments (network speed, machine performance etc). They make your tests slower. From a maintainability point of view they are ambiguous to someone else reading your code. Why were the put there? Is the sleep long enough? They are an acceptance that you don't really know what is going on with your code and in my opinion should be banned (or at least you should try your best to resist the quick win they give you!).
Here are some alternatives to sleep using web drivers wait function....

1) Use angular’s Expected Conditions

browser.wait(  
   protractor.ExpectedConditions.visibilityOf(
      element(by.id('header')
), 5000);

2) Use web driver directly

function waitForElement (locator) {  
   browser.driver.wait(function () {
       return browser.driver.isElementPresent(locator);
   }, 5000);
}
waitForElement(element(by.id('header'));  

This function is useful for pages that don’t have angular (say you want to test your login page).

3) For more custom conditions on a promise you can use the following function

waitForCondition (promise, testFn) {  
   browser.wait(function () {
       var deferred = protractor.promise.defer();
       promise.then(function (data) {
           deferred.fulfill(testFn(data));
       });
       return deferred.promise;
   }, 5000);
}

For example we have a function in our page object that returns the number of rows in a table (returns as a promise). We call the waitForCondition function as follows:

waitForCondition(pageObject.getNumberRowsInTable(), function (rows) {  
 return rows.length === 1;
});

4) Finally to wait for the URL to change

function waitForUrl(expectedUrlFragment){  
  browser.driver.wait(function() {
    return browser.driver.getCurrentUrl().then(function(url) {
   return new RegExp(expectedUrlFragment).test(url);
 });
}, 5000)};

Kevin Duggan

Kevin Duggan is Technical Team Lead on Newsweaver’s new Cross-Channel Analytics product. He has 10 years experience delivering enterprise solutions for the Energy, Finance and Pharmaceutical sector

Cork

Subscribe to Newsweaver Technology Blog

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!