The Problem Description:
We've recently got this infamous error while opening one of the pages in our application in a Protractor end-to-end test:
Failed: Timed out waiting for asynchronous Angular tasks to finish after 50 seconds. This may be because the current page is not an Angular application.
This happens on a browser.get("/some/page/");
call in one of our tests:
describe("Test", function () {
beforeEach(function () {
browser.get("/some/page/");
});
it("should test something", function () {
// ...
});
)};
And, what is weird about our case, is that the error is not thrown on any other page in our Angular web application - Protractor syncs with Angular without any problems. ng-app
location-wise things are the same across all the pages - ng-app
is defined on the root html
tag:
<html class="ng-scope" lang="en-us" ng-app="myApp" ng-strict-di="">
The behavior is consistent - every time we navigate to this page with browser.get()
, we get this error. Any time we navigate to any other page in our app, sync works.
Note that, of course, we can turn the sync off for this page and treat it as non-angular, but this can only be considered as a workaround.
The Questions:
What else can cause Protractor-to-Angular sync fail? What should we check?
And, in general, what is the remended way to debug sync problems in Protractor?
Using currently latest Protractor 5.5.1, Angular 1.5.6.
The Problem Description:
We've recently got this infamous error while opening one of the pages in our application in a Protractor end-to-end test:
Failed: Timed out waiting for asynchronous Angular tasks to finish after 50 seconds. This may be because the current page is not an Angular application.
This happens on a browser.get("/some/page/");
call in one of our tests:
describe("Test", function () {
beforeEach(function () {
browser.get("/some/page/");
});
it("should test something", function () {
// ...
});
)};
And, what is weird about our case, is that the error is not thrown on any other page in our Angular web application - Protractor syncs with Angular without any problems. ng-app
location-wise things are the same across all the pages - ng-app
is defined on the root html
tag:
<html class="ng-scope" lang="en-us" ng-app="myApp" ng-strict-di="">
The behavior is consistent - every time we navigate to this page with browser.get()
, we get this error. Any time we navigate to any other page in our app, sync works.
Note that, of course, we can turn the sync off for this page and treat it as non-angular, but this can only be considered as a workaround.
The Questions:
What else can cause Protractor-to-Angular sync fail? What should we check?
And, in general, what is the remended way to debug sync problems in Protractor?
Using currently latest Protractor 5.5.1, Angular 1.5.6.
Share Improve this question asked Mar 17, 2017 at 19:06 alecxealecxe 475k127 gold badges1.1k silver badges1.2k bronze badges 4-
I guess there is sync issues .
https://github./angular/protractor/blob/master/docs/timeouts.md#how-to-disable-waiting-for-angular
. The solution which they are telling is same to turn the sync off or probably usedriver.browser.get()
instead ofbrowser.get()
. – Kishan Patel Commented Mar 18, 2017 at 10:55 - @KishanPatel thanks, but as I mentioned in the question, I understand that we can turn the sync off and treat the page as non-angular - this is a workaround and it would work, but we are trying to figure out why the sync does not work for this particular page and general guidelines to debug problems like this. – alecxe Commented Mar 18, 2017 at 13:52
-
Your error clearly states that it can sync because of Angular, and there are two reasons for that to happen
$http
and$timeout
- protractor will wait for both of those services to finish. If it's caused by$timeout
then you should simply replace it with$interval
and as for$http
there is no workaround unless you want to write an XHR service and use it instead of$http
– maurycy Commented Mar 20, 2017 at 22:39 -
1
@maurycy right, good points - we've heard about the
$timeout
issue before (don't recall the$http
related one). But, how would I know for sure what exactly is causing the problem? How, through debugging, I can detect the reason for a sync failure?..Thank you. – alecxe Commented Mar 20, 2017 at 22:44
2 Answers
Reset to default 7 +100Ok, so that question intrigued me so I came up with a programmatic solution on how to determine what protractor is waiting for:
var _injector = angular.element(document).injector();
var _$browser = _injector.get('$browser');
var _$http = _injector.get('$http');
var pendingTimeout = true;
//this is actually method that protractor is using while waiting to sync
//if callback is called immediately that means there are no $timeout or $http calls
_$browser.notifyWhenNoOutstandingRequests(function callback () {
pendingTimeout = false
});
setTimeout(function () {
//this is to differentiate between $http and timeouts from the "notifyWhenNoOutstandingRequests" method
if (_$http.pendingRequests.length) {
console.log('Outstanding $http requests', _$http.pendingRequests.length)
} else if (pendingTimeout) {
console.log('Outstanding timeout')
} else {
console.log('All fine in Angular, it has to be something else')
}
}, 100)
Here in the plunker http://plnkr.co/edit/O0CkpnsnUuwEAV8I2Jil?p=preview you can experiment with the timeout and the $http call, my delayed endpoint will wait for 10 seconds before resolving the call, hope that this will be helpful for you
I agree with @maurycy that the issue is $http/$timeout related. The simple fix is normally to replace $timeout with $interval as documented here: https://github./angular/protractor/blob/master/docs/timeouts.md
Remendations:
merge these sane defaults:
allScriptsTimeout: 60000, // 1 minute
jasmineNodeOpts: {
defaultTimeoutInterval: 300000
// 5 minutes. Allows for 5 mands spanning the full synchronization timeout.
}
If you want to find the culprit of $http/$timeout, I would use angular decorators to apply custom logic around these services. This is also a good way to mock angular services accessing third party services. https://docs.angularjs/guide/decorators
//DISCLOSURE: Unlinted & Untested.
beforeAll(() => {
browser.addMockModule('culpritMock', () => {
angular.module('culpritMock', [])
.config(['$httpProvider',
$httpProvider => $httpProvider.interceptors.push('httpCounterInterceptor')
])
.factory('httpCounterInterceptor', ['$q', '$window', ($q, $window) => {
if ($window.httpCounterInterceptor == null) {
$window.httpCounterInterceptor = {};
}
return {
request: config => {
$window.httpCounterInterceptor[config.url] = 'started';
return config;
},
response: response => {
$window.httpCounterInterceptor[response.config.url] = 'pleted';
return response;
},
responseError: rejection => {
$window.httpCounterInterceptor[rejection.config.url] = 'error';
return $q.reject(rejection);
}
};
}])
.decorator('$timeout', ['$delegate', $delegate => {
const originalTimeout = $delegate;
function modifiedTimeout() {
console.log(arguments);
return originalTimeout.apply(null, arguments);
}
modifiedTimeout.cancel = function(promise) {
return $delegate.cancel(promise);
}
return modifiedTimeout;
}]);
});
});