20

I am curious how does waitForAngularEnabled() work? Though it doesn't seem complicated, however, I couldn't get any satisfied answers anywhere. So hopefully someone helps me get cleared.

My goal is to check criteria and pause/lock running test until the criteria is meet. Here are cases for example.

A. to pause running test and wait until page gets loaded

    ...
    let theElement = ...;
    browser.waitForAngularEnabled(false);
    browser.wait(protractor.ExpectedConditions.presenceOf(theElement));

B. to use browser.wait(), the alternative way for similar purpose with A

    browser.wait(() => {
        browser.waitForAngularEnabled(false);
        return browser.isElementPresent(by.id('the-element-id'));
    }, timeout); // timeout may not be given

So the question is:

  1. What will happen once waitForAngularEnabled(false) is invoked? (once the criteria is meet or timeout occur in my case)
  2. Should I revert waitForAngularEnabled(true) to continue normal testing?
  3. If I should do, where to put it?

Hope to get clear answers with some background principle.

Thanks!

firstor
  • 243
  • 1
  • 3
  • 8
  • 1
    Yes, I did, but I was not satisfied. Could you please answer to the question #1? Thanks in advance. – firstor Mar 07 '17 at 17:55
  • to answer question #1 we need to know why you're turning it off in the first place. Are you getting timeouts related to $http or $timeout polling on the Angular end? Also, looks like this function is just a replacement for `browser.ignoreSynchronization`, and this is used within the `waitForAngular()` function to determine whether or not to use it. So that's the difference between the two – Gunderson Mar 07 '17 at 19:19
  • Thanks for your message, Gunderson. The use of waitForAngularEnabled(false) was originated to replace browser.ignoreSynchronization. And sometimes I experienced browser delay/timeout while testing on browserstack, so I kept it. However, that's not important now. What I plan to do is to check certain criteria like as presence of a certain element and pause running test and wait until the criteria is meet. So I am curious, if I should revert by calling waitForAngularEnabled(true), and if waitForAngularEnabled invoke is still required as well. – firstor Mar 08 '17 at 07:37
  • I modified my questions, so please review it and help me. Thanks. – firstor Mar 08 '17 at 08:15
  • Thanks for the question. I have some similar concerns. I am particularly interested in the asynchronous semantics of waitForAngularEnabled. I have found that, whether using control flow or not, setting it to different values in tests in the same execution seems to yield unpredictable results; that is, the enabled state does not follow the same asynchronous semantics of other Protractor/Webdriver calls. So far, my conclusion is that you simply cannot mix waitForAngularEnabled(false) and waitForAngularEnabled(true) in the same execution, which is unfortunate. – Will May 19 '17 at 14:07

4 Answers4

25

1. What will happen once waitForAngularEnabled(false) is invoked? (once the criteria is meet or timeout occur in my case)

Empirically I have found that this seems to cause Protractor to behave as merely Webdriver. It does not wait for Angular to "settle down" (no pending HTTP requests or view updates), which is the behavior for true. Instead, if you use the false setting, you will need to use ExpectedConditions or similar approaches in order to verify preconditions to execute test steps reliably, just as you would with an ordinary Webdriver test.

2. Should I revert waitForAngularEnabled(true) to continue normal testing?

Yes. However, I have found that in Protractor 5.1.1 and 5.1.2, whether using control flow or not, scattering different waitForAngularEnabled values throughout your tests in the same execution seems to yield unpredictable results; that is, the enabled state does not follow the same asynchronous semantics of other Protractor/Webdriver calls. So far, my conclusion is that you cannot reliably mix waitForAngularEnabled(false) and waitForAngularEnabled(true) in the same execution. I suspect that this is a Protractor bug, but I have not yet developed a simple and reliable test to prove it in support of submitting a Protractor issue. There was a possibly related issue here, now closed but incompletely diagnosed.

3. If I should do, where to put it?

"Before" you make Protractor/Webdriver calls that require restoring the waiting-for-Angular semantics. However, as mentioned above, it's not clear that you can reliably guarantee that such calls will truly be made in the context of the true setting.

If you must have some tests that use false and others true, you could run them in separate executions (separate processes; don't run them with the same protractor or ng e2e command). I have encountered no problems when that approach is taken.

Will
  • 6,601
  • 3
  • 31
  • 42
  • Thanks for your answers. They are rich enough and very helpful to me and thus I can get some useful conventions to work with Protractor. Thanks again, Will. – firstor May 19 '17 at 20:02
  • Great. Hopefully as more official information comes out, or bugs are filed or fixed, we can improve upon this. – Will May 19 '17 at 21:55
  • I have encountered problems using `waitForAngularEnabled(true)` with Angular 4, similar to [this issue](https://github.com/angular/protractor/issues/4233). – Will May 31 '17 at 19:09
2

The marked answer is good - still I'd like to answer your question with added details about browser.get:

To override the default behavior of Protractor to wait for Angular calls, we can disable the Angular wait with browser.waitForAngularEnabled(false). For the rest of the driver session, Protractor will not sync the Angular calls unless Angular wait is enabled using: browser.waitForAngularEnabled(true).

But I recommend using wrapped driver directly instead of toggling the waitForAngularEnabled property which can lead to an unstable script. We had an issue with parallel test execution (which we definitely didn't want to run sequentially) - which is obvious when all tests set waitForAngularEnabled concurrently.

Protractor uses the testability APIs exposed by AngularJS functionalities like $q, $timeout, and $html to sync the page created by AngularJS asynchronous components.

browser.get When we call browser.get method in our script to navigate to a web page, Protractor uses the selenium-webdriver's get method to navigate to requested page and then by default tries to sync the page using AngularJS testability API.

Protractor’s waitForAngular strategy considers that the current page has AngularJS library and calls the getTestabilityAPI method on global object window.angular.

browser.driver.get When using Protractor with non-Angular application without overriding the default behavior, we get an error – angular is not defined because, by default, Protractor will try to synch the page using window. angular API which is not available on the page.

Alex Maker
  • 1,529
  • 2
  • 19
  • 27
1

As an addition to the answer of Will, using waitForAngularEnabled multiple times in the same test can be done, but requires a non-obvious addition of browser.get. Intuitively, most people think that setting waitForAngularEnabled(true) waits for protractor to pick up Angular tasks again but this returns a promise. Most people use it in a way where they can disable it on non-Angular pages and re-enable it on Angular pages, aka in a synchronous way. To solve this, you can use the following:

// do things on your Angular application

waitForAngularEnabled(false)

// do things on non-angular page

waitForAngularEnabled(true)
browser.get('/home') // this is a page from your Angular application

The browser.get function blocks until the Angular page is loaded.

Babyburger
  • 1,730
  • 3
  • 19
  • 32
0

As stated by Babyburger waitForAngualar needs a page reload to sync when is set to enable if you are coming from a false state, but, is not the only way to use Get.

Imaging you are working on a page with a hyperlink, the landing page won't be sync if protractor didn't asked for the API again, so as long as the page refreshes after browser.waitForAngular(enabled) by any means it should sync again. Call for a page refresh, move to a new page, use get, click send and get redirected to another page.

Now the difference: If you use browser.ignoreSyncrhonization you are disabling all protractor sync functions. So anything like an add-on that enables protractor to test with react or any other framework would be disabled too

If you use browser.waitForAngularEnabled(false) you will only stop waiting for $timeout and $http, coming from Angular API, every other sync would remain and work as expected.

If you have a test that requires you to read information changing, pictures moving, animation completing or other things requiring you to start processing what is happening from the moment the step is taking I have 2 answers for you:

1.- Do NOT run that as a E2E test, it is a behavior easier to observe, diagnose and evidence by a human

2.- Get a video recording of the step: if you really need to validate it, and the completion state is not enough to validated as a pass, get a video with a screen capture command and then get the same person responsable of looking to test results to validate that step.

For all Developers out there, there is a function called $interval is te expected Angular function for a wait that doesn't end, restarts or has a funny functionality that is not the Timeout expectation, which is, if it doesn't happen in a short time, send a flag and stop Interval is for wait until happening, and protractor ignores this one so it won't mess with test execution.

Here is a developer explaining this Interval vs Timeout

Please QA teams of the world, do NOT allow a lazy developer to give lazy code as an answer.

I had a team which didn't include interval, just used endless timeouts, and it caused a lot of errors in our automation execution, it also lead to excess resources allocated in the machine running the script due to all the timeouts running at the same time in the same window. That same team has now a new assignment, but I had pushed for them to not misuse those 2 wrappers, the coding has gone smoother and creating test for each new function is a breeze thanks to having protractor work for us and not the other way around.

Nerdko
  • 1
  • 1