This post is for people running into the following error when running a Protractor test for their Angular apps:

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

Many search results on the internet tell you that you can solve it by adding browser.ignoreSynchronization = true; to your code, with a remark like:

the key is to browser.sleep(3000) to have each page wait until Protractor is in sync with the project

Unfortunately, this usually is not what you actually want.

How to solve it

Most of the time, the issue will be that you’ve added ng-app to a different element than the <body>, which is where Protractor guesses that your Angular app is located in the page.

You can use a different element, but you will have to tell Protractor which one. You can do so by specifying a CSS selector referring to the element to the rootElement property of your Protractor configuration file. A selector that will work most of the time is

  rootElement: '*[ng-app]',

In other words, this tells Protractor to find Angular on the element with the attribute ng-app.

Why does ignore synchronization work?

Protractor runs on top of WebDriverJS. WebDriverJS is a Javascript interface that let’s you control browsers programmatically, which is useful for e.g. automatic tests.

So then… What does Protractor add? The problem in testing Angular apps using WebDriverJS is that Angular has its own event loop separate from the browser’s. This means that when you execute WebDriverJS commands, Angular might still be doing its thing.

One could work around this by telling WebDriverJS to wait for an arbitrary amount of time (i.e. 3000ms in the example above) and hope that Angular has settled down during that time. Of course, that wasn’t pretty. Thus, Protractor was created to synchronize your tests with Angular’s event loop, by deferring running your next command until after Angular has finished processing the previous one.

This is very nice and all, but becomes problematic when you’re testing a website of which some pages are written in Angular, and some pages aren’t. In the latter case, no matter how long Protractor waits, there is no Angular to complete its cycle – in which case it will terminate with the error above.

Thus, for non-Angular pages, you can tell Protractor not to look for Angular by setting browser.ignoreSynchronization = true – which in practical terms will mean that you’re just using WebDriverJS.

So by adding that to your configuration when Protractor cannot find Angular on your page, you’re giving up on all that makes testing Angular apps easier than plain WebDriverJS. And yes, adding browser.sleep after all your commands will likely work, but it’s cumbersome, will break as soon as Angular takes longer than the pause you set, and makes your tests take excessively long.

The bottom line

  • Use the rootElement property in your Protractor configuration.
  • Only use browser.ignoreSynchronization = true when testing a page that does not use Angular.

License

This work by Vincent Tunru is licensed under a Creative Commons Attribution 4.0 International License.