I'm using page factory and AjaxElementLocatorFactory in my selenium project. I would like to implement something like this:
#FindBy(className = "loading-container")
private WebElement loadingElement;
public LoadingPage(WebDriver driver) {
AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 100);
PageFactory.initElements(factory, this);
}
public void waitLoadingToFinish() {
waitUntilElementDoesn'tExist(loadingElement);
}
Related
I need to add in my declaration a way to wait the element, for so then to click it. I am using Appium with Java, in a IOS device.
#iOSXCUITFindBy (xpath = "//XCUIElementTypeButton[#name=\"Enviar depois\"]")
private RemoteWebElement BtnEnviarDepois;
public void ClickBtnEnviarDepois(){
**// I need to Add a way to wait the element here**
BtnEnviarDepois.click();
}
I need to add in the declaration something like this, but I don't know how to implement:
public void wait(By ID) {
WebDriverWait wait = new WebDriverWait(DriverFactory.getDriver(), (180));
WebElement element = wait.until(ExpectedConditions.elementToBeClickable((ID)));
}
Simplest way to initialise wait and reuse it in the page objects is to use the concept of Inheritance. Here's one example how you can do it.
Page class:
public class MyPage extends BasePage {
#iOSXCUITFindBy(xpath = "//XCUIElementTypeButton[#name=\"Enviar depois\"]")
private WebElement btnEnviarDepois;
public MyPage(AppiumDriver driver){
super(driver);
}
public void ClickBtnEnviarDepois(){
waitForElementToBeClickable(btnEnviarDepois).click();
}
}
BasePage class:
public class BasePage {
private final WebDriverWait wait;
public BasePage(AppiumDriver driver){
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
public WebElement waitForElementToBeClickable(WebElement element){
return wait.until(ExpectedConditions.elementToBeClickable(element));
}
}
Some people don't like to write custom methods like waitForElementToBeClickable(). So alternatively, you can slightly change the code as below:
Page class:
public class MyPage extends BasePage {
#iOSXCUITFindBy(xpath = "//XCUIElementTypeButton[#name=\"Enviar depois\"]")
private WebElement btnEnviarDepois;
public MyPage(AppiumDriver driver){
super(driver);
}
public void ClickBtnEnviarDepois(){
wait.until(ExpectedConditions.elementToBeClickable(btnEnviarDepois)).click();
}
}
BasePage class:
public class BasePage {
protected final WebDriverWait wait;
public BasePage(AppiumDriver driver){
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
}
I started encountering problems when I use static objects reference for WebDriver and run the tests in parallel.
public static WebDriver driver;
Hence I decided to use non-static object reference for the WebDriver.
private WebDriver driver;
Now when I use POM with Page Factory, my understanding is that everytime I create a Test I will have to be creating a new Object in the test class as shown below.
/* Constructor in the Page Object class */
private WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
2 testcases as shown below in the same class.
private LoginPage loginPage;
#Test
public void testCase1() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
#Test
public void testCase2() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
My question here is a
Am I right in creating page object for every test cases?
Is there any way I can optimize this? Because One doubt I got is that non-static object reference may be getting overridden and causing problems in one of the methods if I run them in parallel.
Sorry if my query is naive. Any help would be appreciated.
You do not need to initialize it again. Also, initialize the pages in #BeforeTest rather than in test cases.
Here i would like to give you example of Page object model. Hope you can relate this.
My Main test:
#Before
public void SelectBrowser(){
driver = WebUtils.SelectBrowser(driver,"Chrome");
}
#Test
public void LoginToGmail() throws InterruptedException{
//WebDriver driver = new FirefoxDriver();
//MAximize the Screen
driver.manage().window().maximize();
//Go to Gmail Login Page
SignInPage SignInPage = new SignInPage();
WebUtils.GoToSignInPageForPropertyFile(driver, "URL");
//Click on Next
SignInPage.ClickToLogin(driver, By.cssSelector("input[id='next']"));
Now Supporting class:
GoToSignInPageForPropertyFile method will be in WebUtils
Whatever i write in Webutils will be used by each page object class.
For e.g.
public class WebUtils {
public static pageobject.SignInPage GoToSignInPageForPropertyFile(WebDriver driver, String URL) {
ReadFileData File = new ReadFileData();
Properties Values = File.ReadFile();
driver.get(Values.getProperty("URL"));
return PageFactory.initElements(driver, pageobject.SignInPage.class);
}
}
Now the method ClickToLogin is defined under SignInPage class as:
public class SignInPage {
public EmailViewPage ClickToLogin(WebDriver driver, By by) {
WebUtils.Click(driver, by);
return PageFactory.initElements(driver, EmailViewPage.class);
}
}
Which will further be in Webutils
public class WebUtils {
public static void Click(WebDriver driver, By by) {
WebElement Element = driver.findElement(by);
Element.click();
}
}
I am trying to use PageFactory Design Pattern but getting Null Pointer Exception.Please suggest any improvement required.
My Sample code looks like:
public DriverCapabilities() throws IOException{
URL url;
try {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("newCommandTimeout", "90");
caps.setCapability("browserName", "");
caps.setCapability("appActivity",Config.appActivity );
caps.setCapability("appPackage", Config.appPackage);
caps.setCapability("appWaitActivity",Config.appWaitActivity);
caps.setCapability("platformName", "Android");
caps.setCapability("platformVersion", "5.0");
caps.setCapability("deviceName", "Android Emulator");
}
caps.setCapability("app", Config.path);
caps.setCapability("appium-version", "1.3.7.2");
url = new URL("http://127.0.0.1:4723/wd/hub");
innerDriver = Config.os.equalsIgnoreCase("ANDROID")? new AndroidDriver(url, caps): new IOSDriver(url, caps);
DriverWait.implicitWait();
PageFactory.initElements(new AppiumFieldDecorator(innerDriver, 5, TimeUnit.SECONDS), this);
}
Sample Screen Class:
public class DemoScreen{
#AndroidFindBy(id = "eula_accept")
private static RemoteWebElement eula;
public static void submit() throws IOException{
init.getInstance(); //To initialize the driver
getEula().click();
}
public static WebElement getEula() {
return eula;
}
}
Sample Test code:
public class Demo1{
#Test(groups={"smokeTest"})
public void test1() throws IOException {
DemoScreen.submit();
}*
Is it because somewhere I'm not initializing the object or has it to do with the design pattern I'm following?
I'm trying to test one specific Selenium's Actions class method, which is as below.
public Actions sendKeys(java.lang.CharSequence... keysToSend)
Sends keys to the active element. This differs from calling WebElement.sendKeys(CharSequence...) on the active element.
public class Demo_1 {
private WebDriver driver;
private Actions action;
private String baseUrl;
#Before
public void setUp() throws Exception {
File file = new File("C:\\Users\\ProgramFiles\\firefox.exe");
FirefoxProfile profile = new FirefoxProfile();
FirefoxBinary binary = new FirefoxBinary(file);
driver = new FirefoxDriver(binary, profile);
action = new Actions(driver);
baseUrl = "http://www.mortgagecalculator.org";
}
#Test
public void testUntitled() throws Exception {
driver.get(baseUrl + "/");
driver.findElement(By.name("param[homevalue]")).click();
driver.findElement(By.name("param[homevalue]")).clear();
action.sendKeys("300000");
}
#After
public void tearDown() throws Exception {
//driver.quit();
}
}
I can do this alternatively, but in some cases when there is no WebElement, action.sendKeys can help to send CharSequence without any WebElement as parameter.
Can some come up with similar kind of issue, as the above code is not working :(
Cause its Actions class object so you need to tell the driver the actions you are performing.
action.sendKeys("300000").perform();
Will do the needful.
This is kinda follow-up for my question Test causing error occasionally. I initialize my driver
public class TestSuite {
public static WebDriver driver;
#BeforeClass
public static void setUpClass() {
driver = new FirefoxDriver();
}
public class FluentDriver extends TestSuite {
public static WebElement fluentWait(final By locator) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(300, TimeUnit.SECONDS)
.pollingEvery(50, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement element = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
});
return element;
}
;
}
But this this not handling the script which certainly is on the page, but I can't access the source of it.
FluentDriver.fluentWait(By.id("id")).click();
FluentDriver.fluentWait(By.xpath("//a[starts-with(#href,'/problematic_url.html')]")).click();
FluentDriver.fluentWait(By.className("green_true")).click();
Clicking the "id" pulls out a submenu, where the problematic url is. On webpage source (Ctrl+U) the url is present the whole time.
I got this working by adding Javascript enabling Firefox profile on driver. Then I use the FluentDriver solution. It works most of the time.