Manage objects in class for PO mechanism - java

I am practicing selenium automation using JAVA on OrangeHRM website.
Scenario:
Login
Navigate Admin link
Add user to search
...
I created 3 pages viz.
LoginPage
HomePage
AdminPage
In each page, identified elements & passed appropriate arguments:
For e.g. in login page:
#FindBy(id="txtUsername")
WebElement txt_userName;
#FindBy(id="txtPassword")
WebElement txt_password;
#FindBy(id="btnLogin")
WebElement btn_login;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void enterUserName (String userid) {
txt_userName.sendKeys(userid);
}
public void enterUserPassword (String userpassword) {
txt_password.sendKeys(userpassword);
}
public void clickLoginbutton () {
btn_login.click();
}
Now in main class file, when I try to replay above scenario:
Each time I have to create object of pages to utilize methods:
package xyz;
imports ****;
public class SearchUser {
public WebDriver driver;
public String baseURL;
public void browser_open(){
driver = new ChromeDriver();
baseURL = "https://opensource-demo.orangehrmlive.com";
driver.get(baseURL);
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
public void login_user(String userid, String userpassword){
lgnp = new LoginPage(driver);
lgnp.enterUserName(userid);
lgnp.enterUserPassword(userpassword);
lgnp.clickLoginbutton();
}
public void navigate_admin(){
hp = new HomePage(driver);
Actions a = new Actions(driver);
a.moveToElement(hp.lnk_admin()).click().build().perform();
}
public void click_search(){
ap = new AdminPage(driver);
ap.btn_search();
}
public void add_user(String usersearch){
ap = new AdminPage(driver);
ap.txt_emplUserName(usersearch);
}
public void logout(){
hp = new HomePage(driver);
hp.lnk_welcome();
hp.lnk_logout();
driver.close();
driver.quit();
}
}
Do we have any way to avoid creating objects each time in each class?
I tried to implement Page Object Manager using link (https://www.toolsqa.com/selenium-cucumber-framework/page-object-manager/), but its not working.
Also tried to define objects at global level, but script retruns NLP.
Do we have any ways to manage objects or references?
TIA.

Related

Multiple instances of browser opening up when running test through webdriver manager

I am new to Selenium, so basically whenever I ran my test, it would open up the URL which I have mentioned in my test. In my same Test I have also mentioned to fill the username and Password.
But somehow once the browser gets launched and redirect to the URL, it opens up another instance of blank browser failing my script that element not found.
Please help me here.
///////////////////////////////////////////////////////////////////////////
public class TruefillTest extends BaseClass {
public Truefill truefill()
{
WebDriver driver=InitializeDriver();
return new Truefill(driver);
}
#Test
public void userLoginIntoTheSystem()
{
truefill().dashBoard().Url();
truefill().dashBoard().EnterUsername("bjdgfe#swcwr.com");
truefill().dashBoard().EnterPassword("Test1234");
}
///////////////////////////////////////////////
public class Truefill {
private WebDriver driver;
public Truefill(WebDriver driver) {
this.driver=driver;
}
public DashBoardPage dashBoard()
{
return new DashBoardPage(driver);
}
////////////////////////////////////////////////////////////
public class DashBoardPage {
private final WebDriver driver;
By Username= By.xpath("//input[#name='name']");
By Password= By.xpath("//input[contains(#id,'exampleInputPassword1')]");
public DashBoardPage(WebDriver driver) {
this.driver=driver;
}
public void Url()
{
driver.get("https://rahulshettyacademy.com/angularpractice/");
}
public void EnterUsername(String username)
{
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.findElement(Username).sendKeys(username);
}
public void EnterPassword(String password)
{
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.findElement(Password).sendKeys(password);
}
////////////////////////////////////////////////////////////
public class BaseClass {
WebDriver driver;
public WebDriver InitializeDriver()
{
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
return driver;
}
}
Each call to the truefill() method initializes a new instance of WebDriver. Since your test is calling it multiple times, it will start a new browser instance on each line. Instead, store the DashboardPage in a local variable:
#Test
public void userLoginIntoTheSystem() {
DashBoardPage dashBoardPage = truefill().dashBoard();
dashBoardPage.Url();
dashBoardPage.EnterUsername("bjdgfe#swcwr.com");
dashBoardPage.EnterPassword("Test1234");
}
You might also want to use a setup method to initialize the Truefill instance, rather than creating it on demand:
private Truefill truefill;
#BeforeEach
public void initializeTruefill() {
WebDriver driver = InitializeDriver();
truefill = new Truefill(driver);
}
#Test
public void userLoginIntoTheSystem() {
DashBoardPage dashBoardPage = truefill.dashBoard();
dashBoardPage.Url();
dashBoardPage.EnterUsername("bjdgfe#swcwr.com");
dashBoardPage.EnterPassword("Test1234");
}
This assumes JUnit 5. If you're using JUnit 4, the annotation is #Before instead of #BeforeEach.

NoSuchElementException using WebDriverWait

I would really like to understand why when approaching locating an element the exact same way as previously failing.
NoSuchElementException : Caused by: org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//span[contains(text(),'Add')]"}
I have also tried to use something like the following but it also failed, so in order for me write a good automation code i need to get my knowledge straight with WebDriverWait, so i would appreciate somebody with knowledge to spend some time on this inquiry.
It does locates if i have xpath like this :
//body/div[#id='root']/div[1]/div[1]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/div[2]/div[1]/div[2]/div[1]
public void clickOnAddVehicleButton() {
wait.until(ExpectedConditions.visibilityOf(addVehicleButton));
vehicles.addVehicleButton.click();
}
I am not new into Java but i am new into automation hence some areas of knowledge is missing, i ha
Base class:
public class BasePage {
protected final WebDriver driver;
protected final WebDriverWait wait;
public BasePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver,5);
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 10), this);
}
}
The component where that button should be present :
public class Vehicles extends BasePage {
private static Vehicles vehicles;
private Vehicles(WebDriver driver) {
super(driver);
}
#FindBy(xpath = "//span[text(),'Add']")
public WebElement addVehicleButton;
public static Vehicles vehiclesInstance(WebDriver driver) {
return vehicles == null ? vehicles = new Vehicles(driver) : vehicles;
}
public void clickOnAddVehicleButton() {
vehicles.addVehicleButton.click();
}
Function in the service class:
public void addVehicle(String vehicleName, String numberPlate) {
myAccountService.myAccountPage()
.clickOnVehiclesTab();
vehicles.fillInVehicleName(vehicleName)
.fillInVehicleNumberPlate(numberPlate)
.clickOnAddVehicleButton();
}
WebDriverSettings for test :
public class WebDriverSettings {
protected WebDriver driver;
#Before
public void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
loginToDevEnvironment();
}
And finally my test class where i am calling the service method:
public class VehicleServiceTest extends WebDriverSettings {
private VehiclesService vehiclesService;
#Before
public void setUp(){
super.setUp();
CookieService.cookieServiceInstance(driver).acceptCookies();
HomePageService.homePageServiceInstance(driver).clickOnMyAccountTab();
LoginService.loginServiceInstance(driver).login(loginCorrectData());
HomePageService.homePageServiceInstance(driver).clickOnMyAccount();
vehiclesService = VehiclesService.vehiclesServiceInstance(driver);
}
#Test
public void shouldAddVehicle(){
vehiclesService.addVehicle("test-vehicle","test-test");
Assert.assertEquals(1,vehiclesService.getVehicles().listOfAddedVehicles().size());
}

Run tests in different browser sessions but always get 'NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?'

My test project has #BeforeClass and #AfterClass in the BaseTest.class:
public class BaseTest {
#BeforeClass(groups = {"first"})
public void beforeTest() {
getDriver().get("URL");
}
#AfterClass(alwaysRun = true)
public void afterTest() {
getDriver().close();
removeDriver();
}
}
and its FirstTest.Class:
public class SmokeTest extends BaseTest {
private PageOne pageOne = PageFactory.initElements(getDriver(), PageOne.class);
#Test(testName = "test1", groups = { "first" })
public void firstTest() {
pageOne.goSomething();
}
#Test(testName = "test2", groups = { "first" })
public void secondTest() {
pageOne.goSomethingElse();
}
}
WebDriver singleton:
public class WebDriverSingleton {
private static WebDriver driver;
public static WebDriver getDriver() {
if (driver == null) {
driver = new ChromeDriver();
}
return driver;
}
public static void removeDriver() {
driver.quit();
driver = null;
}
}
And it works just fine. Until I have added new cases which I'd like to start in a new browser instances.
What I've added:
public class BaseModuleTest {
#BeforeClass(groups = {"second"})
public void beforeClass() {
getDriver().get("another URL");
}
}
public class ModuleTest extends BaseModuleTest {
private PageTwo pageTwo = PageFactory.initElements(getDriver(), PageTwo.class);
private PageOne pageOne = PageFactory.initElements(getDriver(), PageOne.class);
#Test(testName = "test1", groups = {"second"})
public void testUp() {
pageTwo.goToPageOne();
pageOne.doSomething(); // getting fail here
}
}
When I start test using testgnconfiguration.xml
'first' group passes
browser window closes
new instance of WebDriver opens new browser window
goes to URL
when starts interacting with the first WebElement on the page that was instantiated during 'first' group run returns an error:
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
So far as I'm using the Page Object Model and I'm using in the 'second' group the same Pages which has been initialised in the 'first' group, I guess they somehow 'remember' the first Session Id which became 'null'.
Although I reinitialise them in ModuleTest.test1()...
Anyway if my suggestions are correct, how to pass a new sessionId to instantiated page objects? Or what is proper way to reinitialise them?
Looks like your problem is:
#BeforeClass(groups = {"first"})
and
#AfterClass(alwaysRun = true)
You are always destroying the driver object after finishing with a class, but you are only creating a driver object for a class in a specific group. I would suggest tweaking your #BeforeClass to:
#BeforeClass(alwaysRun = true)
or
#BeforeClass(groups = {"first, "second"})

Null pointer exception in selenium cucumber JUnit Framework

Can someone tell the issue in my code for null pointer exception?
Error Message in console
=>test.pages.HomePage#31e75d13<=
[31mFailed scenarios:[0m
[31mE2E_Test.feature:3 [0m# Scenario: Test scenario
1 Scenarios ([31m1 failed[0m)
10 Steps ([31m1 failed[0m, [36m8 skipped[0m, [32m1 passed[0m)
0m12.461s
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.$Proxy17.sendKeys(Unknown Source)
at test.pages.HomePage.enterSearchText(HomePage.java:31)
at stepDefinitions.Steps.he_search_for(Steps.java:49)
at ✽.When he search for "test"(E2E_Test.feature:5)
Although I am getting the driver object and its not coming as Null as well but still getting a null pointer exception.
I am trying to run the selenium webdriver code to automate some test case. Here i am trying to open google.com and wants to enter some text in search box but after opening the google.com, when the execution reaches searchtextbox.sendkeys("test"), it gives null pointer exception. I tried debugging it to see if the homepage class object is coming as null or not but its showing the value and not null.
This is the test base class that i am using to initiate the google site and maximize the code
public class TestBase {
public static WebDriver driver;
public static Properties prop;
public static EventFiringWebDriver e_driver;
public static WebEventListener eventListener;
public TestBase() {
try {
prop = new Properties();
FileInputStream ip = new FileInputStream(System.getProperty("user.dir") + "/src/main/java/test" +
"/config/config.properties");
prop.load(ip);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// This method is used to initiatize the site url
public static void initialization(String url) {
String browserName = prop.getProperty("browser");
if (browserName.equals("chrome")) {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\test\\Downloads\\driver\\chromedriver.exe");
driver = new ChromeDriver();
}
e_driver = new EventFiringWebDriver(driver);
// Now create object of EventListerHandler to register it with EventFiringWebDriver
eventListener = new WebEventListener();
e_driver.register(eventListener);
driver = e_driver;
driver.manage().window().maximize();
driver.manage().deleteAllCookies();
driver.manage().timeouts().pageLoadTimeout(TestUtil.PAGE_LOAD_TIMEOUT, TimeUnit.SECONDS);
driver.manage().timeouts().implicitlyWait(TestUtil.IMPLICIT_WAIT, TimeUnit.SECONDS);
if (url == "google") {
driver.get(prop.getProperty("url"));
}
}
}
// Steps Definition file (Steps.java): This is the step defintion file // there is a function he_search_for called where the exception occurs
public class Steps extends TestBase {
WebDriver driver;
TestUtil testUtil;
HomePage homePage;
#Given("^user is on google home page$")
public void user_is_on_google_home_page() throws Throwable {
initialization("google");
testUtil = new TestUtil();
homePage = new HomePage(driver);
}
#When("^he search for \"([^\"]*)\"$")
public void he_search_for(String arg1) throws InterruptedException {
System.out.print("=>" + homePage + "<=");
homePage.enterSearchText();
}
}
// HomePage Class is used to define all the page elements here in this class, i used enterSearchText function to enter the text in a search box.
public class HomePage extends TestBase {
#FindBy(name = "q")
WebElement searchTextBox;
WebDriver driver;
// Initializing the Page Objects:
public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void enterSearchText() {
searchTextBox.sendKeys("Test");
}
}
Problem lies within your code design pattern between Classes Steps & TestBase. Please note
First, Class Steps is extending TestBase which already has WebDriver variable declared & initialized in it. So you do not need to again define WebDriver instance with in Steps. So please remove "WebDriver driver;" from below peace of code.
public class Steps extends TestBase {
WebDriver driver;
TestUtil testUtil;
Second, Please do not declare WebDriver as static variable. Kindly declare it as Non-static as Keeping static may create problem during parallel execution as well.
public class TestBase {
public WebDriver driver;
Making WebDriver instance as non-static and having it as Thread safe
TestBase.java
public class TestBase {
public WebDriver driver;
public static Properties prop;
// This method is used to initiatize the site url
public synchronized void initialization(String url) {
String browserName = prop.getProperty("browser");
if (browserName.equals("chrome")) {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\test\\Downloads\\driver\\chromedriver.exe");
driver = new ChromeDriver();
DriverManager.setWebDriver(driver);
}
}
}
DriverManager.java
import org.openqa.selenium.WebDriver;
public class DriverManager {
public static ThreadLocal<WebDriver> dr = new ThreadLocal<WebDriver>();
public static WebDriver getDriver() {
return dr.get();
}
public static void setWebDriver(WebDriver driver) {
dr.set(driver);
}
}
The problem is here
public class Steps extends TestBase {
WebDriver driver;
TestUtil testUtil;
HomePage homePage;
#Given("^user is on google home page$")
public void user_is_on_google_home_page() throws Throwable {
initialization("google");
testUtil = new TestUtil();
homePage = new HomePage(driver);
}
#When("^he search for \"([^\"]*)\"$")
public void he_search_for(String arg1) throws InterruptedException {
System.out.print("=>" + homePage + "<=");
homePage.enterSearchText();
}
}
The WebDriver driver is null. You initialized WebDriver in initialization("google") method but you don't assign the value of created WebDriver to your driver
Additional line of code might help you.
#Given("^user is on google home page$")
public void user_is_on_google_home_page() throws Throwable {
initialization("google");
this.driver = TestBase.driver; //asign initialized WebDriver to this instance variable
testUtil = new TestUtil();
homePage = new HomePage(driver);
}
You can also remove the local WebDriver driver variable. Since TestBase contains static WebDriver, you can just use it directly since you use inheritance.
However, I highly suggest reading about WebDriverFactory or any similar term, like WebDriverManager. Anything to handle WebDriver instantiation without creating a static WebDriver. It will cause a lot of issues in the future with parallel execution.

Using Common Selenium WebDriver instance

I want use a common WebDriver instance across all my TestNG tests by extending my test class to use a base class as shown below but it doesn't seem to work :
public class Browser {
private static WebDriver driver = new FirefoxDriver();
public static WebDriver getDriver()
{
return driver;
}
public static void open(String url)
{
driver.get(url);
}
public static void close()
{
driver.close();
}
}
I want to use the WebDriver in my test class as shown below, but I get the error message :
The method getDriver() is undefined for the type GoogleTest:
public class GoogleTest extends Browser
{
#Test
public void GoogleSearch() {
WebElement query = getDriver().findElement(By.name("q"));
// Enter something to search for
query.sendKeys("Selenium");
// Now submit the form
query.submit();
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 5 seconds
WebDriverWait wait = new WebDriverWait(getDriver(), 30);
// wait.Until((d) => { return d.Title.StartsWith("selenium"); });
//Check that the Title is what we are expecting
assertEquals("selenium - Google Search", getDriver().getTitle().toString());
}
}
The problem is that your getDriver method is static.
Solution #1: Make method non-static (this will either need to make the driver variable non-static as well, or use return Browser.getDriver(); )
public WebDriver getDriver() {
return driver;
}
Or, call the getDriver method by using Browser.getDriver
WebElement query = Browser.getDriver().findElement(By.name("q"));
You need to start your driver, one of many solution is to try #Before to add, Junit will autorun it for you.
public class Browser {
private WebDriver driver;
#Before
public void runDriver()
{
driver = new FirefoxDriver();
}
public WebDriver getDriver()
{
return driver;
}
public void open(String url)
{
driver.get(url);
}
public void close()
{
driver.close();
}
}

Categories