I am wring a PageFactory framework for a website using maven+TestNG,
I have page wise PageObject classes where all web elements and actions specific to page are present like LoginPageObject, AccountSelectionPageObject...
I have a class "Base" where the common elements like WebDriver, Logger are present.
I have a class "BasePage" where the common actions like click, scroll, select, refresh... are present
MyTestng.xml is having separate <class> entry for both all individual pages.
It's just that I am initializing the browser object in #BeforeSuiit and stored/placed it in the Base class which is being extended in my Test classes
Below is the flow/arch I came up for my project.
Issue:
I have multiple #Test in each of my test classes.
When my Test classes are executed individually, all #Test script executed,
but when I execute them continuously, i.e. my testng file have separate entries for all my test classes, my execution fails. Error says unable to find element on page, I have wait statements, but still it's not working.
I have tried debugging code, but not able to find the reason as the flow stops on starting of second page with exception saying element not found
Code:
#FindBy(id="listAccounts")
WebElement accountDropdown;
public void selectAccount(){
logger.info("Selecting Account");
implicitwait(10);
Select dropdown = new Select(accountDropdown);
logger.info("Drop down is multiple::"+ dropdown.isMultiple());
}
Expected:
Code should execute completely even when separated code page wise.
Actual:
When I have all pages code in one test class, code executed.
But when I place them separately in page wise test class, element not found exception is thrown.
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"id","selector":"listAccounts"}
In POM using PageFactory framework, one should initialise PageFactory in Constructor of PageClasses. Please find below code snippet which might work in your case.
public class LoginPage extends TestBase {
public LoginPage() {
PageFactory.initElements(driver, this);//Here driver is initialised in TestBase class and inherited in LoginPage class
}
//your code
#FindBy(id="listAccounts")
WebElement accountDropdown;
public void selectAccount(){
logger.info("Selecting Account");
implicitwait(10);
Select dropdown = new Select(accountDropdown);
logger.info("Drop down is multiple::"+ dropdown.isMultiple());
}
}
A complement to the Krishna answer:
PageFactory.initElements(driver, this);
The code above can be moved to the base class and from the LoginPage, you just pass the webdriver on the constructor like this.
public class LoginPage extends Base {
public LoginPage(Webdriver driver) {
super(driver);
}
...
public class Base {
public Base(Webdriver driver) {
PageFactory.initElements(driver, this);
}
...
Related
I have the following issue:
I have a home page where I load the URL with the following structure:
public class HomePage extends BasePage {
public HomePage(WebDriver driver) {
super(driver);
getDriver().get("URL");
}
Then I have another page, which extends from the HomePage:
public class OptionsPage extends HomePage {
public OptionsPage(WebDriver driver) {
super(driver);
}
Now, the issue is on the test, where I want to get the OptionsPage from an action (let's say clicking a button present on HomePage). It seems that the page just loads again once I call it:
// Open page
HomePage home = getHomePage(); //loads URL from BasePage
// click on some option which takes me to the OptionsPage
OptionsPage options = home.clickOnRandomOption(); //this method right here loads the URL again, from there the assertion fails since the page just loads again.
Assert.assertTrue(options.isRandomOptionSelected(), "Obviously it wasn't selected.");
The method to click the option on the home page looks like this:
public OptionsPage clickOnRandomOption() {
getWait().until(ExpectedConditions.elementToBeClickable(RandomOption));
RandomOption.click();
return new FlightOptionsPage(getDriver());
}
Can anyone help me out?
Your challenge is that when you instantiate your optionsPage you're executing all constructors up the chain.
From your code structure, you're running: OptionsPage -> HomePage -> BasePage every time you want to create an optionsPage. It's the testing POM equivalent of the Gorilla-banana-jungle problem.
I can see that the return type from home.clickOnRandomOption() is an OptionsPage so I'm assuming that's where you instantiate the options page.
Two suggestions - either of them will fix your problem, but I recommend you think about implementing both:
Don't chain your pages like that. Keep each one separate and ONLY extend once i.e. each page only extends from BasePage. If there is a common method which more than one page needs, put it in your BasePage and there's no need to extend page from other pages.
Don't execute test-context-impacting code in your constructors - use contructors only for initating variables. By this, I mean that when you create your HomePage do not navigate (driver.get("URL")) in the constructor. This will cause future complications for you when you run tests. For example, what if, you wanted to start on pageX and navigate to home via an auto-redirect then do more actions on home? - your POM won't support it as when you create homePage you're going to navigate the URL to there.
Inside class and outside method I am unable to access Webdriver class methods but inside a method of the same class, I can access methods. I am confused why It is happening.
Please click on the image to know clearly
package seleniumV1;
import org.openqa.selenium.WebDriver;
public class Test {
public WebDriver driver;
driver. // showing error here and I am unable to see the recommended methods of webdriver class
public void method()
{ driver.close();
driver.getTitle();
}
}
This has nothing to do with WebDriver. This is all about Java basics. Your code is invalid syntax.
The short answer is: In your example you can access the driver object from within method() only.
The long answer is: read about visibility of variables in Java. This chapter of "Learning Java" should be a good start.
I have a problem how handle inheritance in my test project using Page Object Pattern. In our company we have one stable version of our web appliaction - something called Demo from which we copy ready modules. Kind like a base to other new versions of clients applications. They are in 90% all the same. So i think it would be great to make Base Page Objects Classes and in many projects inheritance from that classes.Sadly they are different in this 10% and I need to override xpaths in class fields. I have a problem when i inheritance from Base POP Class, make a field in child class, and method from parent class(Base POP Class) run on field in parent class not on child. Let show me your example. This is may parent class:
public class BaseHomePage {
#FindBy(xpath = "exampleXpath")
protected WebElement profileButton;
public BaseHomePage(WebDriver driver) {
PageFactory.initElements(driver, this);
}
public void goToProfile() {
profileButton.click();
}
and this is my child class:
public class HomePage extends BaseHomePage {
#FindBy(xpath = "otherXpath")
protected WebElement profileButton;
public HomePage(WebDriver driver) {
super(driver);
PageFactory.initElements(driver,this);
}
public void goToProfile() {
profileButton.click();
}
}
So problem is I need to use the same method goToProfile() in child class, because when i not method from parent call on field in parent class. I don't want to duplicate code and i search for answers but i'm not sure this is good use of POP in multiple projects. What i need to make it properly? Or maybe u would suggest me make it in another way? Thanks for help!
Using Java, I am trying to write a general check for a particular text on every page in a web application that existing tests visit. Instead of having to write it on each and every page individually, is it possible to do in one place at a high level (may be in the base class)?
public class BaseClassForUiTest {
public BaseClassForUiTest() {
...
}
public void test() throws Exception {
boolean isNewPage = checkIfNewPage();
if (isNewPage)
// perform a text check on the page
}
}
Every test extends from BaseClassForUiTest and overrides the test() method.
Instead of having to write it on each and every page individually, is it possible to do in one place at a high level (may be in the base class)?
Yes, it is possible by implementing WebDriverEventListener into BaseClassForUiTest and override event handler methods to handling the appropriate WebDriver events according to need in one place.
Here every method corresponds to an event. According to your requirement you need to handle afterNavigateTo() method. This one is called every time the navigate to a page is completed.
You have to do perform a text checker on the page code in this method so that your code is executed every time the page navigates to some other page.
public class BaseClassForUiTest implements WebDriverEventListener
{
---------
---------
public void afterNavigateTo(String arg0, WebDriver arg1) {
// perform desire text checker stuff on the page here
}
}
Now Create Event Throwing WebDriver to perform your test :-
Create a regular WebDriver.
FirefoxDriver driver = new FirefoxDriver();
Now create an EventThrowingWebDriver using our regular WebDriver created above.
EventFiringWebDriver eventDriver = new EventFiringWebDriver(driver);
Create an instance of your eventHandler class and register it for events using the register method of EventFiringWebDriver object created above as :-
BaseClassForUiTest handler = new BaseClassForUiTest();
eventDriver.register(handler);
Full code :-
import org.openqa.selenium.support.events.EventFiringWebDriver;
public class BaseClassForUiTest {
public void test() throws Exception {
FirefoxDriver driver = new FirefoxDriver();
EventFiringWebDriver eventDriver = new EventFiringWebDriver(driver);
BaseClassForUiTest handler = new BaseClassForUiTest();
eventDriver.register(handler);
eventDriver.get("your url");
//Now do your further stuff
}
}
As for me, you'd better create a separated test class for this check using Parameterized or JUnitParams and give it a urls to run where as parameters, but it depends on what is your common approach to running tests (we run all testpack at the same time, so it's a solution for us in this situation).
Also it is seems like well-logically-separated solution
If you are going to use this check as an assertion you can rewrite your current code for this case and call for it in #Before block (but it is still not a good solution, in my opinion)
With WebDriver and PageFactory, using Java we are implementing a new automation project, and we've been experimenting with various ways of having PageObjects created. We're torn on a few different ideas, and want to make sure we don't work ourselves into a corner.
Is it best to, as documented in the WebDriver documentation, provide an initialized WebDriver to a PageFactory, along with the class template to create a new PageObject?
driver.get(URL);
PageObject page = PageFactory.initElements(driver, PageObject.class);
// elsewhere
class PageObject {
private WebDriver driver;
public PageObject(WebDriver driver) {
this.driver = driver;
this.validateUrl();
}
public void validateUrl() throws Exception {
if (!driver.getUrl().equals(url)) {
throw new Exception("URL not valid");
}
}
}
However, since the PageObject knows a lot about itself, such as perhaps its URL, can we not have the Page Object do the work?
PageObject page = new PageObject(driver);
page.goToUrl();
// elsewhere
class PageObject {
private WebDriver driver;
private String url;
public PageObject(WebDriver driver) {
PageFactory.initElements(driver, this);
}
public void goToUrl() {
driver.get(url);
}
}
I suppose I don't see much of an advantage to having the PageFactory do the instantiation versus just initialization, however I don't want to stray from the standards setup by the architects if there's a reason for it.
Thanks
One of the advantage of Page Factory:
Scenario:
In your application, you are having 100 fields in a page. The same page is called for 50 times.
If this type of scenario is done by using Page Object means, it will find each element again and again. There may be a chance for degradation of the performance.
If the same scenario is done by using Page Factory means, it will find the elements only for the first time, and then it will take from the cache. By this the performance is increased.
The best way is to let the frameworks like Geb and Thucydides abstract out the PageObjects and their initialization. I have been using Geb + Spock BDD combination for this and the results so far has been excellent.