Protractor how to run login test script first - angularjs

I am trying to test an Angular Single Page application with protractor. I need to run the login script first. Only then I can move to other routes since there is a check for token in localStorage on route change.
Is this testing approach correct?. In that case I need to run the login script first. Does protractor allows to control the spec file order.
Or should I run the each script independently by hardcoding the token in localStorage (Should I do login api call independently before each test).
My login script contains the following
it('Login with wrong email', function() {
})
it('Login with correct email', function() {
})
So after running the Login with correct mail I will get the accessToken which will get stored in localStorage and I can continue testing other routes. Is this the correct approach. If not how do I test a single application with login from end to end.
In protractor Style Guide it is mentioned as
Make your tests independent from each other
So should I use beforeAll, beforeEach to get the access token and store in localStorage before each test. In that case please explain me how to do it.
Any help is greatly appreciated.
Thanks.

As highlighted in the Protractor FAQs, you can specify your login code in the onPrepare section of your conf file. Here is an example.
You can also achieve this in beforeAll but that adds unnecessary overhead to your test scripts. Altering the localStorage is possible, but not in the spirit of e2e testing since a lot can go wrong wrt LS, and you will end up wondering if it is your app or your LS modification code that caused this.

Related

Unit testing - ignoring module run block

Is there a way to prevent an application run block from executing during unit tests?
My situation is that I have added some session checking logic to the run block, which redirects to a login page should session checks fail.
Now that I have added this run block in, all my other tests fail since they expect the login page to have been requested as I'm not ensuring the session check returns true before each test.
So is there a way to skip the run block for a unit test, or would it be something like mocking out the module in my tests so it doesn't have the run block included?
I'm probably thinking about this the wrong way, so please enlighten me!
Thanks
No, run block is part of angular app lifecycle.
I would suggest not to have this logic in .run, but transfer all authentication logic into some service. After that its easy to mock it.
If you can be more specific about app architecture, I can suggest more improvements.

How to test angular views accessible after a login?

I am using protractor to test my angular app, where most of the views are accessible for authenticated users only.
Currently, I placed the login action in beforeEach:
beforeEach(function() {
browser.get(site + '/account/login');
element(by.id('Username')).sendKeys('testuser');
element(by.id('Password')).sendKeys('letmein');
element(by.css('[value="Log In"]')).click();
});
The problem is for every it('should....') test, the webdriver visits the login page and perform the same log in ritual over and over again.
I guess there must be a better way to do it. How can we set up correctly so that the webdriver login only once and then perform all the it('should....') tests?
This can be done via the onPrepare field of the protractor configuration file.
An example configuration file with login is provided in Protractor itself.
onPrepare: function() {
browser.driver.get(env.baseUrl + '/login.html');
browser.driver.findElement(by.id('username')).sendKeys('Jane');
browser.driver.findElement(by.id('password')).sendKeys('1234');
...
}
Alternatively, you can make use of the fact that Jasmine tests are ordered. Thus, instead of logging in before every test, you can have your first it login.
I typically organize my Jasmine tests into larger suites, with the first it signing in, and the last it signing off.
The obvious disadvantage is that your tests are not entirely independent, but in return test execution is substantially faster. You can even argue that doing multiple things after logging in is more realistic than logging on and off for every action.
Yet another solution is to use the Jasmine 2.x beforeAll and afterAll notations of (see this answer). This does require that you use the newest version of Protractor, as pre 1.5 versions of Protractor only worked with Jasmine 1.x.

Angular Protractor test session persistence

I'm working on e2e tests for a web app and I would like to log in a user and persist their session.
Specifically the following scenario:
The log in form is posted with valid credentials.
Angular routes the user to a landing page.
I call browser.get( /* the current url */ )
I expect the current URL to be the same, instead of my user getting kicked back to the log in screen.
We're using HTTP header based auth and I don't know how to configure this scenario for testing purposes.
Is it as simple as activating cookies somewhere? Or maybe supporting the auth headers via a config?
I managed to solve this be simply adding browser.sleep(1000) in before calling browser.get( /* the current url */ ).
Basically Protractor was hammering on the router to fast and my app was kicking me out before auth creds were set. Or, perhaps, might be the HTML5 routing takes a little time to process (our deep links are hashed, but then angular converts the hash to HTML5 routes).
You can use browser.waitForAngular(); too.
You can use promises like this
goAfterLogin: function(){
browser.get('http://www.example.com').then(function(){
return this; //or other return
}).then(function(){
return this;
});
}
Its up to you how will you use it (you as well can create promis with waitForAngular() )

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.

What is a good way to test change of location in AngularJS E2E test

I have a login form and now i would like to make an integration test to see if user is redirected to the other page after successful login.
Behind the curtains there is authorization service that fires a page reload via $window.location.href = 'home';
First i had this:
it('should redirect to /home if credentials are correct', function(){
browser().navigateTo('/login');
input('credentials.username').enter('testuser');
input('credentials.password').enter('testpass');
element('button.login').click();
expect(browser().location().path()).toBe("/home");
});
but AngularJS test failed both - run as Karma and as runner in browser. Then i thought that maybe expect is too soon and i added sleep(1) before it. And then it was fine and in test runner I could see the page refresh before assertion.
I assume it might work better if i had location().path('/home') but i prefer full reload at this step.
Is there any design/test pattern that should be used in such cases so i don't have to put sleep() before expected location change?
You can try this code;
it('should redirect to /home if credentials are correct', function(){
browser().navigateTo('/login');
input('credentials.username').enter('testuser');
input('credentials.password').enter('testpass');
element('button.login').click();
browser().navigateTo('/home');
});

Resources