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##").
Related
I'm using the Page Object Model I just started i created 2 packages one is com.automation.pages another one is com.automation.testcases.
In both packages I created a class for the login page it works fine I'm sharing the code below.
package com.automation.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPage {
WebDriver driver;
public LoginPage(WebDriver ldriver)
{
this.driver=ldriver;
}
#FindBy (xpath="//input[#name='email'] ") WebElement email;
#FindBy (xpath="//input[#name='password']") WebElement password;
#FindBy (xpath="//body/div[2]/div[2]/div[2]/form[1]/div[3]/div[2]/button[1]") WebElement loginbutton;
public void logintoLabaiik(String email1, String password1 )
{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
email.sendKeys(email1);
password.sendKeys(password1);
loginbutton.click();
}
}
The problem I'm facing when I working on the new page is when I created a driver and when using ldriver it throws me an error also when I replace the "l" still it throws me the error. kindly solve my problem.
package com.automation.pages;
import org.openqa.selenium.WebDriver;
public class TaxSetup {
WebDriver driver;
public TaxSetup(WebDriver driver)
{
this.driver.ldriver;
}
}
It looks you have an issue in TaxSetup constructor.
This should work.
public TaxSetup(WebDriver driver){
this.driver=driver;
}
Take a look at how to create 2 Page Object classes and use them in tests:
LoginPage
public class LoginPage {
final WebDriver driver;
public LoginPage(WebDriver driver){
this.driver=driver;
}
// page implementation
}
TaxSetup
public class TaxSetup {
final WebDriver driver;
public TaxSetup(WebDriver driver){
this.driver=driver;
}
// page implementation
}
How to use in test
public class SomeTest {
WebDriver driver;
LoginPage loginPage;
TaxSetup taxSetupPage;
#BeforeClass
public void initDriverAndPages() {
driver = ... // e.g. new ChromeDriver()
loginPage = PageFactory.initElements(driver, LoginPage.class);
taxSetupPage = PageFactory.initElements(driver, TaxSetup.class);
}
#Test
public void someTest() {
// implement test using loginPage, taxSetupPage as you like
}
#AfterClass
public void quitDriver() {
driver.quit();
}
}
Please correct the below line in your TaxSetUp constructor.
this.driver.ldriver;
This is suppose to be
this.driver = driver;
And yes, you have to pass the WebDriver instance for all the page classes that you create as part of your application otherwise they will assign default value to the driver which is null.
I am new in selenium and trying to run a basic test both firefox and chrome in parallel. Everthing works for firefox but chrome is not working. Actually chrome browser opens up but does nothing unless I click email input and then click anywhere expect email input. When I do that my test starts on chrome and everything works fine. I am really sure that I should'nt click manually to start the test :)
Here is my page object;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import page.objects.AbstractPageObject;
public class LoginPage extends AbstractPageObject {
#FindBy(xpath = "//input[#type='email']")
private WebElement email;
#FindBy(xpath = "//input[#type='password']")
private WebElement password;
#FindBy(xpath = "//button[#type='submit']")
private WebElement continueButton;
public void verifyAllElementsAreDisplaying() {
email.isDisplayed();
password.isDisplayed();
continueButton.isDisplayed();
}
public void fillEmail (String userEmail) {
email.clear();
email.sendKeys(userEmail);
}
public void fillPassword (String userPassword) {
password.clear();
password.sendKeys(userPassword);
}
public void login () {
this.continueButton.click();
}
}
And here is my test;
import org.testng.annotations.Test;
import page.objects.Login.LoginPage;
public class VerifyLogin extends BaseTest {
#Test(description = "Verfifies Login Page Functionality")
public void verifyLogin() throws InterruptedException {
LoginPage loginPage = new LoginPage();
loginPage.verifyAllElementsAreDisplaying();
loginPage.fillEmail("email");
loginPage.fillPassword("***");
Thread.sleep(2000);
}
}
In BaseTest class I have #BeforeSuit and #AfterSuite annotations to manage driver.
I am using POM pattern in cucumber and in StepDefinition package I created one 'Hooks.java' to launch the browser and 'CustomersModuleSteps.java' to add new customer when I am executing the runner file I am receiving the below error. someone please look into it and advise.
Error:```
************ open URL ************
************ Enter Username & password ************
************ clicking on login button ************
************ Validating page Title ************
************ clicking on CustomersMenu **********
Given user clicks on customers menu # com.nopCommerse.StepDefinition.CustomersModuleSteps.user_clicks_on_customers_menu() in file:/Users/rajasekhar/eclipse-workspace/nopCommerse/target/test-classes/
java.lang.NullPointerException
at org.openqa.selenium.support.pagefactory.DefaultElementLocator.findElement(DefaultElementLocator.java:69)
at org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler.invoke(LocatingElementHandler.java:38)
at com.sun.proxy.$Proxy19.click(Unknown Source)
at com.nopCommerse.Base.ElementExtension.ClickOnIt(ElementExtension.java:55)
at com.nopCommerse.pageObjects.CustomersModuleObjects.clickCustomersMenu(CustomersModuleObjects.java:31)
at com.nopCommerse.StepDefinition.CustomersModuleSteps.user_clicks_on_customers_menu(CustomersModuleSteps.java:32)
at ✽.user clicks on customers menu(com.Features/CustomersModule.feature:4)
When user clicks on customers menu item # com.nopCommerse.StepDefinition.CustomersModuleSteps.user_clicks_on_customers_menu_item() in file:/Users/rajasekhar/eclipse-workspace/nopCommerse/target/test-classes/
************ clicking on logout link ************
************ closing the Browser ************
Failed scenarios:
com.Features/CustomersModule.feature:3 # Add a new customer
1 Scenarios (1 failed)
2 Steps (1 failed, 1 skipped)
0m24.213s
My Base class
public class TestBase extends ElementExtension {
public WebDriver driver;
public Logger logger;
public Properties configProp;
public CustomersModuleObjects custmod;
public LoginPageObjects lp ;
}
My CustomersModuleSteps.java
package com.nopCommerse.StepDefinition;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import com.nopCommerse.Base.TestBase;
import com.nopCommerse.pageObjects.CustomersModuleObjects;
import io.cucumber.java.Before;
import io.cucumber.java.en.*;
public class CustomersModuleSteps extends TestBase {
#Before
public void setup() {
//object creation for logger
logger = Logger.getLogger("EmployeeRestApi"); //added logger
PropertyConfigurator.configure("Log4j.properties"); //added logger
logger.setLevel(Level.DEBUG);
}
#Given("user clicks on customers menu")
public void user_clicks_on_customers_menu() {
logger.info("************ clicking on CustomersMenu **********");
custmod = new CustomersModuleObjects(driver);
custmod.clickCustomersMenu();
}
#When("user clicks on customers menu item")
public void user_clicks_on_customers_menu_item() {
logger.info("************ clicking on customer Menu item **********");
custmod.clickCustomerMenuItem();
}
}
And this is my page factory class
package com.nopCommerse.pageObjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
import com.nopCommerse.Base.TestBase;
public class CustomersModuleObjects extends TestBase {
WebDriver driver;
//constructor of CustomersModule class
public CustomersModuleObjects(WebDriver ldriver) {
driver = ldriver;
PageFactory.initElements(ldriver,this);
}
//Identify webElements
#FindBy(how = How.XPATH,using = "//a[#href='#']//span[contains(text(),'Customers')]")
WebElement CustomersMenu;
#FindBy(how = How.XPATH,using ="//a[#href='/Admin/Customer/List']//span[contains(text(),'Customers')]")
WebElement customerMenuItem;
//action methods for elements identified
public void clickCustomersMenu() {
ClickOnIt(CustomersMenu);
}
public void clickCustomerMenuItem() {
ClickOnIt(customerMenuItem);
}
}
This could be for two reasons in my experience:
You are not initializing the WebDriver correctly, so that you could debug and check that driver is not null at this point CustomersModuleSteps.java:32
The XPath for the element is not the correct one, so that you could install an extension for google chrome (I use xpath helper) and check that you are locating correctly the element in the Page.
In addition to you could improve the structure, extending a little bit the POM Patterns and get the code cleaner splitting the Page Actions and Page Objects as you can see in the following example:
Web Page Element definition
public class LoginPageElements {
protected WebDriver driver;
public LoginPageElements(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
//Mapping web elements
#FindBy(id = "userName")
protected WebElement TxtUserName;
#FindBy(id = "Password")
protected WebElement TxtPassword;
#FindBy(id = "Login")
protected WebElement BtnLogin;
}
Web Page Actions definition
public class LoginActions extends LoginPageElements {
WebDriverWait wait;
public LoginActions (WebDriver driver, WebDriverWait wait) {
super(driver);
this.wait = wait;
}
public void Login() {
fillUserName();
fillPassword();
ClickLogin();
}
private void fillUserName() {
wait.until(ExpectedConditions.visibilityOf(TxtUserName));
TxtUserName.sendKeys("User");
}
private void fillPassword() {
wait.until(ExpectedConditions.visibilityOf(TxtPassword));
TxtPassword.sendKeys("Pass");
}
private void ClickLogin() {
wait.until(ExpectedConditions.visibilityOf(BtnLogin));
wait.until(ExpectedConditions.elementToBeClickable(BtnLogin));
BtnLogin.submit();
}
Test Class
public class LoginExample {
WebDriver driver;
WebDriverWait wait;
LoginActions loginActions;
#BeforeClass
public void setDriver() {
System.setProperty("webdriver.chrome.driver", ClassLoader.getSystemResource("chromedriver.exe").getPath());
driver = new ChromeDriver();
wait = new WebDriverWait(driver, 10);
loginActions = new LoginActions(driver, wait);
driver.manage().window().maximize();
}
#Test()
public void testLogin() {
driver.get("http://www.YourLoginPage.com/");
loginActions.Login();
}
#AfterClass
public void close() {
driver.quit();
}
}
Hope this could help you and so that you will be able to find where the problem is easier
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");
}
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();
}
}