Page Factory is a Selenium model that can be used in test automation instead of Page Object Model.
It allows declaring pairs of locators and web elements together in a page class. The web elements are initialized in the page class constructor (this does not find the elements yet). The web elements are found before they are used for the 1st time.
This is a typical HomePage class implemented with the Page Factory model:
public class HomePage {
private WebDriver driver;
private static final String HOME_PAGE_URL = "https://www.vpl.ca/";
@FindBy(id = "edit-search")
private WebElement searchBox;
@FindBy(id = "edit-submit")
private WebElement searchButton;
public HomePage(WebDriver driver) {
PageFactory.initElements(driver, this);
this.driver = driver;
}
public void open() {
driver.get(HOME_PAGE_URL);
}
public boolean isDisplayed() {
return getUrl().equalsIgnoreCase(HOME_PAGE_URL);
}
public String getUrl() {
return driver.getCurrentUrl();
}
public ResultsPage searchBy(String keyword) {
typeKeyword(keyword);
clickSearchButton();
return new ResultsPage(driver);
}
public void typeKeyword(String keyword) {
searchBox.sendKeys(keyword);
}
public void clickSearchButton() {
searchButton.click();
}
}
And this is a typical ResultsPage class implemented with the same model:
public class ResultsPage {
private WebDriver driver;
private static final String RESULTS_PAGE_URL =
"https://vpl.bibliocommons.com";
@FindBy(xpath = "(//span[@data-key = 'pagination-text'])[1]")
private WebElement resultsFoundLabel;
@FindBy(xpath = "//li[contains(@class, 'page-number')]/a[@data-page = '2']")
private WebElement page2;
@FindBy(xpath = "//li[contains(@class, 'page-number')]/a[@data-page = '3']")
private WebElement page3;
@FindBy(xpath = "//li[contains(@class, 'page-number')]/a[@data-page = '4']")
private WebElement page4;
public ResultsPage(WebDriver driver) {
PageFactory.initElements(driver, this);
this.driver = driver;
}
public boolean isDisplayed() {
return getUrl().startsWith(RESULTS_PAGE_URL);
}
public String getUrl() {
return driver.getCurrentUrl();
}
public String getResultsFound() {
return resultsFoundLabel.getText();
}
public void goToPage2() throws InterruptedException {
scrollToBottom();
page2.click();
}
public void goToPage3() throws InterruptedException {
scrollToBottom();
page3.click();
}
public void goToPage4() throws InterruptedException {
scrollToBottom();
page4.click();
}
private void scrollToBottom() throws InterruptedException {
((JavascriptExecutor) driver).executeScript(
"window.scrollTo(0, document.body.scrollHeight)");
Thread.sleep(2000);
}
}
The page classes seem simpler than when implemented with Page Object Model.
This is because there is no code for finding the web elements. The web elements are found by the page factory before the elements are used for the 1st time. This is done in the background, with no code needed for it in the page classes.
This is great, isn’t it?
No code for finding elements!
Shorter page classes!
Just use the web elements without finding them?
Only good things!
Let’s discuss all these points one by one in the next few posts, starting with the shorter page classes.
We can use PageFactory with Implicit wait that will wait for element to appear in DOM. Much like “Auto Waits” in other tools. 😇