6

I've been using Selenium WebDriver to implement functional tests for some projects that I've worked with. I'm trying to use the Page Object design pattern with Page Factory to factor out my locators. I've also created a static WaitTool object (singleton) that implements several waiting techniques with optional timeout parameters.

My current problem is that I would like to use my wait methods before the PageFactory attempts to initialise the WebElements. The reason I would like to wait is because the PageFactory may try to initialise the page elements before they are available on the page.

Here is a sample PageObject:

public class SignInPage extends PageBase {
    @FindBy(id = "username")
    @CacheLookup
    private WebElement usernameField;

    @FindBy(id = "password")
    @CacheLookup
    private WebElement passwordField;

    @FindBy(name = "submit")
    @CacheLookup
    private WebElement signInButton;

    public SignInPage(WebDriver driver) {
        super(driver);

        WaitTool.waitForPageToLoad(driver, this);

        // I'd like initialisation to occur here
    }

    public MainPage signInWithValidCredentials(String username, String password){
        return signIn(username, password, MainPage.class);
    }

    private <T>T signIn(String username, String password, Class<T> expectedPage) {
        usernameField.type(username);
        passwordField.type(password);
        signInButton.click();

        return PageFactory.initElements(driver, expectedPage);
    }
}

Here is a sample TestObject:

public class SignInTest extends TestBase {
    @Test
    public void SignInWithValidCredentialsTest() {
        SignInPage signInPage = PageFactory.initElements(driver, SignInPage.class);

        MainPage mainPage = signInPage.signInWithValidCredentials("sbrown", "sbrown");

        assertThat(mainPage.getTitle(), is(equalTo(driver.getTitle())));
    }
}

I tend to put my logic in the Page Object as much as possible (including waits), as it makes the test cases much more readable.

Jamie Piltz
  • 205
  • 1
  • 3
  • 12

1 Answers1

8

The WebElements in a PageFactroy are really proxies to WebElements. This means that every time you access a WebElement it will perform a search to find the element on the page.

This has some advantages:

  • When the PageFactory is initialised the proxies are configured, but the WebElements are not found at that point (so you won't get a NoSuchElementException)
  • Every time you use a WebElement it will go and find it again so you shouldn't se StaleElementException's

You are using the @CacheLookup annotation which is losing you the second benefit as it will find the element once and then keep a reference to it, you are now far more likely to see StaleElementExceptions.

That being said you still keep the main benefit which is that Selenium will not go to the page and actually find the element until you first use it.

So in summary all you need to do is move

PageFactory.initElements(driver, this);

Into your constructor and it will all work fine.

Ardesco
  • 7,281
  • 26
  • 49
  • I guess this means I can't return a `PageFactory.initElements(driver, expectedPage)` in the signIn function. – Jamie Piltz Apr 25 '13 at 22:32
  • `PageFactory.initElements(driver, this.class);` doesn't seem to work. supplying `this` or `this.getClass()` works however, but I am unsure if this is doing what I want. – Jamie Piltz Apr 25 '13 at 22:38
  • Sorry that's an error in my answer. I actually meant just this (answer updated to show the correct Code snippet) – Ardesco Apr 26 '13 at 05:29
  • 2
    If I am understanding you correctly you are just worried that when you instantiate the class it is going to start throwing a NoSuchElementExcpetion error because the page may not have loaded all of the WebElements that the PageFactory refers to. If that is your worry don't, that won't happen. When you perform a 'PageFactory.initElements(driver, this);' it will at that point configure all the proxies, but it won't try and find the element on the page until you actually use one of the WebElements. – Ardesco Apr 26 '13 at 05:36
  • 1
    @Ardesco: After I read through this post and your comments, I have a question. What does proxies in this case mean? – Abhijeet Vaikar Mar 20 '14 at 08:35