tl;dr Protractor can help you catch issues with NgZone and so, indirectly, help you improve the performance of your app!

We use to know Protractor as a testing tool to automate e2e testing, it is very great to do his job but in some case, like this one, it can even help you to find performance problem with your app.

The issue

Few days ago we have finalized our application and to facilitate the boring job of QAing our app. But I found an issue in my e2e tests, Protractor was complaining only on one page of our app with the error:



While waiting for element with locator — Locator: By(css selector, i-floating-icon) Failed: Timed out waiting for asynchronous Angular tasks to finish after 15 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular While waiting for element with locator — Locator: By(css selector, i-floating-icon)

The line failing in my spec is:

browser.wait(EC.presenceOf($(‘i-floating-icon’)), 2000);

And even changing it to

browser.wait(EC.presenceOf($(‘html’)), 2000);

the issue was still happening and started to drive me crazy!

The debug

So I read the documentation in the link that Protractor give me in the error message and I can read this:

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 these tasks outside the Angular zone.

And I also started my favorite friend: The performance tab of the Chrome DevTools. I record 5 seconds of doing nothing on this page and here is the result:

Yellow/blue? are scripting = NgZone tick, Green? CSS animation on the page, ignore them…

As a comparison, here it’s the profile of a similar page but with no issue when doing e2e test:

YEY! Nothing happening when user is doing nothing is great, no ?!

The solution

So I started to comment every components in my app to find the one causing this infinite tick of NgZone and found the bad boy. I use hls.js, and I remember having read somewhere (???) that third party library doing heavy stuff should be executed outside the Angular context to improve quality… and today I understand why.

So In my code I have:

const hls = new Hls();



hls.loadSource(src);

hls.attachMedia(videoEl);

hls.on(Hls.Events.MANIFEST_PARSED, () => this.playAfterLoad(videoEl));

And simply surround that with a runOutsideAngular :

this.ngZone.runOutsideAngular(() => {

const hls = new Hls();



hls.loadSource(src);

hls.attachMedia(videoEl);

hls.on(Hls.Events.MANIFEST_PARSED, () => {

this.ngZone.run(() => {

this.playAfterLoad(videoEl);

})

});

});

=

Yellow/blue? No script (NgZone tick) anymore, only Green (CSS animation remains)

And Protractor? oh don’t worry it is happy too and all tests are now passing successfully!