Open jbedard opened 6 years ago
For reference, this is my workaround...
This method must be invoked essentially anytime that AngularJS can potentially be loaded such as when clicking links to AngularJS pages in your app. I assume there is a bit of a race condition where this method (or at least the NG_DEFER_BOOTSTRAP
part) must be invoked before the AngularJS app actually bootstraps. If the the click was embedded into this method that could be worked around.
//Workaround for https://github.com/angular/protractor/issues/4724
function async loadAngularJS() {
//Abort if `resumeBootstrap` has already occured
if (await browser.executeScript(`return "__TESTABILITY__NG1_APP_ROOT_INJECTOR__" in window;`)) {
return;
}
//Might have to re-insert the "NG_DEFER_BOOTSTRAP!" if the name has been changed since protractor loaded the page
if (!await browser.executeScript("window.name.includes('NG_DEFER_BOOTSTRAP!')")) {
await browser.executeScript("window.name = 'NG_DEFER_BOOTSTRAP!' + name");
}
//Wait for the AngularJS bundle to download and initialize
await browser.wait(ExpectedConditions.presenceOf($("a1-app")), 5000, "AngularJS a1-app");
// Run the protractor pre-bootstrap logic and resumeBootstrap
// Based on https://github.com/angular/protractor/blob/5.3.0/lib/browser.ts#L950-L969
{
let moduleNames = [];
for (const {name, script, args} of browser.mockModules_) {
moduleNames.push(name);
await browser.executeScriptWithDescription(script, "add mock module " + name, ...args);
}
await browser.executeScriptWithDescription(
//TODO: must manually assign __TESTABILITY__NG1_APP_ROOT_INJECTOR__ (https://github.com/angular/angular/issues/22723)
`window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = angular.resumeBootstrap(arguments[0]) || angular.element("a1-app").injector();`,
"resume bootstrap",
moduleNames
);
}
//Wait for the initial AngularJS page to finish loading
await browser.waitForAngularEnabled(true);
await browser.waitForAngular();
}
There's also a workaround for https://github.com/angular/angular/issues/22723 in there.
This seems to still impact safari 12 and 13 (current versions). Did anyone identify a solution or a mock that can be configured inside the protractor configuration?
While in the transition from AngularJS to Angular I've started lazy-loading the legacy AngularJS app only when a user navigates to a legacy page. Essentially exactly what is described at https://blog.nrwl.io/using-ngupgrade-like-a-pro-lazy-loading-angularjs-applications-469819f5c86.
Note that the lazy-loaded bundle includes ng-upgrade, AngularJS and the AngularJS app, this bundle is lazy loaded by the Angular router when you navigate to a legacy page.
The issue is that on page load protractor does not detect AngularJS (which is correct because it hasn't loaded yet), so it doesn't inject the
mockModules
+resumeBootstrap
. However the defer label is inserted. This means the bootstrapping is deferred, but nothing ever resumes it. This causes the navigation to an AngularJS page to defer and never finish the bootstrapping, normally getting stuck and timing out on a blank page.v8.9.4
5.2.0
5.2.7, 1.6.8
Workaround I've essentially copied the injecting the
mockModules
+resumeBootstrap
and invoke it manually whenever navigating to an AngularJS route, if not done already.Fix Maybe make injecting the
mockModules
+resumeBootstrap
a public method onbrowser
that can be invoked manually? Or somehow detect if/when AngularJS is lazy loaded?