Protractor tests stopped working after upgrade to Angular 2 - angularjs

I have a manually bootstrapped Angular application with a large number of Protractor tests written. Around June 2016, the tests worked, but no longer do. Since then, the following changes have occurred:
Angular 2 has been released
The login portion of the application has been rewritten. Originally, the login page did not use Angular at all. Now it uses Angular 2. The rest of the app is still Angular 1.
If I do not interact with the app beyond logging in, and run a single test (such as "expect(true).toBe(true)"), then everything runs to completion, with no error messages generated.
If my test automation does interact with the app, then the following occurs:
If my conf.js file contains "useAllAngular2AppRoots: true", I get the error message: "Timed out waiting for Protractor to synchronize with the page after 11 seconds. Please see https://github.com/angular/protractor/blob/master/docs/faq.md"
If my conf.js file does not contain "useAllAngular2AppRoots: true", I get the error message: "Error while waiting for Protractor to sync with the page: "Could not find testability for element."
In either case, the automation proceeds through login and into the Angular1 portion of the application.
The questions I have are:
Is this kind of application (Angular2 login page, everything else Angular1) possible to test with Protractor?
Should "useAllAngular2AppRoots: true" be used?
The error messages I am getting don't seem to point to a particular area of my test code to fix. How can I go about determining what the problem is?
EDIT 27 Oct 2016
After the first answer this question received, I attempted to pin down exactly what was failing, and where.
I found that:
setting rootElement in my conf.js file had no effect. Whether I left it out entirely, specifically set it to 'body', or set it to a random nonsense string, I got the same behavior.
following the given suggestions, I was still getting an error message 'AfterAll Failed: Error while waiting for Protractor to sync with the page: "Could not find testability for element."' Note that I was not trying to make any tests in my AfterAll function, just clicking a Logout button
if I set 'browser.ignoreSynchronization=true' in the beforeAll function of my test, I could make calls that interacted with the app, such as clicking on screen elements. Without this line, no such call had any effect. However, I'm sure that this is not something I should do, or that I should need to.
even with 'browser.ignoreSynchronization=true', I would still get error messages when I tried to make Angular1-specific calls, such as trying to match an element with by.repeater(). This would occur in the part of the app which is still written in Angular 1, and is therefore using ng-repeat rather than ngFor.
Does this additional information give any further insight on what might be going on, and what else I might try?

First of all, you need to make sure you are using the latest protractor (4.0.9) and zone.js >= 0.6.25.
Then, make sure you set browser.ng12Hybrid to true for each page that contains a hybrid angular 1 + 2 app, i.e.:
beforeEach(function () {
browser.ng12Hybrid = true;
browser.get('/somepage.html');
});
afterEach(function () {
browser.ng12Hybrid = false;
});
You can also find example in protractor's own test specs.
As for useAllAngular2AppRoots: true, it should only be used once your app is completely migrated to Angular 2 and you have removed the upgrade adapter, as explained here.
Good luck with your project!

Related

In Protractor test scripts, will we be able to locate elements using by . binding when browser.ignoreSynchronization=true

I'm asking this question coz, the app that I'm testing flows from a non-angular app. I'm my case the whole page is non-angular and it contains a link. On clicking on it opens the new angular view. The problem that I'm facing is that the app is manually bootstrapped. I even added the ng-app under a div and mentioned that as rootElement in the script. However this is throwing an error saying "unable to synchronize with the page. No injector found. The reason maybe that it's not under ng-app. Later when I turn off the synchronization I can't locate elements using their binding values.
I've tried most of the workarounds on net and none of them seems to fix this. Could any of please help
Manually bootstrapped apps are a pain. When you turn off browser synchronization you are telling Protractor that Angular is not and will not ever be present. Because by.binding is Angular-only, and there is no Angular present to bind to, that particular locator isn't going to return an element. I use Protractor for non-Angular apps quite often and it works just fine as long as you don't try to use locators that are Angular-specific. Your options are:
Test all of the non-Angular stuff manually, then the Angular stuff separately
Test everything without the Angular locators

What is the Protractor way to test what is shown before Angular loads

I believe that it's a good practice to inform users that an Angular-based application is loading. I mean, in case of Angular 2, it's e.g. <view>Loading...</view>. I am sure that there is a way to do the same in AngularJS (v1) as well. Thus I believe that there should be a way to use Protractor to test such aspect of the application since it is "an end-to-end test framework for AngularJS applications".
It was suggested to me that there is a way to do that and that I should ask here. So, can you please help me to find the approach which had Nick on his mind? It does no necessarily has to be compatible with Angular 2 already. AngularJS (v1) approach would be enough since I believe that it will be ported once they port Protractor.
This question seems to be similar to Protractor: test loading state but unlike OP I want to make sure that the Angular application is not loaded before the test finishes so I guess that there should be a way to suspend/stop loading of the application (but I may be wrong).
I typically avoid testing things like this because they tend to be very flakey. Unless there's some requirement to test the loader I would not do so.
You can use browser.ignoreSynchronization = true to not wait for angular to load on the page, and then assert that your loader is there.
The only issue with this is that you will struggle with ensuring that angular has not loaded. There's no great way of preventing your angular application from bootstrapping unless you manually bootstrap and build in some sort of delay or "no-bootstrap" trigger but that starts compromising your application just to test a loading state.
Just to add to #Nick's point, you would definitely need to turn the synchronization between protractor and angular off and set browser.ignoreSynchronization = true;.
Then, you can/should add an explicit wait to wait for the loading indicator (for instance, it may be a spinner image) to become visible:
var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(element(by.id("#loading"))), 5000, "Loading indicator has not become visible");
A timeout error would mean that the loading element (in this case the element with id="loading") has not become visible in 5 seconds.
Don't forget to turn the sync back on after the test is completed:
browser.ignoreSynchronization = false;

Timed out waiting for Protractor to synchronize with the page after 50001ms

I am testing AngularJS app and very new to protractor. Every time I open the browser, it gets opened and then waits for the timeout before throwing the following error on cmd.
Timed out waiting for Protractor to synchronize with the page after 50001ms
I have tried increasing the timeout limit, but always get this error.
I have also tried using all of these:
browser.ignoreSynchronization = true;
browser.driver.sleep(5000);
browser.debugger();
browser.waitForAngular();
The page loads properly and if I use Eclipse and Selenium to interact with button objects, it just works fine.
Only protractor is having Sync issues. Please Help.
Possible reasons why Protractor would time out:
Your web page doesn't implement Angular in an expected way (i.e. with an ng-app on the body tag). More often, the error you will get in this case is Angular not found on page, but a timeout isn't out of the question. Using ignoreSynchronization would fix this if it were the issue, so this one isn't you.
An HTTP request is pending or fails. Open up your dev console and check the "Network" tab when the page loads with Protractor (it may happen with Protractor and not in a manual test). If you find something failing, make sure you are issuing the request correctly. For example, if you're trying to access an HTTP endpoint through HTTPS, it's definitely possible that the request would fail and Protractor would time out.
Your page is polling $timeout or $http repeatedly. Protractor won't do anything until Angular has reached a "resting" state (all elements and data bindings are loaded and all requests have returned).
The official list of timeout reasons is here: https://github.com/angular/protractor/blob/master/docs/timeouts.md.
But if you check the Javascript console and Network requests as the page loads, you should be able to figure out what's wrong. Good luck!

Strange, isolated errors "$compile:tpload"

We're having strange, sporadic JavaScript error messages in our production log files (JavaScript errors are logged in the backend):
Uncaught Error: [$compile:tpload] http://errors.angularjs.org/1.2.16/$compile/tpload?p0=modules%2Fsome%2valid-directive-path.tpl.html
The error occurs only with directives. I'm not able to reproduce the errors locally. The templateUrl for the directives are all valid.
The only possible scenario that came to my mind was if the user presses the cancel/stop button in the browser while the page is loading (then i'm able to reproduce the error).
Does anyone have another idea or explanation? Or even a solution :-)
Cheers
Michael
We resolved the issue like this:
Since we are caching our HTML templates with $templateCache using the grunt ngTemplate plugin (https://www.npmjs.com/package/grunt-angular-templates) we do not have the above issues anymore.
Out of interest I was able to recreate this issue. By adding logging to angular I established that when the template load fails it does so with a status of 0 which made me think that the request was actually cancelled. This theory was backed up by the fact that we see no server side errors.
If I emulate a device that cannot support html5 routing and then add an arbitrary query string to the end of the route, it causes an infinite digest loop and in the end the whole page reloads a few times. This in turn was causing the outstanding template requests to be cancelled leading to exactly the errors I was seeing in the logs.
So, for me at least, this is really nothing to do with the loading of the templates, it's just an angular bug (which hopefully is going to be fixed in angular 1.3.8)

AngularJS e2e tests hang when changing between two separate angular apps

I have a frustrating problem: I want to write end to end tests for a complex angular app. The problem is that the login screen is a separate app. The initial idea was that it would branch out to separate other angular apps in our ecosystem based on the login credentials. It works like a charm. For the tests it is a nightmare though.
The tests work as expected but as soon as correct credentials are entered and the main angular app is loaded the tests just time out. No error message or debug output whatsoever, its just waiting. I can see the page is loading correctly.
Now I thought I would skip this part and test right on the target app but thats not working either since I need to initialize the server with the right credentials first (= go through the login screen).
I tried this with the karma scenario runner and protractor, both show the exact same behavior. Can I tell them to reinitialize after the target page is loaded?
So when protractor times out, the error message shows a link to the faq. Right on top there's the explanation for this problem. Apparently the app sends continuous requests (maybe because I am using socket.io), so Angular is never finished.
This problem has nothing to do with the separate apps.
The issue link was very helpful. Since I am not willing to touch any of the pages code I settled with
browser.ignoreSynchronization = true;
and
browser.sleep( ... );
The tests now work as expected.

Resources