Automatic Angular synchronization fails to recover after waitForAngularEnabled is toggled
0 reputation · 03 Nov 2024, 16:25 UTC
0 reputation · 03 Nov 2024, 16:25 UTC
Goal: diagnose whether Protractor's automatic Angular synchronization can be safely toggled off and back on within a single browser session without leaving stale stability state.
Protractor waits for pending $http requests, active $timeout intervals, and element finder activity before actions. browser.waitForAngularEnabled(false) disables this for non-Angular pages and persists for the session. Documentation warns that forgetting to re-enable it breaks later Angular interactions, but it does not state whether re-enabling clears pending-task tracking or resets internal timers. This matters for hybrid apps that alternate between Angular and server-rendered pages.
Assumes a final Protractor release with selenium-webdriver promise control flow; behavior with async/await may differ by version.
Does calling browser.waitForAngularEnabled(true) after false clear Protractor's pending-request, timer, and finder-activity tracking for the current Angular zone?
If stale state remains, is restarting the browser session the only supported way to restore reliable synchronization?
Does the answer change when tests use async/await instead of Protractor's promise control flow?
33275 reputation · 03 Nov 2024, 20:21 UTC
Calling browser.waitForAngularEnabled(true) after it was set to false does **not** clear Protractor’s internal tracking of pending $http requests, $timeout callbacks, or element‑finder activity. The flag only turns the waiting mechanism on or off; any Angular tasks that were already queued while synchronization was disabled remain pending, so the next Angular interaction may hang or fail.
When waitForAngularEnabled(false) is called, Protractor simply stops checking Angular’s stability. Any $http or $timeout that started before the flag was flipped continues to run and increments Angular’s pending request counter. Because Protractor never asks Angular to reset that counter, re‑enabling the flag leaves the counter at a non‑zero value, causing subsequent Angular commands to wait indefinitely (or until the default timeout expires).
browser.waitForAngularEnabled(true), force a navigation that creates a fresh Angular zone, e.g. browser.get(browser.getCurrentUrl()) or browser.refresh().browser.restart()) if a full reset is required.browser.executeScript('return angular.getTestability(document).getPendingRequestCount();') before and after the navigation.If your application uses long‑running $timeout or $http callbacks that are deliberately left pending across page changes, knowing whether such tasks exist will determine whether a simple page reload suffices or a full browser restart is needed. Please confirm whether any pending Angular timers remain after the toggle.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 04 Nov 2024, 00:18 UTC
To clarify the behavior described in the previous response: the issue isn't that Protractor caches a "stale" state internally, but that it resumes querying a live Angular zone that may still be unstable. When browser.waitForAngularEnabled(true) is called, Protractor simply resumes calling angular.getTestability(document) before the next action.
If the application triggered a long-running $timeout or $http request while synchronization was disabled, those tasks remain active in the browser's memory. Consequently, the first command after re-enabling synchronization will see a non-zero pending task count and wait until the timeout expires, even though the "toggle" itself worked perfectly.
To verify if a hang is caused by actual pending tasks versus a failure of the toggle, you can execute this snippet during the hang:
browser.executeScript('return angular.getTestability(document).isStable();')
If this returns false, the synchronization is working as intended; the application is simply not stable.