Selenium newbie here... I am trying to create my first test framework .
Test Website : https://www.phptravels.net/
Test Case :
Open Browser and enter the webpage
Once the page is loaded , click on MyAccount ->Login
I have used xpath in my page object class and the script will run only till launching the webpage. It fails to click on the Login link .
I have tried to include an implicit wait assuming that the time taken for the page to load is longer than usual . Even then the issue persists.
Can you please help me understand what would be the correct xpath that this will work ?
Code :
POM_HomePage.java
package PageObjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class POM_HomePage {
WebDriver driver;
public POM_HomePage(WebDriver driver) {
this.driver=driver;
PageFactory.initElements(driver, this);
}
#FindBy(xpath="//*[#id='li_myaccount']/ul/li[1]/a")
WebElement LinkMyAccount;
public WebElement clickMyAccount() {
return LinkMyAccount;
}
}
HomePage.java
package TestGroupID;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.testng.annotations.Test;
import PageObjects.POM_HomePage;
import Resources.MasterScript;
public class HomePage extends MasterScript{
#Test
public void SignIn() throws IOException {
driver=LoadBrowser();
LoadPropFile();
driver.get(prop.getProperty("test_website"));
POM_HomePage pomHome=new POM_HomePage(driver);
driver.manage().timeouts().implicitlyWait(60,TimeUnit.SECONDS);
if (pomHome.clickMyAccount().isDisplayed()) {
pomHome.clickMyAccount().click();
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
}
}
}
As per your question you have mentioned Once the page is loaded click on MyAccount ->Login. So you should have invoked click() method on two separate WebElements. But your POM_HomePage.java returns only one WebElement as #FindBy(xpath="//*[#id='li_myaccount']/ul/li[1]/a")
Solution
In POM_HomePage.java define two WebElements and two associated functions() as follows :
MyAccount Link
#FindBy(xpath="//div[#class='navbar']//li[#id='li_myaccount']/a")
WebElement LinkMyAccount;
public WebElement clickMyAccount() {
return LinkMyAccount;
}
Login Link
#FindBy(xpath="//div[#class='navbar']//li[#id='li_myaccount']//ul[#class='dropdown-menu']/li/a[contains(.,'Login')]")
WebElement LinkLogin;
public WebElement clickLogin() {
return LinkLogin;
}
In HomePage.java call isDisplayed() and click() for both the WebElements as follows :
#Test
public void SignIn() throws IOException {
driver=LoadBrowser();
LoadPropFile();
driver.get(prop.getProperty("test_website"));
POM_HomePage pomHome=new POM_HomePage(driver);
driver.manage().timeouts().implicitlyWait(60,TimeUnit.SECONDS);
if (pomHome.clickMyAccount().isDisplayed()) {
pomHome.clickMyAccount().click();
}
if (pomHome.clickLogin().isDisplayed()) {
pomHome.clickLogin().click();
}
}
Related
I am using selenium page factory. And while using any of the WebElements, I am receiving null pointer exception.
import java.io.IOException;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.PagesUsingPageFactory.AddNewCustomerUsingPF;
import com.PageswithoutPageFactory.HomePage;
import com.PageswithoutPageFactory.InvokeBrowserSettings;
import com.PageswithoutPageFactory.LoginPage;
public class CreateNewCustomerNegative {
WebDriver driver;
#Test
public void TC_02() throws Exception{
HomePage hompg = new HomePage(driver);
AddNewCustomerUsingPF newcust = new AddNewCustomerUsingPF(driver);
LoginPage loginpage = new LoginPage(driver);
System.setProperty("webdriver.chrome.driver","C:\\Users\\Chinmay\\Downloads\\chromedriver_win32\\chromedriver.exe");
InvokeBrowserSettings invoke = new InvokeBrowserSettings();
driver = invoke.invokeBrowser("chrome", Constant.URL);
loginpage.SignIntoAppWithValidUsrPwd(driver);
//verify home page displayed after valid credentials
hompg.validateHomePageLogo(driver);
hompg.validateManagerButton(driver);
hompg.validatenewCustomerButton(driver);
hompg.clickNewCustomer(driver);
//driver.findElement(By.xpath("//a[contains(text(),'New Customer')]")).click();
//check if add new customer tab is present
Assert.assertTrue(driver.findElement(By.xpath("//p[contains(text(),'Add New Customer')]")).isDisplayed(), "Add new customer option is not visible");
//check if customer name textbox is present
Assert.assertTrue(driver.findElement(By.name("name")).isDisplayed(), "Customer name text box is not presernt");
//name field blank validation
System.out.println("driver=" + driver);
newcust.typeCustomerName("");
}
}
`
Whenever I am using pagefactory for identifying objects, it throws nullpointer exception.
The weird thing is the page factory works for first java file test case, when I use same page factory in another java file, it always fails with nullpointer exception.
I saw some solution on stackoverflow Selenium java.lang.NullPointerException with PageFactory
However, it did not work for me.
I tried initializing page object in my test case and also in my page object script. However, neither of it worked for me.
Here is the code for page factory :
package com.PagesUsingPageFactory;
import org.apache.commons.lang3.RandomStringUtils;
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;
public class AddNewCustomerUsingPF {
public WebDriver driver;
public AddNewCustomerUsingPF(WebDriver driver) {
this.driver=driver;
PageFactory.initElements(driver, this);
}
#FindBy(how=How.XPATH, using="//p[contains(text(),'Add New Customer')]")
public WebElement addNewCustomerLabel;
#FindBy(how=How.XPATH, using="//input[#type='text'][#name='name']")
public WebElement customerNameTxtField;
#FindBy(how=How.XPATH, using="//a[contains(text(),'New Customer')]")
public WebElement newCustomerButton;
public void typeCustomerName(String name) throws Exception {
customerNameTxtField.sendKeys(name);
}
}
Please help me out. I am debigging this issue since more than a week and not able to find the solution.
see here
WebDriver driver;
#Test
public void TC_02() throws Exception{
HomePage hompg = new HomePage(driver);
i hope in HomePage, there is code to initialize driver, that why it is working. then you are passing driver which is not initialized
WebDriver driver;
So, you may need to try to collect driver from Homepage and then pass to other pages also.
As murail said, the driver is not initialized when page factory is intialized. It is passing driver as null.
Change page factory initialization after driver initialization as given below.
public class CreateNewCustomerNegative {
WebDriver driver;
#Test
public void TC_02() throws Exception{
//Initialize the driver first
System.setProperty("webdriver.chrome.driver","C:\\Users\\Chinmay\\Downloads\\chromedriver_win32\\chromedriver.exe");
InvokeBrowserSettings invoke = new InvokeBrowserSettings();
driver = invoke.invokeBrowser("chrome", Constant.URL);
//Initialize page factory
HomePage hompg = new HomePage(driver);
AddNewCustomerUsingPF newcust = new AddNewCustomerUsingPF(driver);
LoginPage loginpage = new LoginPage(driver);
loginpage.SignIntoAppWithValidUsrPwd(driver);
I am a newbie trying to learn automation using the tool Selenium. I am trying to automate this website -
http://newtours.demoaut.com/
where I login and try to access this radio button (one way, round way )for flight finder.
But i am getting the error Unable to locate the element.
Tried the following.
Tried to locate the element using Xpath obtained from firebug.
Used the following Xpath composed from the html code to locate the radio button
//*[#type='radio']//*[#value='oneway']
//*[contains(#type,'radio')]
//*[contains(text(),'oneway']
//input[#type='radio' AND #value='oneway']
Also tried CSS selector to locate the element.
driver.findElement(By.cssSelector("input[type=radio][value=oneway]"))
Tried adding wait times using implicit wait and thread.sleep
The HTML script for the radio button as obtained from firebug is -
input type="radio" checked="" value="roundtrip" name="tripType"
Round Trip
input type="radio" value="oneway" name="tripType"
One Way
Given below is my code -
package gurutrial2;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class gurutrial2
{
public static WebDriver driver;
#BeforeTest
public final void preTest() {
System.setProperty("webdriver.firefox.marionette", "C:/Users/serajendran/Downloads/geckodriver-0.10.0 (1)");
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("marionette", true);
driver = new FirefoxDriver(capabilities);
driver.get("http://newtours.demoaut.com/");
driver.manage().window().maximize();
System.out.println(driver.getTitle());
Assert.assertEquals("Welcome: Mercury Tours", driver.getTitle());
}
#Test
public final void login() {
driver.findElement(By.name("userName")).sendKeys("invalidUN");
driver.findElement(By.name("password")).sendKeys("invalidPW");
driver.findElement(By.name("login")).click();
System.out.println("login in progress");
}
#Test
public final void flightFinder() {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement oneWayRadioButton = wait.until(ExpectedConditions.elementToBeClickable(By.linkText("oneway")));
oneWayRadioButton.click();
System.out.println("Clicked One Way");
}
}
Any help would be deeply appreciated.
//*[#type='radio']//*[#value='oneway'] - you're looking for an element of type radio and value oneway.. this xpath look for an element of type radio that has a child element with value oneway.
//*[contains(#type,'radio')] - you'll get multiple results for this
//*[contains(text(),'oneway'] - the text is not oneway, only the value attribute is oneway, the text contains 'One Way'
//input[#type='radio' AND #value='oneway'] - this should work if you change 'AND' to 'and'
Following solution worked for me on the newtour site -
driver.findElement(By.cssSelector("input[value='oneway']")).click();
Actually the problem is in your test Methods
In TestNG the execution of #Test methods is in alphabetic order by default. So in your code flightFinder() method executing before login() So even you are using right locator to click on radio button, It will show the exception.
Solution:
Maintains your method name in alphabetic order
Use priority under #Test annotation for the methods e.g. - #Test(priority = 1)
Create dependency test e.g. -
#Test()
public final void login()
{
//code
}
#Test(dependsOnMethods={"login"})
public final void flightFinder()
{
//code
}
Update your code as below and try -
#Test
public final void doLogin() {
driver.findElement(By.name("userName")).sendKeys("invalidUN");
driver.findElement(By.name("password")).sendKeys("invalidPW");
driver.findElement(By.name("login")).click();
System.out.println("login in progress");
}
#Test()
public final void flightFinder() {
driver.findElement(By.xpath("//input[#type='radio' and #value='oneway']")).click();
System.out.println("Clicked One Way");
}
I have a question related to improving my Selenium Java code. I am really beginner in Java and Selenium either.
I have written a code which I got an example from the internet and adapted to my reality. The coding works fine as described below:
package test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import page.Login;
public class LoginTest extends BaseTest {
Login login = new Login(driver);
#Test
public void loginWithSuccess() {
sendLoginData("my_user#something.com", "my_password");
login.clickLogin();
assertEquals("View Posted Jobs", login.checkLoginSuccess());
}
private void sendLoginData(String user, String password) {
login.sendUser(user);
login.sendPassword(password);
}
}
The above program is testing and performing a loginWithSucess in the WebSite
package config;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class WebDriverFactory {
public static WebDriver createFirefoxDriver() {
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
return driver;
}
}
In this above example I am instancing a new object WebDriver called driver.
package test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.openqa.selenium.WebDriver;
import config.WebDriverFactory;
public class BaseTest {
protected static WebDriver driver;
private static boolean setUpIsDone = false;
#BeforeClass
public static void setUp() {
if (setUpIsDone) {
return;
}
// Creating first browser for student login
driver = WebDriverFactory.createFirefoxDriver();
driver.get("http://test-tuitiondesk.rhcloud.com/auth");
driver.manage().window().maximize();
setUpIsDone = true;
}
The above example is where I open my WebSite to authenticate
package page;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class Login {
private WebDriver driver;
public Login(WebDriver driver) {
this.driver = driver;
}
public void sendUser(String user) {
driver.findElement(By.xpath("//*[#id='email']")).sendKeys(user);
}
public void sendPassword(String password) {
driver.findElement(By.id("password")).sendKeys(password);
}
public void clickLogin() {
driver.findElement(By.xpath("//*[#id='login-box']/div/div[1]/form/fieldset/div[2]/button")).click();
}
public String checkLoginSuccess() {
return driver.findElement(By.xpath("//a[contains(text(),'View Posted Jobs')]")).getText();
}
}
The above example I have methods which will send a user id and password to the webpage.
So far is everything working fine. The program is performing the following steps:
1 - Open the firefox
2 - Open the webpage
3 - Send the correct user_id, password and click in login button
4 - Check if login was performed with success.
My question now is that I need open a new firefox driver and login with different user_id and this new user_id will interact some actions with the first user_id, so I will need two browsers opened to perform actions with both users in the same time.
I would like to write this implementation the best way than simply write every method again with the second driver. What I thought for the first time was create a new WebDriver called driver2 and create again all methods referring to driver2, but I think I should reuse my methods and classes in a clever way.
Does Anybody have any idea how to implement this second browser in my code?
Thank you
André
You can do this simply by entering this code:
driver2 = WebDriverFactory.createFirefoxDriver();
driver2.get("http://test-tuitiondesk.rhcloud.com/auth");
//call log in function for driver2
//code to interact driver2 with driver1
I am using selenium and testNG framework for my project.
Now what is happening is each class is opening up a browser and then run its methods, eg, if I have five classes, then five browsers will open simultaneously and then run the tests.
I want to Open Browser at the start once and run all the methods and then close it.
public class openSite
{
public static WebDriver driver;
#test
public void openMain()
{
System.setProperty("webdriver.chrome.driver","E:/drive/chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("http://vtu.ac.in/");
}
#test
//Clicking on the first link on the page
public void aboutVTU()
{
driver.findElement(By.id("menu-item-323")).click();
}
#Test
//clicking on the 2nd link in the page
public void Institutes()
{
driver.findElement(By.id("menu-item-325")).click();
}
Now What I want is the testNG should open browser once and open vtu.ac.in once and then execute the methods aboutVTU and Institutes and give me the result
You already declared the type for driver in your field declarations. Redeclaring it in openMain() is your problem. It should look like this.
import static org.testng.Assert.assertNotNull;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class OpenSite {
private WebDriver driver;
#BeforeClass(alwaysRun=true)
public void openMain()
{
System.setProperty("webdriver.chrome.driver","/usr/local/bin/chromedriver");
driver = new ChromeDriver();
driver.get("http://vtu.ac.in/");
}
#Test
//Clicking on the first link on the page
public void aboutVTU()
{
assertNotNull(driver);
driver.findElement(By.id("menu-item-323")).click();
}
#Test(dependsOnMethods="aboutVTU")
//clicking on the 2nd link in the page
public void Institutes()
{
assertNotNull(driver);
driver.findElement(By.id("menu-item-325")).click();
}
}
Basically every time I run my java code from eclipse, webdriver launches a new ie browser and executes my tests successfully for the most part. However, I have a lot of tests to run, and it's a pain that webdriver starts up a new browser session every time. I need a way to re-use a previously opened browser; so webdriver would open ie the first time, then the second time, i run my eclipse program, I want it to simply pick up the previous browser instance and continue to run my tests on that same instance. That way, I am NOT starting up a new browser session every time I run my program.
Say you have 100 tests to run in eclipse, you hit that run button and they all run, then at about the 87th test you get an error. You then go back to eclipse, fix that error, but then you have to re-run all 100 test again from scratch.
It would be nice to fix the error on that 87th test and then resume the execution from that 87th test as opposed to re-executing all tests from scratch, i.e from test 0 all the way to 100.
Hopefully, I am clear enough to get some help from you guys, thanks btw.
Here's my attempt below at trying to maintain and re-use a webdriver internet explorer browser instance:
public class demo extends RemoteWebDriver {
public static WebDriver driver;
public Selenium selenium;
public WebDriverWait wait;
public String propertyFile;
String getSessionId;
public demo() { // constructor
DesiredCapabilities ieCapabilities = DesiredCapabilities
.internetExplorer();
ieCapabilities
.setCapability(
InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,
true);
driver = new InternetExplorerDriver(ieCapabilities);
this.saveSessionIdToSomeStorage(getSessionId);
this.startSession(ieCapabilities);
driver.manage().window().maximize();
}
#Override
protected void startSession(Capabilities desiredCapabilities) {
String sid = getPreviousSessionIdFromSomeStorage();
if (sid != null) {
setSessionId(sid);
try {
getCurrentUrl();
} catch (WebDriverException e) {
// session is not valid
sid = null;
}
}
if (sid == null) {
super.startSession(desiredCapabilities);
saveSessionIdToSomeStorage(getSessionId().toString());
}
}
private void saveSessionIdToSomeStorage(String session) {
session=((RemoteWebDriver) driver).getSessionId().toString();
}
private String getPreviousSessionIdFromSomeStorage() {
return getSessionId;
}
}
My hope here was that by overriding the startSession() method from remoteWebdriver, it would somehow check that I already had an instance of webdriver browser opened in i.e and it would instead use that instance as opposed to re-creating a new instance everytime I hit that "run" button in eclipse.
I can also see that because I am creating a "new driver instance" from my constructor, since constructor always execute first, it creates that new driver instance automatically, so I might need to alter that somehow, but don't know how.
I am a newbie on both stackoverflow and with selenium webdriver and hope someone here can help.
Thanks!
To answer your question:
No. You can't use a browser that is currently running on your computer. You can use the same browser for the different tests, however, as long as it is on the same execution.
However, it sounds like your real problem is running 100 tests over and over again. I would recommend using a testing framework (like TestNG or JUnit). With these, you can specify which tests you want to run (TestNG will generate an XML file of all of the tests that fail, so when you run it, it will only execute the failed tests).
Actually you can re-use the same session again..
In node client you can use following code to attach to existing selenium session
var browser = wd.remote('http://localhost:4444/wd/hub');
browser.attach('df606fdd-f4b7-4651-aaba-fe37a39c86e3', function(err, capabilities) {
// The 'capabilities' object as returned by sessionCapabilities
if (err) { /* that session doesn't exist */ }
else {
browser.elementByCss("button.groovy-button", function(err, el) {
...
});
}
});
...
browser.detach();
To get selenium session id,
driver.getSessionId();
Note:
This is available in Node Client only..
To do the same thing in JAVA or C#, you have to override execute method of selenium to capture the sessionId and save it in local file and read it again to attach with existing selenium session
I have tried the below steps to use the same browser instance and it worked for me:
If you are having generic or Class 1 in different package the below code snippet will work -
package zgenerics;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.BeforeTest;
import org.openqa.selenium.WebDriver;
// Class 1 :
public class Generics {
public Generics(){}
protected WebDriver driver;
#BeforeTest
public void maxmen() throws InterruptedException, IOException{
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
String appURL= "url";
driver.get(appURL);
String expectedTitle = "Title";
String actualTitle= driver.getTitle();
if(actualTitle.equals(expectedTitle)){
System.out.println("Verification passed");
}
else {
System.out.println("Verification failed");
} }
// Class 2 :
package automationScripts;
import org.openqa.selenium.By;
import org.testng.annotations.*;
import zgenerics.Generics;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
public class Login extends Generics {
#Test
public void Login() throws InterruptedException, Exception {
WebDriverWait wait = new WebDriverWait(driver,25);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("")));
driver.findElement(By.cssSelector("")).sendKeys("");
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("")));
driver.findElement(By.xpath("")).sendKeys("");
}
}
If your Generics class is in the same package you just need to make below change in your code:
public class Generics {
public Generics(){}
WebDriver driver; }
Just remove the protected word from Webdriver code line. Rest code of class 1 remain as it is.
Regards,
Mohit Baluja
I have tried it by extension of classes(Java Inheritance) and creating an xml file. I hope below examples will help:
Class 1 :
package zgenerics;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.BeforeTest;
import org.openqa.selenium.WebDriver;
public class SetUp {
public Generics(){}
protected WebDriver driver;
#BeforeTest
public void maxmen() throws InterruptedException, IOException{
driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
String appURL= "URL";
driver.get(appURL);
String expectedTitle = "Title";
String actualTitle= driver.getTitle();
if(actualTitle.equals(expectedTitle)){
System.out.println("Verification passed");
}
else {
System.out.println("Verification failed");
} }
Class 2 :
package automationScripts;
import org.openqa.selenium.By;
import org.testng.annotations.Test;
import zgenerics.SetUp
public class Conditions extends SetUp {
#Test
public void visible() throws InterruptedException{
Thread.sleep(5000);
boolean signINbutton=driver.findElement(By.xpath("xpath")).isEnabled();
System.out.println(signINbutton);
boolean SIGNTEXT=driver.findElement(By.xpath("xpath")).isDisplayed();
System.out.println(SIGNTEXT);
if (signINbutton==true && SIGNTEXT==true){
System.out.println("Text and button is present");
}
else{
System.out.println("Nothing is visible");
}
}
}
Class 3:
package automationScripts;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.testng.annotations.Test;
public class Footer extends Conditions {
#Test
public void footerNew () throws InterruptedException{
WebElement aboutUs = driver.findElement(By.cssSelector("CssSelector"));
aboutUs.click();
WebElement cancel = driver.findElement(By.xpath("xpath"));
cancel.click();
Thread.sleep(1000);
WebElement TermsNCond = driver.findElement(By.xpath("xpath"));
TermsNCond.click();
}
}
Now Create an xml file with below code for example and run the testng.xml as testng suite:
copy and paste below code and edit it accordingly.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestSuite" parallel="classes" thread-count="3">
<test name="PackTest">
<classes>
<class name="automationScripts.Footer"/>
</classes>
This will run above three classes. That means one browser and different tests.
We can set the execution sequence by setting the class names in alphabetical order as i have done in above classes.