9

In some languages, like Javascript, you can create a hierarchial structure of Elements within a PageObject, like so:

class HomePage {
    loginBox = {
        usernameTextBox = findElement(By.cssSelector("input.login"));
        passwordTextBox = findElement(By.cssSelector("input.password"));
    };
    headerTitle = findElement(By.cssSelector("h1.title"));
}

and then in your test you can access them as

function loginTest() {
    homePage = new HomePage();
    homePage.loginBox.usernameTextBox.sendKeys(username);
    homePage.loginBox.passwordTextBox.sendKeys(password);
    homePage.loginBox.loginButton.click();
    assert homePage.headerTitle.contains("Logged In")
}

In Java, however, it seems that however when you try to build inner classes with PageFactory, it simply doesn't descend into inner classes. If you set the inner classes static, you can instantiate the inner-class page objects directly, but you have to assign them to a new object field (e.g. homePageLoginBox = PageFactory.initElements(HomePage.loginBox.class); ) which means you have to explicitly instantiate each inner class.

Is there any way with Page Factory to create a hierarchical page structure and instantiate and access such an organized Page Object (with all subdivisions) in one fell swoop?

4
  • 1
    Have you tried to overload the class instantiation method and include a sub-class instantiation on parent instantiation?
    – mutt
    Aug 8, 2017 at 14:53
  • 1
    @mutt I ended up explicitly initializing the inner classes. I don't think pageFactory.initElements() executes constructors, does it? In any case you'd have to pass the driver object into them somehow... Aug 22, 2017 at 18:06
  • yes, which is why I mentioned overloading them. You basically re-write the initElements() and allow it to pass in the driver so that you can instantiate them all against an existing instance instead of a new instantiation.
    – mutt
    Aug 22, 2017 at 18:09
  • PageFactory isn't that great of an implementation of page objects. In my current project we are simply using nested static classes full of locators, and helper methods that take them as arguments. Not only less hassle with no need for instantiation, but also seriously minimizes the StaleElementExceptions. Oct 10, 2020 at 11:20

1 Answer 1

4

Inheritance can get messy real quick, one thing you can try instead of using inheritance, is to use composition. Create your nested page objects as full top level classes, then put them into your code as instance fields to be accessed.

// It's own file
public class MyPage {
    private final WebDriver driver;

    // Nest your "inner" class through composition instead of inheritance
    public final LoginBoxPage loginBox;

    public MyPage(WebDriver driver) {
        this.driver = driver;
        loginBox = new LoginBoxPage(driver);
}

// It's own file
public class LoginBoxPage {
    private final WebDriver driver;
    private final By username = By.css(...);
    private final By password = By.css(...);
    private final By submitButton = By.css(...);

    public LoginBoxPage(WebDriver driver) {
        this.driver = driver;
    }

    public LoginBoxPage username(String user) {
        driver.findElement(this.username).sendKeys(user);
        return this;
    }

    public LoginBoxPage password(String pw) {
        driver.findElement(this.password).sendKeys(pw);
        return this;
    }

    public void submit() {
        driver.findElement(submitButton).click();
    }
}

This particular example could be used like:

public void test() {
     WebDriver driver = new ChromeDriver();
     MyPage myPage = new MyPage(driver);

     // utilizing fluent returns
     myPage.loginBox.username("herp").password("derp").submit();

     // or not
     myPage.loginBox.username("herp");
     myPage.loginBox.password("derp");         
     myPage.loginBox.submit();
}
3
  • 1
    In my opinion, keeping your page objects immutable helps immensely with long term maintainability by reducing side effects. If you have public instance fields, keeping them final ensures that your assignments can't be mucked with. I put them public to make it a little closer to what you'd be familiar with javascript, however I'd normally make composed inner page objects private with a getter to further drive home immutability.
    – Julian
    Aug 25, 2017 at 18:22
  • In your example you haven't used pageFactory like homePageLoginBox = PageFactory.initElements(HomePage.loginBox.class);..... Is it that you can not use page factory in this pattern or do I missing something?
    – 1234
    Jul 25, 2018 at 22:48
  • @Studeera No, you aren't missing anything. When I wrote that, I didn't know that PageObject was a specific implementation since I've never used it. So I thought that the topic was more broadly talking about the page object model. Hindsight. I don't know how it would fall together using the PageFactory implementation.
    – Julian
    Aug 15, 2018 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.