Protractor: Protractor E2E test times out when app polls an API at regular intervals

Created on 21 Aug 2013  路  32Comments  路  Source: angular/protractor

Our app has a poller which makes calls to an API every 3 seconds. When I load a page with has an active instance of the poller Protractor will always time out.

The poller is started when the page loads and uses the Angular $timeout function.

Is there a way to get Protractor to ignore the poller or send a signal to the app to pause the poller momentarily so the E2E test can finish running?

bug

All 32 comments

Not yet - Protractor attempts to avoid syncing problems by waiting for any $timeout calls to finish, so if you have constant calls it will time out. This is probably an issue that others will run into, so I'll call it a bug.

Thanks @juliemr. If you more details on what the app is doing (to reproduce or test a fix) let me know.

Would love to see it fixed :)
It's been a recurring problem with Angular E2E testing, even with Testacular.

Will be exploring this issue in the poll branch

The issue is basically - how do I tell if the site is just being slow, or if there's some intentional polling going on and it's OK to resume the E2E test?

First step - give better error messages when timeouts occur.

For the record, here's a link to the Angular Scenario Runner Issue of this same thing.

Added a kind of lame temporary fix with 73821fb6b6d252a93cc15ce990b4ec4738b87b95

You can turn off synchronization using protractor.ignoreSynchronization

But of course, this means that Protractor will NEVER wait for $timeout or $http to finish before fulfilling, which can make tests flaky. Leaving this bug open as I discuss better solutions.

EDIT: See my note below about ignoreSynchronization being an instance variable, not a static / class variable.

Important comment!

ignoreSynchronization is an instance variable, NOT a static variable of the protractor namespace! I apologize for making this unclear above. So if you have

var ptor = protractor.getInstance()

You will want to set ptor.ignoreSynchronization, NOT protractor.ignoreSynchronization

Sorry for the confusion!

@juliemr, I'm stuck. I don't know is it ignoreSynchronization not working or my code is wrong:



var util = require('util');

var loginAsExistingUser;
var firstName = 'Andrew';
var lastName = 'Auto1'

loginAsExistingUser = function (ptor) {
    ptor.findElement(protractor.By.css('input[name=email]')).sendKeys("email");
    ptor.findElement(protractor.By.css('input[name=password]')).sendKeys("123");
    ptor.findElement(protractor.By.css('button.green.large')).click();
};

describe('Portal SignIn Page', function() {
    var ptor;


    beforeEach(function() {
        ptor = protractor.getInstance();
        ptor.ignoreSynchronization = true;
        console.log("What's up with ignoreSynchronization?" + ptor.ignoreSynchronization);
        //ptor.driver.manage().timeouts().setScriptTimeout(500);
    }, 20000);


    it ('Check URL after Sign In', function(){
        ptor.get('#/login/');
        ptor.waitForAngular();
        var expectedURL = ptor.baseUrl + 'home';
        loginAsExistingUser(ptor);
        ptor.sleep(5000);
        expect(ptor.getCurrentUrl()).toBe(expectedURL);

    }, 20000);

    it ('Checking username', function(){
       var name = (firstName + lastName);
       ptor.findElement(protractor.By.css('.login-menu-button')).getText().
           then(function(username) {
               expect(username).toEqual(name);
           });
    }, 30000);

});

It looks like ignoreSynchronization gets set correct but test still times out:

Failures:

  1) Portal SignIn Page Checking username
   Message:
     timeout: timed out after 30000 msec waiting for spec to complete
   Stacktrace:
     undefined

Finished in 54.854 seconds
3 tests, 3 assertions, 1 failure

Hey everyone,

With Angular 1.2rc3, you can now use the $interval service to do your polling! Protractor will _not_ wait for anything registered with $interval! Check out https://github.com/angular/angular.js/commit/2b5ce84fca7b41fca24707e163ec6af84bc12e83 for more details.

In our case, we have our own service that keep synchronized a local model with the server database using long polling.

As a workaround to this issue, we replaced clientSideScripts.waitForAngular with a function that wait for angular $$phase and wait for our own service to be ready. This solve all our issues.

@juliemr: Will be really handy if it is possible to overwrite the waitForAngular function from test configuration!

@fedenunez Could you share more details about this $$phase patch?

I'm currently facing the same issue and don't have control over the source base to change $timeout usage to $interval as @juliemr mentions

Using browser.ignoreSynchronization = true; breaks the tests event with manuals browser.sleep(...)

@elgalu under protractor/lib/clientsidescripts.js you will find the implementation of waitForAngular function. That function is executed by protractor to synchronize the Control Flow with angular state.

I just replaced that code with my own implementation that looks something like this:

clientSideScripts.waitForAngular = function() {
  var selector = arguments[0];
  var callback = arguments[1];
  var TIMEOUT_MS        = 18000;   // ms
  var INTERVAL_MS       = 5; //ms
  var elapsed        = 0;
  var el = document.querySelector(selector);

  // "inject" $rootScope service
  var $rootScope = angular.element(el).injector().get('$rootScope');

  // "inject" our own longpolling service 
  var modelService = angular.element(el).injector().get('model');

  var checkLoop = function() {
    if (elapsed <= TIMEOUT_MS ) {

      // check angular digest state and check our longpoll service state (modelService state)
      if (!$rootScope.$$phase && ( !modelService.isProcessing() )) {

       // everything is synchronized!
       callback(); 

      } else { 

        // somebody is still processing, wait a little bit more.
        elapsed = elapsed +  INTERVAL_MS;
        setTimeout( checkLoop, INTERVAL_MS );

      }
    }  else {
      callback( "Timedout while waiting for angular!" );
    }
  }

  //initialize checking loop
  setTimeout( checkLoop, 0 );
};

I hope this help!

Any update on this? I still need to set ptor.ignoreSynchronization = true; in beforeEach() and ptor.ignoreSynchronization = false; in afterEach().

I have a situation where we're loading an index page, which can take quite a long time - about ten seconds.
Protractor then goes and finds a few items on the index page, clicks a button to open a modal (Another HTTP request), fills out a form and clicks a button (Another HTTP request), then repeats.
It does this for almost 100 items, or it would if it could get through three of them before getting -

timeout: timed out after 30000 msec waiting for spec to complete

This is a huge pain in the ass. Any ideas on how to fix this, or just indefinitely extend the the 30000ms limit?

I use 7mins spec timeouts, also have long running e2e tests:

    allScriptsTimeout: 7*60*1000,

Should add that we're already using

allScriptsTimeout: 120000

And still getting the 3000 msec error

You're getting the 30secs timeout on Firefox or Chrome or Both?

Chrome 33.0.1750.152 Angular 1.2.8 Protractor 0.20.1
We're only testing in Chrome - thankfully we have very specific requirements from the client

@wilfredjamesgodfrey it sounds like your tests actually take more than 30 seconds. Increasing the timeout in this case seems reasonable.

thanks @juliemr, I would do that with allScriptsTimeout, right? It just doesn't seem to be working. Re: https://github.com/angular/protractor/issues/49#issuecomment-38747093

Ah, that's amazing @juliemr. Thanks!

I have a permanent $interval in my app and I can't stop it via a click event since it waits to synchronize before running the test. Is there a workaround to this?

Given that Angular 2, as of yet, at least to my knowledge, does not provide an interval service for polling. Would you propose people using protractor to test angular 2 apps workaround this issue? In cases where dropping synchronization is not possible.
In our use case we have a timeout of 20 minutes, set up as a sort of ticker, to revalidate a JWT token. When our protractor tests hit the homepage, they sit there waiting for a 20min timeout.

Cheers,
Nuno

@nvsoares That is exactly what I wanted to write as well! Is there any solution or workaround for this yet?

Edit:
I found this issue, which I guess should be linked here.

Please see our updated documentation (https://github.com/angular/protractor/blob/master/docs/timeouts.md#angular) on this issue and let us know if we need to make it more clear. Thanks!

@juliemr
using $interval service is not working for long running api calls when running protractor e2e tests.. I am still getting timeout for pending http tasks. What could be the fix for this issue? please respond asap i am struggling with this issue since couple of weeks.
Thanks
Murali

@MuraliMolluru ,

Addressing protractor members won't help directly. If you still experience problems please create a new issue and use the issue template in which you provide all needed info. Otherwise you can ask a question on Stackoverflow with the 'protractor' tag or post in the Gitter Channel to get help.

@wswebcreation
I had already created an issue but it was closed without answer and told me that i have to ask in stackoverflow. I even asked in stakoverflow but have not get any answer.

@MuraliMolluru , can you give me the link on SO, then I can check if I can help you there

@wswebcreation Did u get a chance to look at the issue?

Was this page helpful?
0 / 5 - 0 ratings