Testing with Protractor: how to fix synchronization issues

November 4, 2019

We love tools that automate our work— we can do more with fewer efforts, season it with some open-source love and, oh boy, we're gonna use it for sure. However, open-source software is a community-driven approach, there may be hardly any information about it on the internet or no insights at all. If you face errors that cannot be solved or don’t have enough understanding of the tool while exploring, you can give up on the tool without discovering all its useful features.

We want to delve into two possible synchronization issues you may face while working with Protractor—an end-to-end test framework for Angular and AngularJS apps. The good news is that there’s official documentation from the Protractor team, but the bad news is that it didn’t help us to solve these issues, so we'll share the solution we came up with.

“Angular can't be found on the page” error

Let’s check the basic solution Protractor FAQ provides:

Protractor supports Angular and AngularJS 1.0.6/1.1.4 and higher—check that your version of Angular is upgraded.

For AngularJS apps, the angular variable is expected to be available in the global context. To check this, try opening Chrome DevTools or Firefox and see if angular is defined.

For Angular apps, you should see a global method getAllAngularTestabilities.

“Waiting for Angular” timeout error

Asynchronous and multicomponent WebDriver tests may cause various timeout errors in a Protractor test. One of them can be the Waiting for Angular” error. Here’s the information from Protractor’s Documentation:

Before performing any action, Protractor waits until there are no pending asynchronous tasks in your Angular application. This means that all timeouts and HTTP requests are finished.

  • An error in your test results will look like this:  Timed out waiting for asynchronous Angular tasks to finish after 11 seconds.
  • Default timeout: 11 seconds
  • How to change: Add allScriptsTimeout: timeout_in_millis to your Protractor configuration file.

You may also need to fix this problem by investigating and fixing an issue on the application level.

AngularJS

If your AngularJS application continuously polls $timeout or $http, Protractor will wait indefinitely and time out. To fix infinite timeout, you should use the $interval for anything that polls continuously (Note: $interval was introduced in Angular 1.2rc3).

Angular

For Angular apps, Protractor will wait until the Angular Zone stabilizes. This means long-running async operations will block your test from continuing. To work around this, run the following tasks outside of the Angular Zone. 

Example:


this.ngZone.runOutsideAngular(() => {
 setTimeout(() => {
  // Changes here will not propagate into your view.
  this.ngZone.run(() => {
   // Run inside the ngZone to trigger change detection.
  });
 }, REALLY_LONG_DELAY);
});

Resolving errors 

Since tips from the official documentation didn’t help us out in the way we expected, we tried disabling synchronization. Still, this caused a large number of issuespage elements didn't have enough time to load, and the test failed. Waiting for page items to load would require us to build additional functions. Not the best way. We were upset but remained resolute. We came to the following solution to cover both errors:

  1. Create a small test containing one action to navigate the page and one assertion that displays an element.
  2. Detect the reason for the issue: 

if ('You are sure that all your application is written with Angular, but you get the error “Angular could not be found on the page”') {
 try {
  browser.waitForAngularEnabled(false);
  browser.get('/your-page.html');
  expect(element(by.id('logo')).isDisplayed()).toBeTruthy();
// If this code works, check out examples of detected code parts below in this article.
 } 
}else if ('You are not sure that all your application is written with Angular') {
 try {
  checkItManuallyforAngularJS = 'For AngularJS apps, the angular variable is expected to be available in the global context. Try opening Chrome DevTools or Firefox and see if Angular is defined.';
  checkItManuallyforAngular = 'For Angular apps, you should see a global method getAllAngularTestabilities.';
 } 
// Can't manually check? Check the hints on identifying technologies the site is built on*
}else if ('You are sure that the main part of your application is written with Angular, but login page (or any other) isn’t.') {
 try {
  browser.waitForAngularEnabled(false);
  browser.get('/non-angular-login-page.html');  element(by.id('username')).sendKeys('Jane');
  element(by.id('password')).sendKeys('1234');
  element(by.id('button')).click();  browser.waitForAngularEnabled(true);
  browser.get('/page-containing-angular.html');
 }
}

* Here are the hints on identifying technologies the site is built on.

As a result, you should know which part of the application is written using Angular and which part is not.

  1. For each part of the app that isn't written using Angular, use the following function:


browser.waitForAngularEnabled(false);

Also, don’t forget to enable synchronization when you’re done working with the non-Angular parts. Here’s the code:


browser.waitForAngularEnabled(true);

  1. Detect code that needs to be rewritten:

Try to investigate which part of the code always tries to do regular actions, which one is detecting user actions, and which always triggers change detection:

a. Find all setInterval functions, Observable.timers, timers, etc. 

b. Comment out all found parts, build the application, and run the small test (be sure to enable  synchronization).

c. Repeat steps 4.a and 4.b until the test passes.

d. Go back to commented code lines. By process of elimination, uncomment all parts which are not related to synchronization.

e. When all parts of the code which blocked synchronization earlier have been detected, rewrite the code—import ngZone to the component and use the runOutsideAngular function. 

Examples of detected code parts

To better understand which parts of an application you may need to rewrite, see the examples below:

Examples of detected code parts

Conclusion

Needless to say that using open-source tools makes our lives easier. Unfortunately, when working with a new tool, you may often face various issues and don’t have the right example of fixing them. Lack of exhaustive documentation and speedy support can be challenging at times. 

Specializing in Angular web development, we need to find more and more relevant best practices to follow. Earlier, we talked about Cypress testing, and in this article we dived into synchronization issues that might occur while testing Angular-based apps with Protractor

We hope that you’ll enjoy working with Protractor even more after reading this article! We wish you good luck with conquering new QA-horizons!

Subscribe to find out more

Thank you!

Your submission has been received!
Oops! Something went wrong while submitting the form.

More articles

Want to work with us?

Let's discuss how Valor Software can help with your development needs!