I am just completed a test automation using with selenium. And I want to know about how to keep the test data separately in json format.
Can you please tell me how to write test data in the page object pattern.
Here I am using multiple packages. One is for locators identification, another is for page factory for initializing elements, and the other is package utilities for common values like get URL. I also have a test package for testing a login module.
What I don't know is where should I put the test data class ?
I want to keep the test data separately. Not scattering all over the script. Keep the test data in Json. And read it from there where ever it is necessary.
Still I'm getting confusing about where Should I put the json format
And also I am selenium code doesn't follow a framework. I did n't follow any frameworks. Anybody please tell me about frameworks ?
Frameworks are : Data driven, keyword driven, hybrid and modular. which framework is most people using , because and why ?
As a tester should have knowledge about all frameworks ?
I am following page object design pattern:
Page object :
package pageobjects;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
public class HomePage
{
#FindBy(how= How.NAME, using = "username")
WebElement username;
#FindBy(how=How.NAME, using = "password")
WebElement password;
#FindBy(how=How.XPATH, using="//*[#id=\'login-container\']/form/div[3]/div/p/input[1]" )
WebElement button;
//enter username
public void userLogin(String user, String pass)
{
username.sendKeys(user);
password.sendKeys(pass);
button.click();
}
}
Steps:
package steps;
import org.openqa.selenium.support.PageFactory;
import pageobjects.ClientPage;
import pageobjects.HomePage;
import util.DriverManager;
public class LoginSteps
{
public HomePage Login(String nam, String pas) {
HomePage homePageObj = PageFactory.initElements(DriverManager.driver, HomePage.class);
homePageObj.userLogin(nam,pas);
return homePageObj;
}
}
Util:
package util;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class DriverManager
{
public static WebDriver driver;
String baseUrl="//http:qms";
public DriverManager()
{
System.setProperty("webdriver.chrome.driver","/home/naveen/chromedriver");
driver=new ChromeDriver();
driver.get(baseUrl);
driver.manage().window().maximize();
}
}
Login Test :
package login;
import org.testng.Assert;
import org.testng.annotations.*;
import pageobjects.HomePage;
import steps.LoginSteps;
import util.DriverManager;
import static util.DriverManager.driver;
public class loginTest
{
#BeforeSuite(groups = {"regression"})
public void initDriver(){
DriverManager manager = new DriverManager();
}
#DataProvider(name= "login")
public static java.lang.Object[][] loginData(){
return new Object[][]{{"geoso","1"},{"ges","2"},{"geo","1"}};
}
#Test(dataProvider = "login")
public void verifyValidLoginWithDataProvider(String userName,String password)
{
LoginSteps loginSteps= new LoginSteps();
HomePage ex=loginSteps.Login(userName,password);
Assert.assertTrue(driver.getPageSource().contains("Hello Naveen"));
}
}
Here is the scenario of json format Please tell me how to write the code?
first open URL and go to login page then .
login
{
"username" :"ertte"
password: "34"
}
"Admin"
"users"
"add users"
"username" :"tsrt"
"password":"sdfgsdrfg"
name:"gfgf"
nickname:"fgsdgf"
role:"client"
email:"sdfsd#gmail.com"
submit
}}
There are so many different frameworks you can use now in combination with selenium.
I use Cucumber [BDD].
You can write your scenarios as regular sentences and Gherkin will transfer them in a methods. Sentences can have parameters or list of a parameters.
You have execution control for your test at two, let call it top levels. You can choose which feature file you want to ran.
Second execution filter can be build by using tags. For e.g. #smoketest #regression and so on.
You can use also TestNG. You have .xml file where you can make your setup. Execute particular clases, methods, prioretize test, make test dependencies, skip tests, and have full control over execution.
There are lot more I assume but these two are the most popular.
Related
I have a button on my Webpage which I want to click once the required piece of information is entered. I am currently using By to establish all the elements of the page but want to use WebElements for this button and then use Actions to click it later.
How should I do that in my Page Object class.
I tried with below approach :
WebElement addressinput = driver.findElement(By.xpath("//input[#id='pac-input']"));
By addressinput = By.xpath("//input[#id='pac-input']");//this works fine
But on running the Test class as TestNG it shows null pointer exception on WebElement line. Tried to do it with By as well but the button just won't recieve the click. It works pefectly fine with WebElements and action which I have tried before without using POM below is the reference code for that :
WebElement button = driver.findElement(By.xpath("//button[#id='btn_gtservice']"));
Actions action = new Actions(driver);
action.moveToElement((WebElement) CheckAvailability).click().perform();
driver.switchTo().defaultContent();
You've got
action.moveToElement((WebElement)CheckAvailability)
That should be
action.moveToElement((button)CheckAvailability)
As it is, you'll be getting a null pointer as you have no variable named WebElement defined
When using PageFactory in PageObjectModel if you expect the element to be loaded after some information is entered, through some JavaScript and it might not be immediately present on the page already you can use the Actions once the element is returned through WebDriverWait support with a normal locator factory as follows:
Code Block:
package com.pol.zoho.PageObjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.interactions.Actions;
public class ZohoLoginPage {
WebDriver driver;
public ZohoLoginPage(WebDriver driver)
{
PageFactory.initElements(driver, this);
}
#FindBy(xpath="//button[#id='btn_gtservice']")
public WebElement myButton;
public void doLogin(String username,String userpassword)
{
WebElement button = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(ZohoLoginPage.getWebElement()));
new Actions(driver).moveToElement(button).click().perform();
}
public WebElement getWebElement()
{
return myButton;
}
}
You can find a detailed discussion in How to use explicit waits with PageFactory fields and the PageObject pattern
I Tried to execute the same test with different data but I am getting the following error when I tried to run the test
You can implement missing steps with the snippets below:
#When("^Enter the ADMIN and password(\\d+)$")
public void enter_the_ADMIN_and_password(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
Below is my Feature file
Scenario Outline: Login
Given Open chrome and login
When Enter the <Username> and <Password>
Then Click on Login
Examples:
|Username |Password |
|ADMIN |password123|
Below is the #when annotation part in Steps file
#When("^Enter the \"(.*)\" and \"(.*)\"$")
public void enter_the_Username_and_Password(String username,String Password) throws Throwable
{
System.out.println("This step enter the Username and Password on the login page."+username +Password);
loginObj.Login(driver);
}
It may be occurring due to cucumbers packages is misconfigured. Check the GLUE options
#RunWith(Cucumber.class)
#CucumberOptions(
features = { "src/test/resources/features/CucumberTests.feature" },
tags = { "#integration_test"},
glue = { "br.com.cucumber.integration.stepDefinition" },
format = { "pretty", "html:target/reports/cucumber/html", "json:target/cucumber.json", "usage:target/usage.jsonx", "junit:target/junit.xml" })
#ContextConfiguration(classes= AppConfiguration.class)
public class CumcumberTest extends BaseTestCase {
}
I think what you are describing as an "error" is in fact cucumber telling you that is not able to find the matching definition for the step "When Enter the Username and Password" and has auto-generated the example definition below based on the scenario outline data:
#When("^Enter the ADMIN and password(\\d+)$")
public void enter_the_ADMIN_and_password(int arg1) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
The problem is that your step definition is using quotes on the parameters but your actual step has no quotes, hence cucumber is not able to match them. You either need to change your step in the feature file to include quotes:
When Enter the "<Username>" and "<Password>"
Or you need to change the step definition to not include quotes:
#When("^Enter the (.*) and (.*)$")
public void enter_the_Username_and_Password(String username,String Password) throws Throwable
{
System.out.println("This step enter the Username and Password on the login page."+username +Password);
loginObj.Login(driver);
}
I got the same error. For me the problem was that I created step definition in the package for back end tests instead of front end ones. If the step definition classes have same or similar names, it is possible to make a mistake. This would happen during chosing the wrong package while creating step definition from the feature file in Intellij.
I was getting this issue and discovered the reason was I accidentally gave the name of the class and not the package for the glue code:
The wrong argument value for my gluecode was my class as: gluecode="StepDefinition", when it should have been my package: gluecode="stepDefs"
My TestRunner.java looks as follows:
package testRunner;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "src/test/java/features",
glue = "stepDefs")
public class TestRunner {
}
I got the same error. In my case I was forgetting the .step. part in my file name.
So I've solved by modifying my file name from:
mystepfile.ts
to:
mystepfile.step.ts
I am using "driver.findElement" multiple times. So can it be saved in a method and called multiple times?
driver.findElement(By.xpath("//tbody[#id='detailsstockid']/tr/td[12]/a/input")).click();
driver.findElement(By.id("supplier_name")).click();
driver.findElement(By.xpath("//select[#id='supplier_name']/option[7]")).click();
driver.findElement(By.id("catagory_name")).click();
driver.findElement(By.id("productname")).sendKeys("AutoProductNew");
driver.findElement(By.id("productcode")).sendKeys("ap02");
You just need a wrapper like this
public static WebElement findElement(By locator){
WebElement anElement = driver.findElement(locator);
return anElement;
}
findElement(By.id("id")).click();
Basically you can call whatever method available to the object
I think what you are trying to do is to simplify your code... maybe make it more human readable. This is a noble goal but I would suggest that you take a different approach. Without more info, I don't know what your typical script is like. From the example code you provided, I would assume that you are going to a few pages, clicking on things, filling in textboxes, etc. I would suggest that you look into the page object model.
There are a LOT of references on the web on this topic, here's a good one to start with.
http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
The basic concept is create one Class file per page. [Page doesn't always literally mean an entire page. For example, I would create a separate page object for each popup dialog.] What this allows you to do is to consolidate all the code specific to that page into a single location. If you know what an API is and understand it, you will basically create an API for each page/dialog you touch. If done properly, it will greatly simplify and organize your code and will make creating new scripts drastically easier and they will be much easier to read. The benefits are numerous... one big one is code maintenance is made SO much easier. Imagine you have 100 scripts that all start by logging into the site. Let's assume the design of the login page changes... without the page object model, you will have to update all 100 scripts individually. If you are using the page object model, you open the LoginPage.java class, make the change to the Login() method, and you just fixed all 100 scripts.
You may be asking... how does this answer my question? What it does is turns
driver.findElement(By.id("supplier_name")).click();
into
somePage.clickSupplierName();
in your actual script. I think this is more along the lines of what you are asking without answering your specific question. The .findElement code still exists, but is "hidden away" in the page object.
A simple example. I wrote a script, with supporting page objects, to navigate to Amazon.com, search for Star Wars, return the # of found items, and then navigate to the Today's Deals page. The entire code is below.
program.java (Main script)
public class program
{
public static void main(String[] args)
{
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.get("https://www.amazon.com");
// HOME PAGE
HomePage homepage = new HomePage(driver);
homepage.search("star wars");
// SEARCH RESULTS PAGE
SearchResultsPage searchResultsPage = new SearchResultsPage(driver);
System.out.println(searchResultsPage.getNumberOfResults());
// navigate to the Today's Deals page
searchResultsPage.clickTodaysDealsLink();
// TODAY'S DEALS PAGE
// do more stuff
driver.close();
driver.quit();
System.out.println("Done");
}
}
HomePage.java (Home page page object)
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class HomePage
{
WebDriver driver;
private By searchTextboxLocator = By.id("twotabsearchtextbox");
public HomePage(WebDriver driver)
{
this.driver = driver;
}
public void search(String searchString)
{
driver.findElement(searchTextboxLocator).sendKeys(searchString + "\n");
}
}
SearchResultsPage.java (Search results page page object)
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class SearchResultsPage
{
WebDriver driver;
private By todaysDealsLinkLocator = By.linkText("Today's Deals");
private By numberOfResultsLocator = By.id("s-result-count");
public SearchResultsPage(WebDriver driver)
{
this.driver = driver;
}
public String getNumberOfResults()
{
// grabs only the total count of search results from the string in the form "1-16 of 7,488,146 results for "
return driver.findElement(numberOfResultsLocator).getText().split(" ")[2];
}
public void clickTodaysDealsLink()
{
driver.findElement(todaysDealsLinkLocator).click();
}
}
I have created a POM model in my webdriver framework where i have two pages one is login page and the other is users page, now i have written a test case for login page and it is working fine, the problem comes when i am trying to run a second test case where i need to login first in order to reach to the users page where i need to click on the view page.
below is the piece of code which i am writing to run the two different page object model methods into a single test case , currently it is running the login method only not the users page method.![enter image description here][1]
Above i have attached the framework screenshot, and below is the userstestcase code which i have written :
It is not allowing me to paste the framework screenshot please help me out
package testCases;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import pageFactory.Userspage;
import pageFactory.loginPage;
public class UsersTestCase {
WebDriver driver;
loginPage lpg;
Userspage upg;
#BeforeTest
public void setup(){
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("someurl");
}
#Test(priority=0)
public void test_login(){
lpg = new loginPage(driver);
String loginPageTitle = lpg.getLoginTitle();
Assert.assertTrue(loginPageTitle.contains("Login"));
lpg.loginToGuru99("username", "password");
driver.findElement(By.xpath("//a[#href='somelink']")).click();
}
public void test_users(){
upg = new Userspage(driver);
String usersPageTitle = upg.getLoginTitle();
Assert.assertTrue(usersPageTitle.contains("Users"));
}
}
EDIT:
a quick fix would be:
Move the below
lpg = new loginPage(driver);
upg = new Userspage(driver);
to the beforeTest step, right under:
driver.get("http://citysurfstaging.sourcefuse.com/admin/login");
and in your user test, before anything else, call the line below:
lpg.loginToGuru99("saurabh.singh#sourcefuse.com", "sourcefuse123");
driver.findElement(By.xpath("//a[#href='http://citysurfstaging.sourcefuse.com/admin/users']")).click();
That should put you in the state you need to perform the user test...
Quick advice, if you really want to do POM, then you shouldnt be mapping elements in your tests, that should all be done within your page class...
ORIGINAL:
If you have multiple pages, and need them to interact with each other to perform an end to end test, why dont you create another layer of abstraction to the POM and have a Flow class?
Example:
In the constructor of the flow class you instantiate the pages you need to perform a flow (loginpage, userpage), which will give you visibility of the page objects of each page class, then create as many flows (methods) between these pages. The next step would be instantiate the flow in your test (the same way you instantiated the page) and call your flow methods which interacts with as many pages you wish... if this is not clear enough I can give more detailed examples
The above question has been resolved what i have done to resolve this is i haven't declared the global webdriver command and then using this command i wasn't transferring the control to the users page but i have recreated my framework and everything is working fine now
I am trying to automate google search,normal sendkeys is working ,but when I try to send using keys.F5 or ascii code ,refresh wont work
also when try to do location reload it gives error as " The method execute_script(String) is undefined for the type WebDriver
"
Tried instead of F5 ,F1 key also but no avail
` package com.at.sample;
import org.openqa.selenium.Keys;
import java.lang.Thread;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
// import org.openqa.selenium.Alert;
import java.util.List;
public class Refreshgoogle {
public static void main(String[] args) throws InterruptedException {
WebDriver driver;
System.setProperty("webdriver.chrome.driver","c://chromedriver.exe");
driver= new ChromeDriver();
//Launch the Application Under Test (AUT)
driver.get("http://google.com");
Actions action = new Actions(driver);
WebElement element = driver.findElement(By.name("q"));
element.sendKeys("test data");
//sends normal keybaord strokes
// approch 1 driver.findElement(By.xpath("//html")).sendKeys(Keys.F5);
// approch 2.1 WebElement element1 = driver.findElement(By.xpath("//*[#id=\"tsf\"]/div[2]/div[1]/div[2]/div[2]"));
//approch 2.2 element1.sendKeys(Keys.F1);
// approch 3 driver.findElement(By.xpath("//*[#id=\"gsr\"]")).sendKeys(Keys.F5);
// driver.execute_script("location.reload(true);");
System.out.println(driver.getTitle());
// working driver.navigate().to(driver.getCurrentUrl());
}
}
`
There are 4 approaches
First 3 wont refresh pagea
when used 4th it shows error as The method execute_script(String) is undefined for the type WebDriver
You can refresh in below ways:
1.Using get method and recursive way
driver.get("https://URL.com");
driver.get(driver.getCurrentURL());
Using Navigate method and Recursively calling your URL
driver.get("https://URL.com");
driver.navigate.to(driver.getCurrentURL());
Using one valid webelement and send keys
driver.get("https://URL.com");
driver. findElement(By.id("username")).sendKeys(Keys.F5);
Hope this help.
Please refer below solution
driver.navigate.refresh();
If you want to refresh your page using keys then you can also use Robot class.
Robot robot = new Robot(); // Robot class throws AWT Exception
Thread.sleep(2000); // Thread.sleep throws InterruptedException
robot.keyPress(KeyEvent.VK_CONTROL); // press Control key down key of
robot.keyPress(KeyEvent.VK_F5);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_F5);
Thread.sleep(2000);
This is selenium related issue more details available here: https://github.com/webdriverio/webdriverio/issues/1344
WebElement(I) sendKeys() will not accept Keys (keyboard keys). This can be handled using Actions class only.
Additionally, if you need to refresh the page, use WebDriver() refresh() or get current URL using getCurrentUrl() of same interface and navigate() using same url as parameter.
Update:
Here is the detailed explanation on each approach:
1) As per 'https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/WebElement.html#sendKeys-java.lang.CharSequence...-', sendKeys() in WebElement(I) accepts only char sequence (i.e. string.).
// approch 1 driver.findElement(By.xpath("//html")) returns a WebElement and this element sendKeys will accept only char sequence. Hence, your approach r=to refresh using Keys.F5 won't work here.
2) // approch 2.1 WebElement element1 = driver.findElement(By.xpath("//*[#id=\"tsf\"]/div[2]/div[1]/div[2]/div[2]"));
//approch 2.2 element1.sendKeys(Keys.F1);
Same explanation as approach 1.
3) // approch 3 driver.findElement(By.xpath("//*[#id=\"gsr\"]")).sendKeys(Keys.F5);
Did the same kind of operation as approach 1 and is explained there.
4) If we need to use javascriptexecutor, first we need to create javascriptexecutor object like below and should call execute_script() using reference variable of that object:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(Script,Arguments);
If you are not created this object, you will get 'execute_script(String) is undefined for the type WebDriver', which is expected.
Hence, the 4 approaches what you tried will not refresh the page.
Instead, you can use below options:
1) Actions class sendKeys(): which will accept keyboard keys.
2) using driver.navigate().refresh();
3) Using javascriptexecutor after creating an object for the same (as explained in approach 4)
Try with this code:
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class TestRefresh {
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://www.google.com");
`// case 1:`
`driver.navigate().to(driver.getCurrentUrl());`
`// case 2:`
`((JavascriptExecutor)driver).executeScript("document.location.reload()");`
`// case 3:`
`driver.navigate().refresh();`
}
}