I have to test a browser page that requires a login. Is there a way to keep the browser open between every it block so I don't need to login for every it block?
Thanks
Is there a way to keep the browser open between every it block so I don't need to login for every it block?
Yes: Provide the browser session, before starting protractor - it is called attach in Protractor lingo
Protractor will not close the browser session if you have started the browser session before starting Protractor.
I have created an NPM Package to start the browser easily. Let me know if this helps you.
https://github.com/andreasmarkussen/webdriver-reuse-session
Protractor closing browsers between different tests files is by design. However, there are a few ways to solve your problem.
1) Write all your tests in one file
Self explanatory, this will accomplish what you are trying to do, but only works as long as you aren't running tests in parallel. This will work for you, but I would recommend using the 2nd option. You are able to have multiple describes in the same test file which will help it be more readable if you go this route. Example test.js file:
describe('Testing login',function(){
it('Should login',function(){
//test here
});
});
describe('Testing foo',function(){
it('Should test foo here',function(){
//test here
});
it('Should test foo here as well',function(){
//test here
});
});
describe('Testing bar',function(){
it('Should test bar here',function(){
//test here
});
it('Should test bar here as well',function(){
//test here
});
});
2) Use a login function
This is what I personally use. I have a function that I call at the start of every test that logs in. The function accepts a Username and Password. While this doesn't keep the browser open, I personally think this is best way to go at this problem. Example:
Test1.js:
const helper = require util.js;
const util = new helper;
describe('Testing foo',function(){
beforeAll(function(){
util.login();
};
it('Should test foo here',function(){
//test here
});
it('Should test foo here as well',function(){
//test here
});
});
test2.js
const helper = require util.js;
const util = new helper;
describe('Testing bar',function(){
beforeAll(function(){
util.login();
};
it('Should test bar here',function(){
//test here
});
it('Should test bar here as well',function(){
//test here
});
});
util.js:
const helper = function(){
this.login = function(){
//do login here
}
}
Here is a useful stack post about reusing code, it goes more into depth about some syntax.
Related
I want my Protractor test to open https://www.jetblue.com/ and click on Round Trip. Below is the piece of code I have written for the same :
describe('This test suite will validate booking related features', function(){
beforeAll(function(){
browser.driver.manage().window().maximize();
browser.ignoreSynchronization=true;
browser.waitForAngularEnabled(false);
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
})
beforeEach(function(){
browser.get('https://www.jetblue.com/');
browser.getTitle().then(function(text){
console.log("Title of the page is : " +text);
});
});
it('Customer can search for Flights for One Way Trip', function(){
var AllElements = element.all(by.xpath("//label[text()=' One-way ']/parent::jb-radio"));
AllElements.each(function(ele){
ele.click();
browser.sleep(10000);
});
});
});
The test is successfully passing without selecting the radio button. I used the same locators using Selenium-Java and test is actually performing the operation and passing. Makes me think which is actually better as Selenium-Java is equally effective on Angular applications as well.
The 'Roundtrip' radio button appears to be this element
<div _ngcontent-c47="" class="marker ba b--transparent bg-core-blue t-vfast"></div>
So I would try to use this locator:
element(by.css('.marker.ba.b--transparent.bg-core-blue.t-vfast'));
I am using protractor-cucumber frame work(protractor 5.2.2 and cucumber 3.2.0).I need to login with multiple user credentials.So i need to use incognito window.So i have setup in my config file as given below.
capabilities: {
'browserName': 'chrome',
chromeOptions: {
args: ["--incognito"]
}
},
and i have added
browser.restart();
after each logout code.But when i am open new incognito windows,i am not able to access the code inside of onPrepare function.my onPrepare function is given below.
onPrepare: function() {
browser.ignoreSynchronization = true;
browser.manage().window().maximize();
global.testdata = require('./support/testdata.js');
}
so how can i access the code inside of onPrepare function while opening the browser each time.Thanks in advance.
you can wrap the code within onPrepare() into a function and export the function in a .js file.
// onPrepare.js, move the codes in `onPrepare()` at here
module.exports = function onPrepareConfig() {
browser.ignoreSynchronization = true;
browser.manage().window().maximize();
global.testdata = require('./support/testdata.js');
}
// protractor conf.js
onPrepare: function() {
// you need to import `onPrepare.js` within this function
// because the variable `browser` we used in `onPrepare.js`
// are available inside `onPrepare()`
var onPrepareConfig = require('./onPrepare.js');
onPrepareConfig();
}
// the code line where you call browser.restart();
browser.restart();
var onPrepareConfig = require('./onPrepare.js');
onPrepareConfig();
Node.js based on javascript language that is a single thread. So, each test which opens a browser runs in separate process and that's why you don't need incognito mode. The issue is how to share between multiple tests different users. The simplest way is:
create a file in a root of project with different users credentials and in the test beforeAll() get credentials and remove this line from file. At the end of test returns it back.
OR
you create a server with simple API for getting different credentials and use it in the test.
As you can see it is a little bit complicated.
I apologize for the slightly vague title, I'm not sure how exactly to word this.
I have my Page Object which, with one exception, works perfectly. Here's the excerpt:
module.exports = function(){
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = element(by.name('facility')).all(by.tagName('option')).count().then(function(numberOfItems) {
var rnum = parseInt(Math.random() * numberOfItems);
return rnum;
}).then(function(randomNumber) {
element(by.name('facility')).all(by.tagName('option')).get(randomNumber)
});
}
I can access and use facilityList just fine. But then I realized that I'm almost always doing the same thing to facilityList so why don't I just create another line to make it choose a random one. So I create randomFacility using the code from the main conf.js.
It didn't work. The error I see displayed is:
Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"
I'm confused. Is this saying I can't do all that processing in the page object to get the random one or do I simply have to manipulate facilityList in the conf.js and be done with it?
You nee to know the mechanism about how protractor to find element. Protractor only to start find element from page when protractor's action API be called, like getText(), click(), count() etc.
So when you define variable to represent certain element on page, when Nodejs execute this line, protractor won't to start find element from page:
// page object login.page.js
module.exports = function LoginPage(){
this.sumbitButton = element(by.css('#submit'));
this.countName = element.all(by.css('.username')).count();
}
// use page object in conf.js
var LoginPage = require('./login.page.js');
var loginPage = new Loginpage();
When Nodejs execute line var loginPage = new Loginpage();, all lines in function LoginPage will be executed.
When execute the first line, protractor not to find element from current open page,
When execute the second line, protractor will find element from current open page, But at this time point, protractor is possible to launching browser with a blank page, the target page have not been opened or navigated to.
To fix your problem, you need to define randomFacility as class's Method, rather than Property:
module.exports = function() {
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = function() {
return element(by.name('facility'))
.all(by.tagName('option')).count()
.then(function(numberOfItems) {
console.log('count: '+numberOfItems);
var rnum = parseInt(Math.random() * numberOfItems);
console.log('random index: '+rnum);
return rnum;
})
.then(function(randomNumber) {
console.log('argument randomNumber: '+randomNumber);
return element(by.name('facility'))
.all(by.tagName('option')).get(randomNumber)
});
}
};
// how to use
pageObject.randomFacility().then(function(ele){
return ele.click();
});
I have started doing a POC on Protractor as our e2e automation testing tool.
Our application is designed in angular which makes it a perfect fit.
However, I need to login via google which is a non-angular website and therefore at the start of my test I state
browser.ignoreSynchronization = true;
Then I go to
'https://accounts.google.com/ServiceLogin'
Enter my google credentials and click on signin
At this point I try to go to my application's URL, which is an angular application so I was hoping to turn
browser.ignoreSynchronization = false;
All the the above steps are part of a beforeEach so that I can login before each test
But when I turn ignoreSynchronization to false, all my tests start failing.
On the other hand, if I don't turn it to false, I am compelled to use a lot of browser.sleeps as Protractor is still treating it as a non-angular app and does not wait for angular to load fully
I have also tried to put the ignoreSynchronization = false in each individual test as opposed to beforeEach but even then all my tests start failing.
Below is my beforeEach code
browser.ignoreSynchronization = true;
browser.driver.manage().window().setSize(1280, 1024);
browser.get(googlelogin);
email.sendKeys('username');
next.click();
browser.wait(EC.visibilityOf(pwd), 5000);
pwd.sendKeys('pwd');
signin.click();
browser.ignoreSynchronization = false;
browser.driver.get(tdurl);
Few things to fix:
wait for the "click" to go through
use browser.get() on the Angular Page
Here are the modifications:
signin.click().then(function () {
browser.ignoreSynchronization = false;
browser.get(tdurl);
browser.waitForAngular(); // might not be necessary
});
You may also add a wait with an Expected Condition to wait for the login step to be completed - say, wait for a specific URL, or page title, or an element on the page.
Reconciliation_verifyExapanedDatainExpanedRow: function (HeaderName, texttobepresent) {
browser.waitForAngular().then(function () {
var EC = protractor.ExpectedConditions;
var columnHeaderActive = GUtils.$locatorXpath('//p-datatable//span[contains(text(),"' + HeaderName + '")]/..//span[#class="ui-cell-data"][contains(.,\'' + texttobepresent + '\')]');
browser.wait(EC.presenceOf(GUtils.$element(columnHeaderActive)), GUtils.shortDynamicWait()).then(function () {
console.log('PASS');
}, function (err) {
console.log('FAIL');
});
});
},
I am new to Protractor (and Javascript by the way), and I am writing some tests to practice. My goal so far is to check that when I click on the home button of a website, the redirection leads me correctly to the expected address.
I have written this:
var HomeTopBanner = function() {
this.homeUrl = browser.params.homePageObject.homeUrl;
this.topBanner = element(by.css('.navbar-inner'));
this.homeButton = this.topBanner.element(by.css('.icon-home'));
}
describe('Home button', function(){
var homeTopBanner = new HomeTopBanner();
var newUrl = '';
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function storeNewUrl(url) {
newUrl = url;
});
})
it('checks that the home button leads to the homepage', function(){
expect(newUrl).toEqual(homeTopBanner.homeUrl);
})
});
This works, but my question is:
Why do I need to separate the "GetCurrentUrl" and the "expect(newUrl)" parts? I would prefer to have both of them in the same spec, but if I do that, during the comparison of the expect, newUrl=''
I assume this is related to browser.getCurrentUrl() being a promise, but is there a better way to do it?
Yes, getCurrentUrl returns a promise with the url in the form of a string as explained in the protractor api docs. You have to wait until the url is returned in order to use it. Now in order to combine both the specs you can write your expect statement inside the function that getCurrentUrl returns as shown below and there is no need of using a newUrl variable too if you want -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click();
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
})
There could also be another issue when after the click action the previous url is being captured due to the fact that protractor is async and fast. In that case you can write your getCurrentUrl() function inside the promise that click() function returns. Here's an example of it -
it('clicks on the Home button', function(){
homeTopBanner.homeButton.click().then(function(){
browser.getCurrentUrl().then(function(url) {
expect(url).toEqual(homeTopBanner.homeUrl);
});
});
})
Hope this helps.