I started encountering problems when I use static objects reference for WebDriver and run the tests in parallel.
public static WebDriver driver;
Hence I decided to use non-static object reference for the WebDriver.
private WebDriver driver;
Now when I use POM with Page Factory, my understanding is that everytime I create a Test I will have to be creating a new Object in the test class as shown below.
/* Constructor in the Page Object class */
private WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
2 testcases as shown below in the same class.
private LoginPage loginPage;
#Test
public void testCase1() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
#Test
public void testCase2() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
My question here is a
Am I right in creating page object for every test cases?
Is there any way I can optimize this? Because One doubt I got is that non-static object reference may be getting overridden and causing problems in one of the methods if I run them in parallel.
Sorry if my query is naive. Any help would be appreciated.
You do not need to initialize it again. Also, initialize the pages in #BeforeTest rather than in test cases.
Here i would like to give you example of Page object model. Hope you can relate this.
My Main test:
#Before
public void SelectBrowser(){
driver = WebUtils.SelectBrowser(driver,"Chrome");
}
#Test
public void LoginToGmail() throws InterruptedException{
//WebDriver driver = new FirefoxDriver();
//MAximize the Screen
driver.manage().window().maximize();
//Go to Gmail Login Page
SignInPage SignInPage = new SignInPage();
WebUtils.GoToSignInPageForPropertyFile(driver, "URL");
//Click on Next
SignInPage.ClickToLogin(driver, By.cssSelector("input[id='next']"));
Now Supporting class:
GoToSignInPageForPropertyFile method will be in WebUtils
Whatever i write in Webutils will be used by each page object class.
For e.g.
public class WebUtils {
public static pageobject.SignInPage GoToSignInPageForPropertyFile(WebDriver driver, String URL) {
ReadFileData File = new ReadFileData();
Properties Values = File.ReadFile();
driver.get(Values.getProperty("URL"));
return PageFactory.initElements(driver, pageobject.SignInPage.class);
}
}
Now the method ClickToLogin is defined under SignInPage class as:
public class SignInPage {
public EmailViewPage ClickToLogin(WebDriver driver, By by) {
WebUtils.Click(driver, by);
return PageFactory.initElements(driver, EmailViewPage.class);
}
}
Which will further be in Webutils
public class WebUtils {
public static void Click(WebDriver driver, By by) {
WebElement Element = driver.findElement(by);
Element.click();
}
}
Related
I am using TestNG with java to execute my scripts.
I have a fixed tab bar with 5 elements fixed for all time once the user logged in to the application.
I am able to execute the script by clicking on the first element from the list, but for the second time when I try to click on another element from the tab bar it is failing continuously. I tried adding explicit waits, but is not helping me either.
Here is a snippet of my code:
afterLogin.java
public class afterLogin {
WebDriver driver;
WebDriverWait wait;
#FindBy(xpath="//*[#id=\"root\"]/div/div[2]/div/div[1]/div[1]/div[3]")
WebElement button1;
#FindBy(xpath = "//*[#id=\"root\"]/div/div[2]/div/div[1]/div[1]/div[2]")
WebElement button2;
public afterLogin(WebDriver driver){
this.driver = driver;
wait = new WebDriverWait(driver,Duration.ofSeconds(300));
}
public void clickButton1() {
wait.until(ExpectedConditions.visibilityOf(button1);
button1.click();
}
public void clickButton2(){
wait.until(ExpectedConditions.visibilityOf(button2));
button2.click();
}
}
testCase1.java
#Test
public void init() throws Exception {
afterLogin obj = PageFactory.initElements(driver, afterLogin.class);
obj.clickButton1();
}
testCase2.java
#Test
public void init() throws Exception {
afterLogin obj = PageFactory.initElements(driver, afterLogin.class);
obj.clickButton2(); /////THIS IS FAILING
}
I was able to solve this by using Thread.sleep(1000). I will try to update my code to use Implicit waits, but this solves the purpose for now.
I have used Page Object Model design pattern along with Cucumber. So for this I have created two pages named as abstractPage and loginPage but on running the script i get null pointer exception even when i have already initialize the webelements using pagefactory , please have a look at below code:
abstractPage:
public class abstractPage {
protected WebDriver driver;
public static loginPage lpOBJ;
public void openBrowsernURLhit() {
driver=new FirefoxDriver();
driver.get("http://www.facebook.com");
PageFactory.initElements(driver, loginPage.class);
}
}
loginPage:
public class loginPage extends abstractPage {
#FindBy(name = "email")
public WebElement username;
#FindBy(name = "pass")
public WebElement password;
#FindBy(id = "u_0_2")
public WebElement loginButon;
public void loginIntoApp() {
String url=driver.getCurrentUrl();
System.out.println("the url is::::::::::::::::"+url);
username.sendKeys("testuser");
password.sendKeys("123");
}
public void clicklogn() {
loginButon.click();
}
}
And then I have a class stepDefination from where I am calling the above methods of login class. Browser is opened fine and url is hit but when it goes inside loginintoapp() method it throws exception on first line itself.
public class SmokeTest {
#Given("^Open Firefox and start application$")
public void Open_Firefox_and_start_application() throws Throwable {
abstractPage obj = new abstractPage();
obj.openBrowsernURLhit();
}
#When("^I enter valid \"([^\"]*)\" and \"([^\"]*)\"$")
public void I_enter_valid_username_and_password(String arg1, String arg2) throws Throwable {
loginPage lpobj = new loginPage();
lpobj.loginIntoApp();
}
#Then("^user should be able to login successfully$")
public void user_should_be_able_to_login_successfully() throws Throwable {
loginPage lpobj = new loginPage();
lpobj.clicklogn();
}
}
I also have a TestRunner class where i have glued my stepDefination:
#RunWith(Cucumber.class)
#CucumberOptions(
features= "features",
glue= {"stepDefination"},
plugin= {"html:target/cucumber-html-report"}
)
public class TestRunner {
}
But on running the above script I always get NullPointerException in first line ofloginIntoApp() method.I have already used Pagefactory to initialize webelements but i guess "driver" variable is not getting initialized in Login class though i have inherited asbtract class where i m instantiating the driver due to which it is throwing null pointer.Please see what I am i doing wrong here.Error is as follows:
1 Scenarios ([31m1 failed[0m)
3 Steps ([31m1 failed[0m, [36m1 skipped[0m, [32m1 passed[0m)
0m18.149s
java.lang.NullPointerException
at pages.loginPage.loginIntoApp(loginPage.java:22)
at stepDefination.SmokeTest.I_enter_valid_username_and_password(SmokeTest.java:33)
at ?.When I enter valid "t1#gmail.com" and "pass"(MyApp.feature:5)
Thanks
please add the following constructor. It may solve the issue.
public loginPage(){
PageFactory.initElements(driver, loginPage.class);
}
you can put outside as well like,
public void loginIntoApp() {
String url=abstractPage.driver.getCurrentUrl();
System.out.println("the url is::::::::::::::::"+url);
loginPage lp=PageFactory.initElements(abstractPage.driver, loginPage.class);
lp.username.sendKeys("testuser");
lp.password.sendKeys("123");
}
other way is,
public class SmokeTest extends abstractPage {
#Given("^Open Firefox and start application$")
public void Open_Firefox_and_start_application() throws Throwable {
openBrowsernURLhit();
}
#When("^I enter valid \"([^\"]*)\" and \"([^\"]*)\"$")
public void I_enter_valid_username_and_password(String arg1, String arg2) throws Throwable {
loginPage lpobj = PageFactory.initElements(driver, loginPage.class);
lpobj.loginIntoApp();
}
#Then("^user should be able to login successfully$")
public void user_should_be_able_to_login_successfully() throws Throwable {
loginPage lpobj = PageFactory.initElements(driver, loginPage.class);
lpobj.clicklogn();
}
}
the simplest way to solve the problem is to make your driver object static.
protected static WebDriver driver;
as you are using page factory, you also need to initiazlize the page object, otherwise all the the WebElement will be null
public loginPage(){
PageFactory.initElements(driver, this);
}
or this, which I don't think is a good practice and people should avoid this.
public void loginIntoApp() {
String url=driver.getCurrentUrl();
System.out.println("the url is::::::::::::::::"+url);
PageFactory.initElements(driver, this);
username.sendKeys("testuser");
password.sendKeys("123");
}
Can anyone please resolve the issue in the below post.
Selenium Framework Page Object Model and Page Navigation
I am not able to resolve the null pointer exception issue when a page returns an object of other page. Can anyone please tell what is the exact way of doing it. As explained in the above link, it's not clear how the error is resolved.
I will try illustrating PageFactory example using 3 different classes types.
Base Class- Has configuration setting like driver declaration
POM Class- Contains the POM objects for a single page
Test Class-Class containing test steps
BaseClass Example
public class BaseClass {
public WebDriver driver=null;
public BaseClass() throws MalformedURLException {
driver=new firefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get(baseURL);
}
POM Class example
//Class1
public class WebshopHomePage {
WebDriver driver;
public WebshopHomePage(WebDriver driver){
this.driver=driver;
}
#FindBy(how=How.LINK_TEXT,using="Log in")//Identifying page elements
WebElement loginLink;
public void clickLoginLink(){
loginLink.click();
}
}
//Class2
public class SignInSignUpPage {
WebDriver driver;
public SignInSignUpPage(WebDriver driver){
this.driver=driver;
}
#FindBy(how=How.ID,using="Email")
WebElement emailID;
}
TestClass Example
public class WebShopSignInTest extends BaseClass {
#Test
public void testSteps() {
System.out.println("I'm in teststeps!!");
WebshopHomePage wshpObj=PageFactory.initElements(driver,WebshopHomePage.class);//Assigning POM class1 objects to driver
wshpObj.clickLoginLink();
SignInSignUpPage signInSignUpPageObj=PageFactory.initElements(driver, SignInSignUpPage.class);//Assigning POM class2 objects to driver
signInSignUpPageObj.enterCredsSubmit(userID, passw0rd);
}
package org.pom;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class GoogleHomePageObjects
{
public GoogleHomePageObjects(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
#FindBy(name="q")
public WebElement txtSearch;
#FindBy(name="btnG")
public WebElement btnSearch;
#FindBy(linkText="Selenium - Web Browser Automation")
public WebElement lnkSelenium;
public void searchGoogle(String SearchText)
{
txtSearch.sendKeys(SearchText);
btnSearch.click();
}
public SeleniumPageObjects clickSelenium()
{
lnkSelenium.click();
return new SeleniumPageObjects(driver); //Here is the issue and i am getting error
}
}
//test class 2
package org.pom;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class SeleniumPageObjects{
public SeleniumPageObjects(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
#FindBy(linkText="Download")
public WebElement lnkDownload;
#FindBy(xpath=".//*[#id='header']/h1/a")
public WebElement lnkHome;
public void clickDownloads()
{
lnkDownload.click();//Here it throws null pointer excception
}
public void clickHome()
{
lnkHome.click();
}
}
Below is my main class:
package org.pom;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class GoogleSearchTest
{
public static void main(String[] args) throws InterruptedException
{
System.setProperty("webdriver.gecko.driver","D:\\Desktop\\Selenium\\Jars\\geckodriver-v0.11.1-win64\\geckodriver.exe");
WebDriver driver=new FirefoxDriver();
driver.get("http://www.google.com");
GoogleHomePageObjects page=new GoogleHomePageObjects(driver);
page.searchGoogle("Selenium");
Thread.sleep(4000);
SeleniumPageObjects selPage=page.clickSelenium();
Thread.sleep(4000);
selPage.clickDownloads();
Thread.sleep(4000);
selPage.clickHome();
}
}
In the below example, We have created a Login class , Home class, and a Test class ...
It is not necessary to create one class for one page may be you can group the functionality or modules based on your convenience...
Summary:-
Created Login Class with all the required objects...and the loginas method should return the homepage class.....
public class LoginPage {
private final WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
// Check that we're on the right page.
if (!"Login".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps logging out first
throw new IllegalStateException("This is not the login page");
}
}
// The login page contains several HTML elements that will be represented as WebElements.
// The locators for these elements should only be defined once.
By usernameLocator = By.id("username");
By passwordLocator = By.id("passwd");
By loginButtonLocator = By.id("login");
public LoginPage typeUsername(String username) {
driver.findElement(usernameLocator).sendKeys(username);
// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}
public LoginPage typePassword(String password) {
driver.findElement(passwordLocator).sendKeys(password);
// Return the current page object as this action doesn't navigate to a page represented by another PageObject
return this;
}
public HomePage submitLogin() {
// This is the only place that submits the login form and expects the destination to be the home page.
// A seperate method should be created for the instance of clicking login whilst expecting a login failure.
driver.findElement(loginButtonLocator).submit();
// Return a new page object representing the destination. Should the login page ever
// go somewhere else (for example, a legal disclaimer) then changing the method signature
// for this method will mean that all tests that rely on this behaviour won't compile.
return new HomePage(driver);
}
// Conceptually, the login page offers the user the service of being able to "log into"
// the application using a user name and password.
public HomePage loginAs(String username, String password) {
// The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
typeUsername(username);
typePassword(password);
return submitLogin();
}
}
2. Created Homepage class , I have added only a sample verification method here , may be you can add methods as per your application needs...
class HomePage {
private final WebDriver driver;
public HomePage(WebDriver driver) {
this.driver = driver;
// Check that we're on the right page.
if (!"HOME".equals(driver.getTitle())) {
// Alternatively, we could navigate to the login page, perhaps
// logging out first
throw new IllegalStateException("This is not the home page");
}
}
// below method is just a sample method
public HomePage verifyRecords() {
/// your homepage validation
return null;
}
}
Now we are going to see how to put the above class together and make it work as per your requirement...
class Test {
public static void main(String[] args) {
LoginPage login = new LoginPage(new FirefoxDriver());
// login and verify records in home page
login.loginAs("myname", "pass##").verifyRecords();
}
}
In this line login.loginAs("", "").verifyRecords(); we are calling a method from login class and the method that is being called would return HomePage class....
You can create any no of pom classes and return it like the above......Like create some thing like dashboard and return it from homepage class
How returning page works :-
login.loginAs("myname", "pass##").verifyRecords();
In the above code once this login.loginAs("myname", "pass##") snippet executes , it will complete the login action and returns this method submitLogin(); which in turns returns new HomePage......
Here once execution of login.loginAs("myname", "pass##") is done it will become new Homepageobject..... Javacompiler is smart enough to manipulate that and provides the Homepageobject's methods once you put a dot after login.loginAs("myname", "pass##").
It runs the first test OK, but then I'm getting a null pointer exception when running the "Edit Profile" test, and I'm not sure why. I globally declared public driver.
public class TestLogin
{
public WebDriver driver;// = new FirefoxDriver();
public String baseURL = "mytestsite.com";
#BeforeTest
public void setBaseURL()
{
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait( 20L, TimeUnit.SECONDS );
driver.get( baseURL );
}
// Login test
#Test
public void testLogin() throws InterruptedException{
driver.manage().timeouts().implicitlyWait(20L, TimeUnit.SECONDS);
analyticsLoginPage mylogin = PageFactory.initElements(driver, ` ` analyticsLoginPage.class);
analyticsLandingPage landingpage = mylogin.login("username", "password");
Thread.sleep(3000);
}
// Edit Profile test
#Test // (dependsOnMethods = { "testLogin" })
public void verifyProfile()
throws InterruptedException
{
// driver = new FirefoxDriver();
Thread.sleep( 3000 );
analyticsLandingPage landingpage = new analyticsLandingPage( driver );
Thread.sleep( 3000 );
landingpage.gotoProfile();
// Thread.sleep(5000);
analyticsEditProfilePage editprofile = PageFactory.initElements( driver, analyticsEditProfilePage.class );
editprofile.verifyEditFirstName();
editprofile.verifyEditLastName();
editprofile.verifyCompanyName();
editprofile.verifyReportingProfile();
editprofile.verifyUsageStatistics();
}
Landing page class
package com.tapanalytics.pom.domain;
import java.util.concurrent.TimeUnit;
import javax.security.auth.login.Configuration;
import org.junit.Test;
public class analyticsLandingPage
{
WebDriver driver;
public analyticsLandingPage( WebDriver driver )
{
this.driver = driver;
}
#FindBy( xpath = Configuration.manage_dashboard )
public WebElement manage_dashboard;
#FindBy( xpath = Configuration.manage_services )
public WebElement manage_services;
#FindBy( xpath = Configuration.profile )
public WebElement profile;
#FindBy( xpath = Configuration.support )
public WebElement support;
#FindBy( xpath = Configuration.logout )
public WebElement logout;
public void gotoMangeDashboards()
{
manage_dashboard.click();
}
public void gotoServices()
{
manage_services.click();
}
public void gotoProfile()
{
profile.click();
}
public void gotoSupport()
{
support.click();
}
public void Logout()
{
logout.click();
}
}
There are multiple ways you could fix this. I think you could use a #BeforeMethod method that initializes the driver before each test method and then a #AfterMethod that calls driver.quit() and sets the driver to null after each test method. The non-static driver can remain the same as a class member.
Personally, with Selenium tests I never re-use the same driver for multiple test methods. Your asking for trouble when you do that and you usually need to enforce test method order.
More advanced: create your WebDriver instance in a data provider and then pass it into each test method. Then, have a #AfterMethod that closes the driver after each test. Then, your test class doesn't need to contain its own shared driver instance and TestNG handles your test multi-threading.
Try with
public static WebDriver driver;
in two classes.
Thank You,
Murali
I'm trying to test one specific Selenium's Actions class method, which is as below.
public Actions sendKeys(java.lang.CharSequence... keysToSend)
Sends keys to the active element. This differs from calling WebElement.sendKeys(CharSequence...) on the active element.
public class Demo_1 {
private WebDriver driver;
private Actions action;
private String baseUrl;
#Before
public void setUp() throws Exception {
File file = new File("C:\\Users\\ProgramFiles\\firefox.exe");
FirefoxProfile profile = new FirefoxProfile();
FirefoxBinary binary = new FirefoxBinary(file);
driver = new FirefoxDriver(binary, profile);
action = new Actions(driver);
baseUrl = "http://www.mortgagecalculator.org";
}
#Test
public void testUntitled() throws Exception {
driver.get(baseUrl + "/");
driver.findElement(By.name("param[homevalue]")).click();
driver.findElement(By.name("param[homevalue]")).clear();
action.sendKeys("300000");
}
#After
public void tearDown() throws Exception {
//driver.quit();
}
}
I can do this alternatively, but in some cases when there is no WebElement, action.sendKeys can help to send CharSequence without any WebElement as parameter.
Can some come up with similar kind of issue, as the above code is not working :(
Cause its Actions class object so you need to tell the driver the actions you are performing.
action.sendKeys("300000").perform();
Will do the needful.