Currently I have the following classes which use PageFactory to initialize the elements that I use.
Base Class:
public class BaseClass {
public static WebDriver driver;
public static boolean bResult;
public BaseClass(WebDriver driver){
BaseClass.driver = driver;
BaseClass.bResult = true;
}}
Login Page Classs that holds the elements:
public class LoginPage extends BaseClass{
public LoginPage(WebDriver driver)
{
super(driver);
}
#FindBy(how= How.XPATH, using="//input[#placeholder='Username']")
public static WebElement username;
Then I use a separate Login class for my actions:
public class Login {
//Login
public static void enterUsernamePassword(String username, String password) throws Exception{
LoginPage.username.sendKeys(username);
LoginPage.password.sendKeys(password);
}
Then my steps class:
#When("^I enter a valid username (.*) and password (.*)")
public void I_enter_a_valid_username_and_password(String username, String password) throws Throwable
{
PageFactory.initElements(driver, LoginPage.class);
Login.enterUsernamePassword(username, password);
}
As you can see I am using PageFactory within the steps class. I hate doing this and would like to put the PageFactory somewhere else, just not in the steps class.
Without adding or deleting any classes, where could I place the PageFactory class? Any help would be appreciated.
I found that the best to do it is by using an Inversion Of Control / Dependency Injection framework. I use Spring but there are other options as well, e.g. Guice, Weld, Picocontainer.
Using Spring you can annotate all pages with #Component and add a PageObject Bean postprocessor to initialize all page elements when the pages are being created.
This approach is also recommended by the Cucumber for Java Book by Aslak Hellesoy (Cucumber Ltd founder). Cucumber also provides
Related
Sample Code:
public class RediffLoginPage
{
Webdriver driver;
public RediffLoginPage(Webdriver driver){
this.driver=driver;
}
By username=By.xpath(".//*(#id='login1']");
By Password=By.name("passwd");
}
public Webelement Emailid()
{
return driver.findElement(username);
}
public Webelement Password(){return driver.findElement(Password);}
In this line,
By username=By.xpath(".//*(#id='login1']");
what's the purpose of first By keyword here?
It's object repository code for a testcase.
Class By
Class By extends java.lang.Object and is defined as:
public abstract class By
extends java.lang.Object
Mechanism used to locate elements within a document. In order to create your own locating mechanisms, it is possible to subclass this class and override the protected methods as required, though it is expected that all subclasses rely on the basic finding mechanisms provided through static methods of this class:
public WebElement findElement(WebDriver driver) {
WebElement element = driver.findElement(By.id(getSelector()));
if (element == null)
element = driver.findElement(By.name(getSelector());
return element;
}
By have the following direct known Subclasses:
By.ByClassName
By.ByCssSelector
By.ById
By.ByLinkText
By.ByName
By.ByPartialLinkText
By.ByTagName
By.ByXPath
By.Remotable
I need to refresh the page using the Serenity screenplay pattern. I tried to apply
user.attemptsTo(Hit.the(Keys.F5).into(element));
But it didn't work of course.
Serenity Screenplay does not have a convenience function for refresh, but it should be trivial to roll your own.
public class Refresh implements Task {
public Refresh() { }
public static Refresh thePage() {
return Tasks.instrumented(Refresh.class);
}
#Override
#Step("{0} refreshes the browser")
public <T extends Actor> void performAs(T actor) {
WebDriver driver = BrowseTheWeb.as(actor).getDriver();
driver.navigate().refresh();
}
}
I have created a class in which I am creating all the methods I require for my test automation. Issue which I am facing is that when I run main class, it works fine. But when I call that class in other class it opens 2 browser windows. The test is performed on 1 and other remains ideal. Also when I use close() or quit() method for #After, it closes the ideal window not the one which I am working on.
Below is my code snippet for ref.
Main class
public class ProjectManagement{
WebDriver driver = new FirefoxDriver();
public void navigateCreate(String uid, String pass) throws Throwable {
driver.manage().window().maximize();
driver.get(baseurl);
driver.findElement(By.id("Email")).sendKeys(uid);
driver.findElement(By.id("Password")).sendKeys(pass);
driver.findElement(By.id("loginBtn")).click();
driver.findElement(By.linkText("Projects")).click();
driver.findElement(By.linkText("Create New Project")).click();
}
}
Test Class
public class NewTest extends ProjectManagement{
ProjectManagement project1 = new ProjectManagement();
#Test
public void createPro() throws Throwable {
project1.navigateCreate(UId,Password);
}
#AfterTest
public void afterTest() {
driver.quit();
}
}
If you are extending ProjectManagement, you don't need to instantiate it on the sub-class. By doing so, you're effectively creating two instances of the class and, as such, two instances of WebDriver (which in turn generates two browser windows).
So, remove the following:
ProjectManagement project1 = new ProjectManagement();
And change your createPro() method to:
#Test
public void createPro() throws Throwable {
navigateCreate(UId,Password);
}
I want to integrate the code to take screenshot using remoteWebdriver inside, testng's onTestFailure(ITestResult). I am unable to get the current webdriver instance inside onTestFailure().
Okay, I had a similar problem.
And since there's no clear answer here, I would post my ( working) solution
On your BaseTest / TestBase class, make your RemoteWebdriver instance accessible ( either by having it as a public property or with a getter)
In the Listener class (In my case its a public property):
public class BaseTest {
public RemoteWebDriver remoteDriver;
//... initalize driver
}
public class TestListener implements ITestListener {
#Override
public void onTestFailure(ITestResult result) {
BaseTest test = (BaseTest) result.getInstance();
if (test == null) {
return;
}
RemoteWebDriver driver = test.remoteDriver;
}
}
i m confused :( as automation framework if i use page object/factory than i should use object repository I mean Properties file in selenium webdriver.
OR
i can use one at a time either page factory or properties file approach.
i m using this code:
package Pages;
import java.util.Properties;
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 LoginPage {
final WebDriver driver;
static Properties prop = new Properties();
#FindBy(how = How.ID, using = "form-login-username")
private WebElement usernameEditbox;
#FindBy(how = How.NAME, using = "password")
private WebElement passwordEditbox;
#FindBy(how = How.NAME, using = "Log In")
private WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void enterUsername(String login) {
usernameEditbox.clear();
usernameEditbox.sendKeys(login);
}
/*public void enterUsername(String login) {
signInUsername.clear();
usernameEditbox.sendKeys(login);
}*/
public void enterPassword(String password) {
passwordEditbox.clear();
passwordEditbox.sendKeys(password);
}
public void clickSigninButton() {
loginButton.click();
}
public LandingPage login(String login, String password) {
enterUsername(login);
enterPassword(password);
clickSigninButton();
return PageFactory.initElements(driver, LandingPage.class);
}
}
Instead on defining #FindBy(how = How.ID, using = "form-login-username")
private WebElement usernameEditbox; in same file how i can call it from OR.properties ???
Here's a suggestion I made to somebody else using Page Object Pattern.
Properties files would be no different than just separating your elements to an elements class file and initializing them in the way I describe in the linked post.
Edit: Example of an elements class:
#FindBy(css = "button[id='Save']")
public static WebElement buttonSave;
#FindBy(css = "button[id='Cancel']")
public static WebElement buttonCancel;
And so on. The elements class is just meant to hold on to your elements. You then use those elements via the PageFactory.init example shown in the link above. It would be preferred to have a separate elements class for each "page." I hope that's clear enough :)
If you follow the page object pattern, then in theory each selector will only exist once. Therefore, it is acceptable to in affect hard code them in the page object class rather than create some kind of repository or external resource.
Take a look at Test Automation Framework (TAF) which have enhanced Page Object Factory implementation. It will allow you to use a properties file for your locators for your Page Factory classes.
You can mention a default locator file for your factory and can also override it at runtime (if required) by providing a external file.
http://menonvarun.github.io/taf/
http://menonvarun.github.io/taf/pages/locator_in_taf.html