I have an Angular web app that uses Protractor for e2e tests. I recently added OAuth0 authentication. I disable Angular synchronisation before redirection to the non-Angular OAuth0 page using await browser.waitForAngularEnabled(false) and that works fine. However I cannot reenable Angular synchronisation using await browser.waitForAngularEnabled(true) again for the rest of that spec file test suite or I get the infamous protractor timeout errors. I'd like to re-enable Angular synchronisation as otherwise I have to use expected conditions, waits and sleeps to ensure follow-on pages are loaded and that can result in intermittent errors.
I have read all the questions and answers and have tried all the obvious - reloading the page, getting a new page, waits, long sleeps, etc, etc.
So my question is quite specific rather than looking for suggestions - does anyone understand the mechanism Protractor uses to sync with Angular pages and do you know whether it possible or not for Angular to resync after a redirection out to, and back from, a non Angular page, i.e. am I wasting my time looking for a fix. I read up a little on the mechanism - it loads a script to be run on the page but I'm unsure why that can't be loaded again when I do a browser.get{'/') after returning from the auth0 redirection.
Note that I can leave Angular synchronisation disabled and can get things to work so I am not asking for advice on just how to get things working. If you have faced the specific problem and come up with a fix I'd love to hear it.
Any help appreciated.
Answer - yes you can reenable angular in protractor. However, protractor doesn't always work with angular apps. So just make sure protractors synchronization will be working as it should with your app AND the page is ready for this.
First, manually open the app, and get authorized. Then in console run getAllAngularTestabilities(). If this command in not available, protractor can't work with angular. If the command is successful, take a look at returned object, specifically at hasPendingMacrotasks and hasPendingMicrotasks properties of obj[0]._ngZone. If any of them is true, protractor can't work with this page. If both of them are false then you can proceed to the next step
Now, when you now the page can talk to protractor with browser.waitForAngularEnabled(true) you need to implement the following method for your tests
let login = async function (username, password) {
await browser.waitForAngularEnabled(false);
await browser.get(url);
await $usernameInput.sendKeys(username);
await $passwordInput.sendKeys(password);
await $loginButton.click();
// MOST IMPORTANTLY, YOU HAVE TO WAIT UNTIL YOUR APP FULLY LOADED
await browser.wait(
// whatever you need to wait for,
timeout,
'failure message'
);
// AND FINALLY
await browser.waitForAngularEnabled(true);
}
I mean you don't have to have this method, I just showed you the order of actions you have to follow to achieve your results.
Basically, the point is, when you login, make sure the non-angular login page is gone, and your angular page is fully loaded before reenabling waiting for angular.
Two approaches you could use:
return !obj[0]._ngZone.hasPendingMacrotasks && !obj[0]._ngZone.hasPendingMicrotasks and pass it to the browser.waitIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With