Selenium WebDriver POM Handling compound classes - java

I am new to selenium and I am facing this null pointer exception in my code,
Here is a class of one of my page object (Login Page).
package Pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import Lib.lib;
public class LoginPage extends lib{
WebDriver driver;
By loginLink = By.xpath("/html/body/nav/div/a[7]");
By emailInput = By.name("email");
By passwordInput = By.name("password");
By signInBtn = By.className("btn btn-primary btn-lg");
public LoginPage(WebDriver driver)
{
this.driver=driver;
}
public void redirectToLogin()
{
driver.findElement(loginLink).click();
new WebDriverWait(driver, 30).until(ExpectedConditions.visibilityOfElementLocated(emailInput));
}
public void enterEmail(String email)
{
driver.findElement(emailInput).sendKeys(email);
}
public void enterPW(String password)
{
driver.findElement(passwordInput).sendKeys(password);
}
public void clickOnSignIn() throws Exception
{
driver.findElement(signInBtn).click();
Thread.sleep(3000);
}
public void loginToKB(String userEmail, String userPW) throws Exception
{
this.redirectToLogin();
this.enterEmail(userEmail);
this.enterPW(userPW);
this.clickOnSignIn();
}
}
And this is my Test Case code
package TestCases;
import org.testng.annotations.Test;
import Lib.lib;
import Pages.LoginPage;
public class logging_in extends lib {
LoginPage memLogin = new LoginPage(driver);
#Test
public void user_login() throws Exception
{
memLogin.loginToKB("uzii#test.com", "uziii");
}
}
I am importing the chrome driver configuration from the lib class, which is following,
package Lib;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;
public class lib {
protected static WebDriver driver = null;
#BeforeTest
public void chrome_extension()
{
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
driver.get("http://www.testsite.com");
}
#AfterTest
public void quit()
{
driver.quit();
}
}
When I am running my Test Case (logging_in), I initially redirect to website page, but after that it stops the execution and gives me compound class error.
Error seems to be pointed towards this,
By signInBtn = By.className("btn btn-primary btn-lg");
Please let me know, how to handle compound classes. Any help/feedback will be appreciated. Thanks.

You are passing static driver instance without initialization to LoginPage(Webdriver driver) constructor. You would need to initialize the drive either in static block in lib or before initializing memLogin variable in logging_in page.
for compound classes you will have to use XPath. if you can show us html snippet of your DOM, we should be able to tell you the relevant XPath.

You have declared web-driver driver instance as private in class lib which is correct then your'e again declaring web-driver driver instance in class LoginPage which is incorrect.
Remove the second declaration to avoid the null pointer exception.

Related

I can't work out why "this.driver is null" when running an assertion

First time poster so apologies if I'm breaking some guidelines.
I'm teaching myself Java/Selenium/Chromedriver and I've hit the first problem that I haven't been able to work out myself. I'll do my best to represent it below but please ask for more info if I haven't included what I needed to! Here is the test:
#Test
public void loginAsTomSmith(){
LoginPage loginPage = homePage.clickFormAuthentication();
loginPage.enterUsername("tomsmith");
loginPage.enterPassword("SuperSecretPassword!");
SecureAreaPage secureAreaPage = loginPage.clickLogin();
secureAreaPage.getBannerText();
assertTrue(secureAreaPage.getBannerText()
.contains("You logged into a secure area!"),"Incorrect message displayed");
}
As you can see, I pass the driver from the homepage right over to the login page in my first step (I think). I then eventually pass it over to the secureareapage and it's there that I get the following error when I run the assertion:
java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.WebDriver.findElement(org.openqa.selenium.By)" because "this.driver" is null
It's notable that I've been following an online course but I'm going rogue for this specific project and doing a few things that I wasn't taught. For example, in the course every page object is a distinct class whereas I've decided to have all pages be an extension of a base page class so they can share basic methods more easily. I'm starting to worry that there have been consequences of that decision that I didn't understand.
Anyway, since the project is so small it probably makes sense to post it in full. Thanks in advance for your help. Huge fan of your work!
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class BasePage{
protected WebDriver driver;
protected BasePage(WebDriver driver){
this.driver = driver;
}
protected void clickLink(By linkTextBy){
driver.findElement(linkTextBy).click();
}
protected void populateTextField(By textFieldBy, String inputText){
driver.findElement(textFieldBy).sendKeys(inputText);
}
protected void clickButton(By buttonBy){
driver.findElement(buttonBy).click();
}
}
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class HomePage extends BasePage{
// private WebDriver driver;
private By formAuthenticationLink = By.linkText("Form Authentication");
public HomePage(WebDriver driver){
super(driver);
}
public LoginPage clickFormAuthentication(){
clickLink(formAuthenticationLink);
return new LoginPage(driver);
}
}
package pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage extends BasePage{
private By usernameTextField= By.id("username");
private By passwordTextField = By.id("password");
private By loginButton = By.className("radius");
public LoginPage(WebDriver driver){
super(driver);
}
public void enterUsername(String username){
populateTextField(usernameTextField, username);
}
public void enterPassword(String password){
populateTextField(passwordTextField, password);
}
public SecureAreaPage clickLogin(){
clickButton(loginButton);
return new SecureAreaPage(driver);
}
}
package pages;
import org.openqa.selenium.*;
import org.openqa.selenium.WebDriver;
public class SecureAreaPage extends BasePage {
private WebDriver driver;
private By loginBanner = By.id("flash");
public SecureAreaPage(WebDriver driver){
super(driver);
}
public String getBannerText(){
return driver.findElement(loginBanner).getText();
}
}
package base;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import pages.HomePage;
public class BaseTests {
private WebDriver driver;
protected HomePage homePage;
#BeforeClass
public void setUp(){
System.setProperty("webdriver.chrome.driver", "resources/chromedriver.exe");
driver = new ChromeDriver();
driver.get("https://the-internet.herokuapp.com/");
homePage = new HomePage(driver);
}
#AfterClass
public void tearDown(){
driver.quit();
}
}
package base;
import static org.testng.Assert.*;
import org.testng.annotations.Test;
import pages.LoginPage;
import pages.SecureAreaPage;
public class LoginTests extends BaseTests {
#Test
public void loginAsTomSmith(){
LoginPage loginPage = homePage.clickFormAuthentication();
loginPage.enterUsername("tomsmith");
loginPage.enterPassword("SuperSecretPassword!");
SecureAreaPage secureAreaPage = loginPage.clickLogin();
secureAreaPage.getBannerText();
assertTrue(secureAreaPage.getBannerText()
.contains("You logged into a secure area!"),"Incorrect message displayed");
}
}
Your SecureAreaPage contains a field private WebDriver driver; that you never initialize (in the constructor you call super(driver); but you never initialize the field in SecureAreaPage).
In the method getBannerText() you call driver.findElement(loginBanner) which accesses the field from SecureAreaPage.
Since every subclass of BasePage has access to the driver field in BasePage you do not need hat field. Remove it and everything should work.
The principle behind this is that the field driver of the class SecureAreaPage "shadows" the field driver of the class BasePage.
Do you use the correct chromedriver.exe for your installed Chrome version?
Some time ago, this was the solution when I encountered this problem.
Take a look at this page:
https://chromedriver.chromium.org/downloads
If you are using Chrome version 102, please download ChromeDriver
102.0.5005.27
If you are using Chrome version 101, please download ChromeDriver
101.0.4951.41
If you are using Chrome version 100, please download ChromeDriver
100.0.4896.60

Cannot invoke "org.openqa.selenium.WebDriver.get(String)" because "this.driver" is null

I am getting the error below. I am new to Java and thus any help would be appreciated.
Cannot invoke "org.openqa.selenium.WebDriver.get(String)" because "this.driver" is null
Please see the code below:
package steps;
import io.cucumber.java.en.Given;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class hotelBookingFormPage {
public WebDriver driver;
#Before
public void startBrowser() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}
#After
public void closeBrowser() {
driver.close();
driver.quit();
}
#Given("I navigate to the hotel booking form page")
public void iNavigateToTheHotelBookingFormPage() {
driver.get("http://hotel-test.equalexperts.io/");
}
Any help would be appreciated.
import org.junit.After;
import org.junit.Before;
With this you're importing the JUnit hook annotations, not the Cucumber ones. So Cucumber doesn't know you want to run the annotated methods before and after each scenario.
Cucumbers annotations are in a different package:
import io.cucumber.java.en.Before;
import io.cucumber.java.en.After;
The casting of the Webdriver interface with Chromedriver has only been declared in your #Before step (where it is not used), the other steps are unaware. Amend to the following:
public class hotelBookingFormPage {
public WebDriver driver = new ChromeDriver();
#Before
public void startBrowser() {
WebDriverManager.chromedriver().setup();
}
#After
public void closeBrowser() {
driver.close();
driver.quit();
}
#Given("I navigate to the hotel booking form page")
public void iNavigateToTheHotelBookingFormPage() {
driver.get("http://hotel-test.equalexperts.io/");
}

BDD PageObject steps always null?

It's been a very long time I've used Selenium webdriver. I know how I want my project to be structurized, but I'm getting NullPointer Exceptions, "because "driver" is null".
Consider the following code for the STEPS DEFINITION:
package Steps;
import PageObjects.ResultsPage;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import PageObjects.SearchPage;
public class StepsSearch {
WebDriver driver;
SearchPage Search = new SearchPage(driver);
ResultsPage Results = new ResultsPage(driver);
#Given("I go to Google.com")
public void iGoToGoogleDotCom() {
driver.manage().window().maximize();
driver.navigate().to("https://www.google.com");
}
#Then("I see that I'm on the search page")
public void iSeeThatIMOnTheSearchPage() throws InterruptedException {
Search.clickAgreedButton();
Search.seeLogo();
And some more blabla
}
with the PAGEOBJECTS for Search looking like this:
package PageObjects;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import static Helpers.Constants.setWaitingTime.fast;
public class SearchPage {
public WebDriver driver;
public SearchPage(WebDriver driver){
this.driver = driver;
}
//Here are some Elements I use to perform actions
By searchfield = By.xpath("//input[#name='q']");
By logo = By.xpath("//img[#class='lnXdpd']");
By searchButtonInAutoFill = By.xpath("(//input[#name='btnK'])[1]");
By searchButtonBig = By.xpath("(//input[#name='btnK'])[2]");
By AgreedButton = By.xpath("(//div[#class='jyfHyd'])[2]");
By cookieStatement = By.id("CXQnmb");
By header = By.id("gb");
//Following are methods, waits, clicks, and all other actions
public void enterSearchQuery(){
WebDriverWait wait = new WebDriverWait(driver, fast);
wait.until(ExpectedConditions.elementToBeClickable(searchfield));
driver.findElement(searchfield).sendKeys("Monkey");
}
And some other stuff }
With the HOOKS looking like this:
package Steps;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class Hooks {
public WebDriver driver;
#Before
public void browserSetup(){
System.setProperty("webdriver.chrome.driver", "D:\\Chromedriver\\chromedriver.exe");
driver = new ChromeDriver();
}
#After
public void tearDown(){
driver.close();
driver.quit();
}
}
Now, when I change (in the Stepdefintion)
WebDriver driver;
to
Webdriver driver = new ChromeDriver;
it's working "fine", in that two instances of chromedriver get opened (as one is started in the Hooks). When I keep it like this, I get the above mentioned
java.lang.NullPointerException: Cannot invoke "org.openqa.selenium.WebDriver.manage()"
because "this.driver" is null
I'm not getting it. I think I'm doing something wrong with the Webdriver driver calls, but I've hit dead ends for the last couple of hours. I hope you can help me?
Just extend Hooks class to StepsSearch and remove Webdriver declaration in StepsSearch

How to resolve java.lang.NullPointerException, with selenium webdriver along with page object model

I am running these test with Testng using page object model. But I get a NullPointerException.
I have instantiated the webdriver. But I am not sure if it is correct the way I have done it.
FindObjectPage - Element page
package Pages;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.testng.Assert;
public class Flash_Alerts_Elements {
WebDriver driver;
public void Search_alert_Title(){
driver.findElement(By.cssSelector(".d-flex.justify-content-between.my-3 > div > a:nth-of-type(1)")).click();
System.out.println("Pass Alert search");
WebElement element = driver.findElement(By.xpath("//div[#id='app']/div[#class='app-body']/div[#class='container-fluid']/div[#class='mb-3 px-3']//h1[#class='tw-my-auto']"));
if (element.getText().equals("Add Flash Alert"))
System.out.println("Match found -Form heading - Add Flash Alert");
else
System.out.println("Match Not found");
Assert.assertEquals(element.getText(), "Add Flash Alert");
}
public void Add_Alert_Title_Country(String Country_or_region){
driver.findElement(By.cssSelector("div:nth-of-type(2) > .form-control.w-100")).sendKeys(Country_or_region);
}
public void Add_Alert_Title_Event(String Event){
driver.findElement(By.cssSelector("div:nth-of-type(3) > .form-control.w-100")).sendKeys(Event);
}
public void Add_Alert_Title_Date(String Date){
driver.findElement(By.cssSelector("div:nth-of-type(4) > .form-control.w-100")).sendKeys(Date);
}
public void Add_Alert_Title_Specific_Area(String Area){
driver.findElement(By.cssSelector("div:nth-of-type(5) > .form-control.w-100")).sendKeys(Area);
}
public void Select_Severity(){
driver.findElement(By.xpath("//div[#id='severity']//span[.='Informational']"));
}
public Flash_Alerts_Elements(WebDriver driver) {
this.driver = driver;
}
}
Test page
package Tests;
import Pages.Dashboard_Elements;
import Utilities.DriverFactory;
import org.junit.Before;
import org.openqa.selenium.WebDriver;
import Pages.Flash_Alerts_Elements;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class Test_Flash_Alerts {
public WebDriver driver;
#BeforeClass
public static void loginTestWithDashboardTests() throws InterruptedException {
///Initialize diver
WebDriver driver = DriverFactory.open("chrome");///note this can be changed to Firefox or IE to pom.xml different browsers, ensure you remove the comments from the IE data in the utilities package
driver.get("https://wip.devbox.red24.com/login-as/slenkers");
driver.manage().deleteAllCookies();
driver.manage().window().maximize();
}
#Test
public void Capture_Flash_alert_from() {
///Testing Flash form
Flash_Alerts_Elements Create_Flash_alert = new Flash_Alerts_Elements(driver);
Create_Flash_alert.Search_alert_Title();
Create_Flash_alert.Add_Alert_Title_Country("South Africa");
Create_Flash_alert.Add_Alert_Title_Event("Test");
Create_Flash_alert.Add_Alert_Title_Date("15 Sep");
Create_Flash_alert.Add_Alert_Title_Specific_Area("CPT");
}
}
I have added the webdriver and instantiate it in the Flash_alert_element page. Also thought should I add this in the test_flash_alert flow.
How can I resolve this.
Try using:
WebDriver driver = new ChromeDriver();
This is the way I have always instantiated the WebDriver.

"NullPointerException" on trying to run my script using PageFactory

I have attached POM, BaseTest and Test classes. Im getting NullPointerException for the below code on trying to run it as TestNG test by right clicking on the project. Please could suggest?
POM Class:
package 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 Introduction
{
#FindBy(xpath="//a[text()='Hello. Sign In']")
WebElement signInLink;
public Introduction(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
public void signIn()
{
signInLink.click();
}
}
BaseTest Class:
package scripts;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.*;
public class BaseTest
{
public WebDriver driver;
#BeforeSuite
public void preCondition()
{
driver= new FirefoxDriver();
driver.get("https://www.walmart.com/");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
#AfterSuite
public void postCondition()
{
driver.close();
}
}
Test Class:
package scripts;
import org.testng.annotations.Test;
import pom.Introduction;
public class SignIn extends BaseTest
{
#Test
public void validSignIn()
{
Introduction i= new Introduction(driver);
i.signIn();
}
}
Your code has a few issues.
You are instantiating your webdriver in a #BeforeSuite. This causes your webdriver instance to be created ONLY once per <suite> tag. So all other #Test methods will always get a NullPointerException because the #BeforeSuite annotated method doesn't get executed the second time.
You are resorting to using implicit timeouts. Please don't use implicit timeouts. You can read more about the evils of implicit waits in this SO post.
So to get started, I would suggest that change your test code to something like below
BaseTest.java
package scripts;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.*;
public class BaseTest {
private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
#BeforeMethod
public void preCondition() {
driver.set(new FirefoxDriver());
driver.get().get("https://www.walmart.com/");
}
#AfterMethod
public void postCondition() {
driver.get().quit();
}
public final WebDriver driver() {
return driver.get();
}
}
SignIn.java
package scripts;
import org.testng.annotations.Test;
import pom.Introduction;
public class SignIn extends BaseTest {
#Test
public void validSignIn() {
Introduction i = new Introduction(driver());
i.signIn();
}
}
Here what we have done is chose to use #BeforeMethod and #AfterMethod for instantiation and cleanup of webdriver, because these methods are guaranteed to be executed before and after every #Test method. We then went on to using ThreadLocal variants of Webdriver because ThreadLocal ensures that every thread gets its own copy of webdriver, so that you can easily start running your tests in parallel. This is right now not a problem, but very soon you will face this issue as you start building upon your implementation. You can read more about how to resort to parallel executions using TestNG by reading this blog post of mine.

Categories