Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protractor: how to wait for full load of bootstrapped AngularJS

I have a bootstrapped Angular (1.2.6) app. This means it doesn't have an explicit ng-app. As such, I've run into all sorts of problems getting Protractor framework'd tests to work (using SauceLabs and grunt-protractor-runner).

The errors vary based on what I try, but generally:

 Error: Angular could not be found on the page http://xxx:9000/ :
 angular never provided resumeBootstrap

Or...

Error: Error while waiting for Protractor to sync with the page: {}

I've found a few proposed solutions which I've tried. Including those found in this rich thread, as well as here, too. Nothing I do, though, gets things working.

I've tried to use angular.resumeBootstrap in the bootstrapping like so (note I tried multiple variations of this to no avail, including trying to set an ng-app programatically on the document body):

angular.element( document ).ready( function() {
  window.name = 'NG_DEFER_BOOTSTRAP!'
  angular.bootstrap( document, [ 'app' ] );
  setTimeout( angular.resumeBootstrap, 0 );
});

The error for this, as others have found, is weird:

UnknownError: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element
'<body ng-app="" ng-controller="ApplicationController" class=" ng-scope pace-done">'

What's weird/annoying is that, at least looking in Sauce Labs session, it appears that this test is working... it's just weirdly thinking that it's been bootstrapped twice.

I've also tried using various combinations of waitForAngular, wait, and others in the test itself. Here's one variation I've tried:

it( 'should load the home page', function() {
  ptor = protractor.getInstance();
  ptor.waitForAngular();
  ptor.driver.get( 'http://xxx:9000/' );
  ptor.driver.wait( function() {
    return ptor.getCurrentUrl().then( function() {
      return ptor.isElementPresent( by.id( 'signIn' ) ).then( function() {
        console.log('we are here!');
        return true;
      });
    });
  })
  .then( function() {
    expect( ptor.isElementPresent( by.id( 'signIn' ) ) ).toBe( true );
  });
});

This results in errors like the following:

1) e2e: home should load the home page
  Message: timeout: timed out after 20000 msec waiting for spec to complete
  Stacktrace: undefined

I've also tried increasing various timeouts in the config file to no avail.

Any help would be much appreciated!

like image 472
pjb Avatar asked Dec 06 '14 05:12

pjb


1 Answers

You should separate the test in two 'it'-steps. Like this:

it( 'should load angular', function() {
  ptor = protractor.getInstance();
  ptor.waitForAngular();
})

it( 'should load the home page', function() {
  ptor.driver.get( 'http://xxx:9000/' );
  ptor.driver.wait( function() {
    return ptor.getCurrentUrl().then( function() {
      return ptor.isElementPresent( by.id( 'signIn' ) ).then( function()     {
        console.log('we are here!');
        return true;
      });
    });
  })
  .then( function() {
    expect( ptor.isElementPresent( by.id( 'signIn' ) ) ).toBe( true );
  });
});

The problem with protractor is that every command runs without waiting for the prior step to complete. So, ptor.waitForAngular() and ptor.driver.get( 'http://xxx:9000/' ) are running at almost the same time. If you separate these into two steps, protractor moves on after the first 'it'-step is done.

like image 166
apoh Avatar answered Sep 23 '22 07:09

apoh