Jasmine - Restart browser between tests (it blocks) - selenium-webdriver

In our Protractor+Jasmine framework trying to restart browser between tests for different login user. As we have non-angular login page and after login its navigate to angular page. Following is my main test spec file
describe('User Permissions', function() {
var docsLoginPage = require('../pages/CLM_Page.js');
var projectsPage = require('../pages/Projects_Page.js');
var contentPage = require('../pages/Content_Page.js');
beforeEach(function() {
browser.ignoreSynchronization = true;
browser.get('http://be-docs-dev.xyz.local/');
});
it('Verify permissions for Non Admin and Read only permission group user', function() {
docsLoginPage.loginToDocs("sipqa4#xyz.com","Yahoo#123");
expect(browser.getTitle()).toEqual('abc');
browser.ignoreSynchronization = false;
expect(projectsPage.checkElementExistsById('headers_nav_projects')).toBe(false);
expect(contentPage.checkElementExistsById("content_browse_options_folder_settings")).toBe(false);
expect(contentPage.checkElementExistsById('content_browse_options_new_menu')).toBe(false);
});
it('Verify permissions for Project collaborator Non Admin and Read only permission group user', function() {
/*browser.restart().then(function(){
console.log("-----------Restarted the browser---------------");
});*/
docsLoginPage.loginToDocs("sipqa2#xyz.com","Yahoo#123");
expect(browser.getTitle()).toEqual('abc');
browser.ignoreSynchronization = false;
expect(projectsPage.checkElementExistsById('headers_nav_content')).toBe(false);
expect(contentPage.checkElementExistsById("projects_browse_options_folder_settings")).toBe(false);
expect(contentPage.checkElementExistsById('projects_browse_options_new_menu')).toBe(false);
});
});
And CLM_Page.js
var CLM_page = function() {
this.userName = element(By.id('userName'));
this.password = element(By.id('password'));
this.signIn = element(By.className('btn btn-primary'));
this.loginToDocs = function(userName, password) {
browser.driver.manage().window().maximize();
browser.driver.manage().timeouts().implicitlyWait(10000);
this.userName.sendKeys(userName);
this.signIn.click();
this.password.sendKeys(password);
return this.signIn.click();
};
};
module.exports = new CLM_page();
In conf file set to
restartBrowserBetweenTests: true
First it block is executing correctly. However while executing second it block browser restarting and closing immediately. Showing following error
Failures:
1) User Permissions Verify permissions for Project collaborator Non Admin and Read only permission group user
Message:
Failed: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used.
Stack:
NoSuchSessionError: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used.

The problem here is the webdriver session is closed after starting the test.
There is no problem with restartBrowserBetweenTests: true, Since your browser is restarted after the first test.
Since you are moving from non angular to angular application. Follow as below
browser.driver.get('http://localhost:8000/login.html');
browser.driver.findElement(by.id('username')).sendKeys('Jane');
browser.driver.findElement(by.id('password')).sendKeys('1234');
browser.driver.findElement(by.id('clickme')).click();
You are using browser.ignoreSynchronization = true; which is deprectaed. Try usingwaitForAngularEnabled(true).
make the BeforEach() as
beforeEach(function() {
browser.waitForAngularEnabled(false); // to tell protractor that this is a non- anularg page
browser.get('http://be-docs-dev.xyz.local/');
});
After moving to angular page make it as browser.waitForAngularEnabled(true);.
Hope the above answer helps you...

Based on your test case design, you can achieve the same by setting restartBrowserBetweenTests: false in conf.js file
And also clear the browser cookies and session from the browser after each it block run. Please modify your existing test script by adding afterEach
add the below snippet with existing code
afterEach(function () {
browser.manage().deleteAllCookies();
browser.executeScript('window.sessionStorage.clear();window.localStorage.clear();');
});
beforeEach function should be like
beforeEach(function() {
browser.waitForAngularEnabled(false);
browser.get('http://be-docs-dev.xyz.local/');
});
In conf.js.
Note: Default value is false. So it is not mandatory to set it as false
exports.config = {
...
restartBrowserBetweenTests: false,
...
}
If you are setting restartBrowserBetweenTests: true, This will cause your tests to slow down drastically. Please refer this

Related

Shareds Behavior Jasmine + Protractor

I'm new with Protractor and jasmine framework to test an AngularJS Application.
I whould like to reuse some of my scenarios, like Login feature can call in all scenarios of my suite.
This is my login_test.js
module.exports = function(testName, testFn) {
const loginPage = pages.login;
const mainPage = pages.main;
var protractor;
describe('common Login suite', function() {
browser.ignoreSynchronization = true;
beforeEach(function() {
});
afterAll(function() {
browser.manage().deleteAllCookies();
});
it(testName, function() {
browser.get('http://localhost:9000/');
loginPage.typeUserName('bxxxxx');
loginPage.typePassword('xxxxxx');
loginPage.clickLogin();
});
});
}
And here I have the remote_terminal feature, here I need call Login feature to perfom login in my scenario.
var loginSuite = require('./login_test.js');
loginSuite('login Suite terminal feature', function(browser) {
describe('description', function() {
console.log('describe');
it('it', function() {
console.log('it');
});
});
});
But when this spec (remote_terminal) is called to run I got this message on my console
Started
Spec started
.
common Login suite
✓ login Suite terminal feature
As you can see the describe and IT in the remote_terminal spec aren't ran.
Demo:
http://pavelbogomolenko.github.io/dry-principles-with-protractor.html
You can use pageObjects to achieve reusable code accross your test,
Let us create a new js file for login page as login_page.js as below,
var login_page = function(){
this.performLogin = function(){
//add code for performing login operation.
}
}
module.exports = new login_page();
Now you can import the login_page.js in all 'specs' and can call the performLogin() method whenever required.
Look at the example spec.js below,
describe("Test pageobject code",function(){
var login_page = require("login_page.js");
beforeAll(function(){
login_page.performLogin();
})
it("simple test to perform after login action is performed",function()
//do whatever you want to test
})
})

Use protractor on an non angular page

in my recent test I need to first login and take some actions on an non angular page (https://www.qa.dealertrack.com/default1.aspx)
then switch to an angular page and finish the test.
In conf I have
global.driver = browser.driver;
My page object looks like:
var LogInPage = function() {
this.loginUrl = 'https://www.qa.dealertrack.com/default1.aspx';
this.id = browser.driver.findElement(by.name('username'));
this.password = browser.driver.findElement(by.name('password'));
this.loginButton = browser.driver.findElement(by.name('login'));
this.logIn = function(id, password) {
// maximize window
driver.manage().window().maximize();
// log in
driver.get('https://www.qa.dealertrack.com/default1.aspx');
this.id.sendKeys(id);
this.password.sendKeys(password);
this.loginButton.click();
}
};
My test looks like:
describe('Sample Test - Log In', function() {
var loginPage = require('../pages/LogInPage.js');
/**
* Disable waiting for AngularJS for none Angular page
*/
beforeEach(function() {
isAngularSite(false);
});
it('logging in', function() {
loginPage.logIn('xxx', 'xxx');
})
})
However, even before getting to the site, protractor throws error NoSuchElementError: no such element: Unable to locate element:{'method':'name','selector':'username'}
But when I commented out all the element variables and related lines, only left
driver.get(this/loginUrl);
It worked. Why would browser.driver.get works but browser.driver.findElement does not?
This is my first question on Stackoverflow. Thank everyone!!
Before login you need to set
browser.driver.ignoreSynchronization=true;
So it shold be like
browser.driver.ignoreSynchronization=true;
login();
browser.driver.ignoreSynchronization=false;
I tried to removed all the elements I declared outside my functions in page object. Instead of that, I just hard code the elements in the function. And it worked.

How to say protractor to wait till page loads?

My application taking some to page the login page.So protractor trying to enter the user name before page loads.So i need to say protractor to wait till the login page loads.
Could you please help me what command I need to use for this and where I need to use?(Please modify my code to add the wait command)
PFB for my onPrepare and beforeeach function
onPrepare: function() {
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
})
}
beforeEach(function() {
browser.get('https://accounts.google.com/');
//browser.manage().timeouts().pageLoadTimeout(30000);
//browser.manage().timeouts().implicitlyWait(5000);
//browser.sleep( 10000 );
//browser.waitForAngular();
});
I used those commented functions,but it didn't work for me.
Please guide me.thanks in advance.
Assuming you want to click the Get Started button, wait for the button to become clickable:
var EC = protractor.ExpectedConditions;
var getStarted = element(by.css('button[title="Get started"]'));
browser.wait(EC.elementToBeClickable(getStarted), 5000);
getStarted.click();
Use the wait command: browser.driver.wait(condition, timeout);
onPrepare: function() {
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
});
}
beforeEach(function() {
browser.driver.get('https://accounts.google.com/');
return browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function (url) {
return url.indexOf('https://accounts.google.com/') > -1;
});
}, 5000);
//whatever you want after
});
you can wait for any condition like that.
Also, google f.e is not an angular page, so you should use:
browser.driver.get instead of protractors browser.get,
or it will wait for angular on the page.

Detect internet working or not in Cordova Ionic Framework

I want show message when internet not working in cordova Ionic Application, Can anybody done this in Ionic Cordova Application.
There is a network-information plugin to get network information from the device. Add the
cordova plugin add org.apache.cordova.network-information
include it and in app.js and register an offline event handler from within the onDeviceReadyevent handler,
onDeviceReady: function() {
document.addEventListener("offline", onOffline, false);
},
onOffline: function () {
//handle offline
}
Its quite simple actually.
Add the plugin:
cordova plugin add org.apache.cordova.network-information
You don't need to include anything in index.html. Just add $cordovaNetwork on the controller you are using. And, the following snippet will go well with it.
document.addEventListener("deviceready", function () {
// Check for network connection
if(window.Connection) {
//you can log your connection as well, whether it is internet, wifi and so on.In this case you are checking for no connection
alert(navigator.connection.type);
if(navigator.connection.type == Connection.NONE) {
$ionicPopup.confirm({
title: 'Network Problem',
content: 'Sorry, Please Check Your Network Connection.'
})
//or you can simply navigate it to a page with the no internet connection html.
}
}
})
//This is one of the way. The next way is having the following snippet in the controller you want to use. Don't forget to add the $cordovaNetwork, $ionicPlatform in this case.
var type = $cordovaNetwork.getNetwork();
var isOnline = $cordovaNetwork.isOnline();
var isOffline = $cordovaNetwork.isOffline();
$rootScope.$on('$cordovaNetwork:online', function(event, networkState){
var onlineState = networkState;
alert(onlineState);
})
$rootScope.$on('$cordovaNetwork:offline', function(event, networkState){
var offlineState = networkState;
alert(offlineState);
})
document.addEventListener("deviceready", function () {
$rootScope.$on('$cordovaNetwork:online',function(event,networkState){
$location.path('/japp/login');
})
$rootScope.$on('$cordovaNetwork:offline',function(event,networkState){
$ionicPopup.confirm({
title: "Internet Disconnected",
content: "The internet is disconnected on your device."
}).then(function(){
ionic.Platform.exitApp();
})
})
If you are still having problem feel free to ask any small detail.
here is some discussion on the ionic forum: http://forum.ionicframework.com/t/how-to-check-network-coneection/15806/14
you can find a lot like this one. I would suggest to use ngCordova and do something like this:
$rootScope.$on('$cordovaNetwork:online', function() {});
$rootScope.$on('$cordovaNetwork:offline', function() {});
After installing plugin (cordova plugin add org.apache.cordova.network-information), you can use following code inside app.js to show alert message
if(window.Connection) {
console.log("checking connection");
if(navigator.connection.type == Connection.NONE) {
$ionicPopup.alert({
title: "No Internet Connection",
content: "Internet Connection is not available. In offline you can see previously fetched data.",
okType:"balanced",
})
.then(function(result) {
if(!result) {
console.log('ok clicked');
}
});
}
}
Hi there is another issue here. Network information only tells you wether there is a connection. But that doesn't mean you have connection to a website and/or a running database. In most cases an app depends on the website and/or the database are available. So you have to check those too.

Simple protractor test for isElementPresent failing with unsupported locator strategy

My test:
it('should allow login', function() {
browser.get('index.html');
$('#username').sendKeys('administrator');
$('#password').sendKeys('password');
$('#login').click();
var logout = $('#logout');
expect($p.isElementPresent(logout)).to.eventually.be.true;
});
But this errors out with:
Error: Unsupported locator strategy: click
at Error (<anonymous>)
at Function.webdriver.Locator.createFromObj (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/locators.js:97:9)
at Function.webdriver.Locator.checkLocator (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/locators.js:111:33)
at webdriver.WebDriver.findElements (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:805:31)
at webdriver.WebDriver.isElementPresent (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver/webdriver.js:787:29)
at Protractor.isElementPresent (/usr/local/lib/node_modules/protractor/lib/protractor.js:476:22)
at /Users/pschuegr/wt/client/e2e/login_test.js:26:15
Strangely, it points to the isElementPresent line, rather than the line with the click. I'm pretty new to webdriver, so apologies if I missed something obvious. I'm running using the mocha framework (which means the canary version of protractor), fwiw.
Any ideas appreciated.
Using the latest Protractor build, you can shorten the above answer to the following:
expect(element(by.css('#logout')).isPresent()).toBeTruthy();
This way you do not have to perform the browser.wait and you reduce the number of calls to isElementPresent.
$('#logout') is a WebElement. isElementPresent takes a locator, like by.css
$('#username').sendKeys('administrator');
$('#password').sendKeys('password');
$('#login').click();
var logout = by.css('#logout');
browser.wait(function() { return $p.isElementPresent(logout); }, 8000);
expect($p.isElementPresent(logout)).toBeTruthy();
The safest approach I would take is depicted in the following code snippet:
it('should return true when element is present', function () {
var logout;
logout = $('#logout');
browser.driver.isElementPresent(logout).then(function (isPresent) {
isPresent = (isPresent) ? true : browser.wait(function () {
return browser.driver.isElementPresent(logout );
}, 15000); //timeout after 15s
expect(isPresent).toBeTruthy();
});
});
Above code starts of with a promise to check if an element exists, and if true then assign it true, otherwise wait and keep pooling for the next 15sec to see if element is present, and in both cases we expect it to be true.
This should work :
var logout = $('#logout');
expect(logout.isPresent()).to.eventually.be.true;

Resources