angular / protractor

E2E test framework for Angular apps
http://www.protractortest.org
MIT License
8.75k stars 2.31k forks source link

Angular2 application requires browser.ignoreSynchronization #3611

Closed abierbaum closed 8 years ago

abierbaum commented 8 years ago

I am trying to get up to speed on how to use protractor with Angular2. Most things seem to work well but there are a few that are causing me problems.

One of those is that some tests seem to hang unless I disable synchronization by using:

browser.ignoreSynchronization = true;

Is this a known issue with Angular2 or am I just running into a corner case I should try to reproduce further?

As a feature request, I think it would be very helpful to have an example Angular 2 application that shows how to setup and use protractor to test an ng2 application with routes and other common capabilities.

heathkit commented 8 years ago

For angular2 apps, one thing you need to do is make sure you have useAllAngular2AppRoots: true, in your config. If you have that set and tests still hang, please let us know.

I agree, a basic (though reasonably complex, with routes, etc.) angular 2 example would be a great addition to the cookbook.

cnishina commented 8 years ago

Since this is a cookbook addition, I created an issue here: https://github.com/angular/protractor-cookbook/issues/15. @mgiambalvo should we close this issue against Protractor?

ghost commented 8 years ago

Do you use angular2-moment by chance or another library which uses timeouts?

abierbaum commented 8 years ago

I was using the useAllAngular2AppRoots: true and still had to set browser.ignoreSynchronization = true;.

I found that as a workaround in https://github.com/AngularClass/angular2-webpack-starter/blob/master/config/protractor.conf.js

So now I can write tests, but I do have to put in browser.wait calls to wait for elements to show up on screen since I can't wait for angular2 to complete.

heathkit commented 8 years ago

Thanks for following up. You shouldn't need to be ignoring synchronization when testing Angular 2. Could you give us some more information on your application? A minimal example that reproduces the problem would be really helpful.

If you let Protractor time out, does it list any tasks that are pending?

heathkit commented 8 years ago

Also, please take a look at #3349. Protractor will wait until there are no more pending tasks in the Angular zone. If you have an async task that you don't want to block your tests, you'll need to run it outside of the angular zone using ngZone.runOutsideAngular. See Julie's talk at https://www.youtube.com/watch?v=DltUEDy7ItY and the related example at https://github.com/juliemr/ngconf-2016-zones/blob/master/src/app/main.ts#L38

abierbaum commented 8 years ago

@mgiambalvo

Here is the stack that I get with a timeout. I don't see anything obvious that points to what is holding it up. What is happening is that protractor fills in the login details, gets back an http response allowing the app in, the router then changes to another route and that default page loads. The page is showing content that is refreshed every 20 seconds based upon an rx.Obserservable.timer() call. The http call the timer is hitting returns in a couple milliseconds. I can see the page in the browser and it is fully rendered.

If I run a similar test that logs in and redirects to a different route in the application, things seem to work as expected. So for whatever reason something I am doing on this page must be causing the system to think Angular 2 is not stabilizing.

1) Admin App Login/Logout should login to default page
  Message:
    Failed: Timed out waiting for Protractor to synchronize with the page after 110 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md
    While waiting for element with locator - Locator: By(css selector, tc-health-page)
  Stack:
    ScriptTimeoutError: asynchronous script timeout: result was not received in 110 seconds
      (Session info: chrome=53.0.2785.116)
      (Driver info: chromedriver=2.22.397932 (282ed7cf89cf0053b6542e0d0f039d4123bbb6ad),platform=Linux 3.13.0-87-generic x86_64)
        at WebDriverError (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/error.js:26:26)
        at ScriptTimeoutError (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/error.js:291:26)
        at Object.checkLegacyResponse (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/error.js:639:15)
        at parseHttpResponse (/home/abierbaum/my_app/node_modules/selenium-webdriver/http/index.js:538:13)
        at /home/abierbaum/my_app/node_modules/selenium-webdriver/http/index.js:472:11
        at ManagedPromise.invokeCallback_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:1379:14)
        at TaskQueue.execute_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2913:14)
        at TaskQueue.executeNext_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2896:21)
        at /home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2820:25
        at /home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:639:7
    From: Task: Protractor.waitForAngular() - Locator: By(css selector, tc-health-page)
        at Driver.schedule (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/webdriver.js:377:17)
        at ProtractorBrowser.executeAsyncScript_ (/home/abierbaum/my_app/node_modules/protractor/built/browser.js:236:28)
        at runWaitForAngularScript (/home/abierbaum/my_app/node_modules/protractor/built/browser.js:267:30)
        at ProtractorBrowser.waitForAngular (/home/abierbaum/my_app/node_modules/protractor/built/browser.js:270:16)
        at ElementArrayFinder.getWebElements (/home/abierbaum/my_app/node_modules/protractor/built/element.js:155:29)
        at ElementFinder.isPresent (/home/abierbaum/my_app/node_modules/protractor/built/element.js:919:46)
        at Object.<anonymous> (../../src/app.admin/admin.app.e2e.ts:76:39)
        at /home/abierbaum/my_app/node_modules/jasminewd2/index.js:94:23
        at new ManagedPromise (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:1082:7)
        at controlFlowExecute (/home/abierbaum/my_app/node_modules/jasminewd2/index.js:80:18)
    From: Task: Run fit("should login to default page") in control flow
        at Object.<anonymous> (/home/abierbaum/my_app/node_modules/jasminewd2/index.js:79:14)
        at /home/abierbaum/my_app/node_modules/jasminewd2/index.js:16:5
        at ManagedPromise.invokeCallback_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:1379:14)
        at TaskQueue.execute_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2913:14)
        at TaskQueue.executeNext_ (/home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2896:21)
        at /home/abierbaum/my_app/node_modules/selenium-webdriver/lib/promise.js:2775:27
    From asynchronous test: 
    Error
        at Suite.<anonymous> (../../src/app.admin/admin.app.e2e.ts:71:7)
        at Suite.<anonymous> (../../src/app.admin/admin.app.e2e.ts:49:4)
        at Object.<anonymous> (../../src/app.admin/admin.app.e2e.ts:38:1)
heathkit commented 8 years ago

This sounds like the expected behavior. Please see the discussion in #3349 - you'll need to wrap your polling Observable in a runOutsideAngular() call.

maazzali commented 8 years ago

@mgiambalvo I am facing the same issue with browser.ignoreSynchronization = true; and useAllAngular2AppRoots: true for my Angular2 App. I have to add waits myself so that the page is loaded completely. If I make browser.ignoreSynchronization = false; and useAllAngular2AppRoots: true. The tests hang and exception is being thrown on server side. I have pasted a screenshot below.

screen shot 2016-10-20 at 5 07 30 pm

laurelnaiad commented 7 years ago

I've been using the runOutsideAngular techinque. It seems to work, but not always. When I have two different long-polling processes going at the same time, I seem to run into a case where protractor and angular kind of "bomb" ... that is, I get back a return value of "true" from the .whenStable(..) call. This happens in the course of protractor and jasmine unwinding my promises, and it instantly kills the test.

This line kicks in: https://github.com/angular/protractor/blob/master/lib/browser.ts#L470

    return runWaitForAngularScript()
        .then((browserErr: Function) => {
          if (browserErr) {
            throw new Error(
                'Error while waiting for Protractor to ' +
                'sync with the page: ' + JSON.stringify(browserErr));
          }
        })

with a browserErr === true.

It doesn't time out, it instantly fails. I think this is because there are multiple background processes sneaking in from outside angular to run in angular?

If I'm correct, then I hope that's a bug in angular or protractor (and that this case should have been handled for me by zone.js and all the other framework goodness), because if not, it would seem like I might have to reign in and control all of the outside angular code under one umbrella observable?

Here's hoping I'm wrong and it's a bug. :) If I can scrounge some time, I will try to write a reproducible example of this problem using a couple of background ops re-entering the zone at different schedules.

heathkit commented 7 years ago

@laurelnaiad A reproducible example would be most apprieciated! Also, it'd be helpful if you could open a new issue for this case with logs and any other details you think might help. Thanks!