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.
Related
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!
I'm running an Angular app and I'm trying to get the current URL when testing on protractor. Which one to use?
browser.driver.getCurrentUrl() or browser.getCurrentUrl() ?
If this is an Angular application under test - use browser, otherwise - browser.driver.
To quote #jmr from a relevant github issue:
If you need to interact with a non-Angular page, you may access the wrapped webdriver instance directly with browser.driver.
Though, note that both are gonna work if this is Angular application under test. Some people even said that found browser.driver more reliable if it the sync time is longer than usual:
Just to add to this - I find that browser.driver works better on AngularJS apps that take time to sync. I have tried both and for some reason browser.driver is more reliable.
Though, I've personally used browser.getCurrentUrl() and cannot recall any problems.
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
Say I have a time sensitive app, such as a football game betting app, and I can not best after the game has started. Now I want some angularjs, protractorjs e2e tests for the app that run on something like Jenkins. The issue is I don't know when the app is run as that is based on people updated the repo'. So how can I fake or set the time, or an I looking at this wrong?
I had looked all online but can't see a say of getting protractorjs to set the time of day for the tests.
I am not sure if protractor can change the time on your computer or anything, but there are still some ways to work with it.
You should probably be looking into a mock mode version of your website that your protractor tests can hit. Using ngMockE2E (https://docs.angularjs.org/api/ngMockE2E) and other mock tools, you can, for example, mock the service that gets the time for your website. You should have an angular service that checks for the time of day and then feeds that data through to your site to enable or disable betting. You can mock the service and feed it different sets of time, maybe attach those to different routes on your mock mode, and have your protractor tests hit that.
Let me know if this sounds like what you need, and we can get more into it.
I was watching a youtube video and in that there was an example:
loginPage.userName.sendKeys ...
loginPage.password.sendKeys ...
loginPage.loginButton.click();
browser.waitForAngular();
expect( ...
I thought Protractor was coded in such a way that it would do the wait without the need for a browser.waitForAngular().
Can someone confirm if I need the waitForAngular() in this example?
I think that whether you need browser.waitForAngular() depends on the application you're testing.
Not 100% sure on what the conditions are, but I have found that I required this method when my test is performing a task that requires a response from a server, such as changing a user's password in a web app.
On another note, in my experience, browser.waitForAngular() is not robust enough to handle every type of wait condition I've needed to perform.
For example, I'm writing tests for a web application where the user logs in through a non-Angular page and is directed to an Angular page. If I want to make assertions to test the elements present on the login landing page, I can't use browser.waitForAngular() because non-angular pages do not have access to this method. I've found that a more reliable way to tell the driver "wait for the page to fully load, then check the text present on the page" is to use browser.wait to explicitly wait for the presence or visibility of an element on the next page that you know will take the longest to load.