Page Factory in Selenium
Page Factory is a Selenium support mechanism used with the Page Object Model (POM) to initialize and manage web elements represented as WebElement fields. It commonly uses annotations such as @FindBy to define element locators and PageFactory.initElements() to initialize those fields.
Page Factory is not a replacement for the Page Object Model. Instead, it is one implementation style that can be used inside page-object classes. The Page Object Model separates page-specific UI behavior from test logic, while Page Factory provides an annotation-based way to declare and initialize elements.
JustAcademy's Selenium Training curriculum includes Selenium WebDriver, TestNG, Page Object Model, automation framework concepts, data-driven testing, reusable test architecture, reporting, debugging, Selenium Grid, and CI/CD concepts. Page Factory is especially useful to understand when learning how traditional Selenium POM frameworks represent page elements. :contentReference[oaicite:0]{index=0}
1. What Is Page Factory?
Page Factory is a Selenium-supported approach for initializing WebElements inside Page Object classes. Instead of repeatedly creating By locators and calling driver.findElement(), developers can declare elements using annotations such as @FindBy.
The page class then initializes those element fields using:
PageFactory.initElements(driver, this);
For example:
@FindBy(id = "username")
WebElement username;
After initialization, the page object can interact with the element using:
username.sendKeys("admin");
2. Simple Definition
Page Factory is an annotation-based mechanism used with Selenium Page Objects to declare, initialize, and work with web elements more conveniently.
The common Page Factory flow is:
Web Page
↓
Locate Element
↓
@FindBy
↓
Page Object
↓
PageFactory.initElements()
↓
WebElement
↓
Test Method
↓
Browser Action
3. Page Factory vs Page Object Model
Page Object Model and Page Factory are related, but they are not the same thing.
| Page Object Model | Page Factory |
| Design pattern for organizing automation code. | Selenium-supported mechanism for initializing page elements. |
| Separates page behavior from test logic. | Uses annotations such as @FindBy. |
Can use By locators. | Commonly uses WebElement fields. |
| Does not require Page Factory. | Can be used as one implementation approach for POM. |
| Focuses on maintainability and architecture. | Focuses on element declaration and initialization. |
4. Why Use Page Factory?
Traditional Selenium scripts can become difficult to maintain when locators and browser actions are scattered throughout test classes. Page Factory provides a cleaner way to declare page elements.
- Reduces repeated element lookup code.
- Makes page classes easier to read.
- Provides annotation-based locator declarations.
- Encapsulates page elements inside page classes.
- Works naturally with the Page Object Model.
- Helps organize large Selenium projects.
- Allows page classes to expose business-level methods.
5. Basic Page Factory Architecture
Test Class
|
| calls
↓
Page Object Class
|
| contains
↓
@FindBy WebElements
|
| initialized by
↓
PageFactory.initElements()
|
↓
Selenium WebDriver
|
↓
Browser
|
↓
Web Application
6. Important Page Factory Classes and Annotations
The most commonly encountered Page Factory-related Selenium classes and annotations include:
| Class / Annotation | Purpose |
@FindBy | Defines a locator for a WebElement. |
@FindBys | Allows multiple locator conditions to be combined. |
@FindAll | Allows multiple possible locator strategies. |
PageFactory | Provides methods for initializing page elements. |
WebElement | Represents an element on the web page. |
WebDriver | Controls the browser. |
7. Required Imports
A basic Page Factory page class commonly requires the following imports:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
8. Basic Page Factory Syntax
public class LoginPage {
WebDriver driver;
@FindBy(id = "username")
WebElement username;
@FindBy(id = "password")
WebElement password;
@FindBy(id = "login")
WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
}
9. Understanding PageFactory.initElements()
The statement below is one of the most important parts of the Page Factory approach:
PageFactory.initElements(driver, this);
It tells Selenium to initialize the element fields declared in the current page object.
Here:
driver is the Selenium WebDriver instance.
this refers to the current page-object instance.
PageFactory.initElements() processes the annotated fields.
10. Constructor in Page Factory
A Page Factory page object normally initializes its elements inside the constructor.
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
Whenever a test creates the page object:
LoginPage loginPage = new LoginPage(driver);
the constructor initializes the Page Factory fields.
11. The @FindBy Annotation
@FindBy is the most commonly used Page Factory annotation. It allows a locator to be declared directly above a WebElement.
Example:
@FindBy(id = "username")
WebElement username;
This represents an element located using the ID locator.
12. @FindBy Using ID
@FindBy(id = "username")
WebElement username;
HTML:
<input id="username" type="text">
13. @FindBy Using Name
@FindBy(name = "email")
WebElement email;
HTML:
<input name="email" type="email">
14. @FindBy Using Class Name
@FindBy(className = "login-button")
WebElement loginButton;
15. @FindBy Using CSS Selector
@FindBy(css = "#username")
WebElement username;
Another example:
@FindBy(css = "input[type='email']")
WebElement email;
16. @FindBy Using XPath
@FindBy(xpath = "//input[@id='username']")
WebElement username;
Another example:
@FindBy(xpath = "//button[contains(text(),'Login')]")
WebElement loginButton;
17. @FindBy Using Link Text
@FindBy(linkText = "Forgot Password?")
WebElement forgotPassword;
18. @FindBy Using Partial Link Text
@FindBy(partialLinkText = "Forgot")
WebElement forgotPassword;
19. @FindBy Using Tag Name
@FindBy(tagName = "button")
WebElement button;
Tag-name locators should be used carefully because a page can contain many elements with the same tag.
20. Common @FindBy Strategies
| Strategy | Example |
| ID | @FindBy(id = "username") |
| Name | @FindBy(name = "email") |
| Class Name | @FindBy(className = "btn") |
| CSS | @FindBy(css = "#username") |
| XPath | @FindBy(xpath = "//input[@id='username']") |
| Link Text | @FindBy(linkText = "Login") |
| Partial Link Text | @FindBy(partialLinkText = "Log") |
| Tag Name | @FindBy(tagName = "button") |
21. Complete Login Page Using Page Factory
package pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPage {
WebDriver driver;
@FindBy(id = "username")
WebElement username;
@FindBy(id = "password")
WebElement password;
@FindBy(id = "loginButton")
WebElement loginButton;
@FindBy(linkText = "Forgot Password?")
WebElement forgotPassword;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void enterUsername(String value) {
username.sendKeys(value);
}
public void enterPassword(String value) {
password.sendKeys(value);
}
public void clickLogin() {
loginButton.click();
}
public void login(String user, String pass) {
username.sendKeys(user);
password.sendKeys(pass);
loginButton.click();
}
public void clickForgotPassword() {
forgotPassword.click();
}
}
22. Understanding the Login Page
The LoginPage class contains four important areas:
- WebDriver object.
- WebElement declarations using
@FindBy.
- Constructor with
PageFactory.initElements().
- Methods that perform business actions.
The test class does not need to know the XPath, ID, or CSS selector of every element. Those implementation details remain inside the page object.
23. Login Test Using Page Factory
package tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
import pages.LoginPage;
public class LoginTest {
@Test
public void validLoginTest() {
WebDriver driver = new ChromeDriver();
driver.get("https://example.com/login");
LoginPage loginPage = new LoginPage(driver);
loginPage.login("admin", "admin123");
driver.quit();
}
}
24. Test Flow
Start Test
↓
Create WebDriver
↓
Open Login Page
↓
Create LoginPage Object
↓
PageFactory.initElements()
↓
@FindBy fields become usable
↓
loginPage.login()
↓
Enter Username
↓
Enter Password
↓
Click Login
↓
Validate Result
↓
Close Browser
25. Page Factory With TestNG
Page Factory can be combined with TestNG to create structured automation tests.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class LoginTest {
WebDriver driver;
LoginPage loginPage;
@BeforeMethod
public void setUp() {
driver = new ChromeDriver();
driver.get("https://example.com/login");
loginPage = new LoginPage(driver);
}
@Test
public void loginTest() {
loginPage.login("admin", "admin123");
}
@AfterMethod
public void tearDown() {
driver.quit();
}
}
26. Page Factory With BaseTest
In a framework, browser initialization should normally be centralized rather than duplicated in every test class.
public class BaseTest {
protected WebDriver driver;
@BeforeMethod
public void setUp() {
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://example.com");
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
The test class can then extend BaseTest.
27. Page Factory With BaseTest and LoginPage
public class LoginTest extends BaseTest {
@Test
public void validLogin() {
LoginPage loginPage = new LoginPage(driver);
loginPage.login("admin", "admin123");
}
}
28. Page Factory With Assertions
Assertions should generally remain in the test layer rather than being scattered throughout page classes.
@Test
public void loginTest() {
LoginPage loginPage = new LoginPage(driver);
loginPage.login("admin", "admin123");
Assert.assertEquals(driver.getTitle(), "Dashboard");
}
29. Page Verification Methods
A page object can provide methods that expose meaningful page state to tests.
public boolean isDashboardDisplayed() {
return dashboardHeading.isDisplayed();
}
Test:
Assert.assertTrue(homePage.isDashboardDisplayed());
30. Page Factory With Explicit Wait
Page Factory does not eliminate the need for synchronization. Modern web applications often load elements asynchronously, so explicit waits may still be necessary.
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOf(username));
username.sendKeys("admin");
A more maintainable approach is to centralize synchronization logic where appropriate instead of adding arbitrary sleeps throughout the framework.
31. Page Factory and Lazy Element Lookup
Traditional Page Factory implementations commonly use proxy objects so that the actual element lookup can happen when the field is accessed rather than necessarily locating every element at page-object construction time.
This behavior is important when understanding Page Factory, but it should not be confused with automatic synchronization. Lazy lookup does not mean that an element will automatically wait for an arbitrary application state.
32. Page Factory Is Not an Automatic Wait Mechanism
This is a common misconception.
Incorrect assumption:
@FindBy(id = "login")
WebElement loginButton;
does not mean that Selenium will automatically wait until the application is ready under every condition.
For dynamic applications, use appropriate explicit synchronization:
wait.until(ExpectedConditions.elementToBeClickable(loginButton)).click();
33. @FindBys Annotation
@FindBys can be used when multiple locator conditions need to be combined.
@FindBys({
@FindBy(tagName = "input"),
@FindBy(className = "username")
})
WebElement username;
The exact locator design should be based on the application's DOM and the uniqueness and stability of the selected attributes.
34. @FindAll Annotation
@FindAll can be used when multiple possible locator strategies are supplied and matching elements are considered.
@FindAll({
@FindBy(id = "username"),
@FindBy(name = "username")
})
WebElement username;
Use such combinations only when they make the locator strategy clearer and more maintainable.
35. Page Factory With Multiple Elements
public class RegistrationPage {
@FindBy(id = "firstName")
WebElement firstName;
@FindBy(id = "lastName")
WebElement lastName;
@FindBy(id = "email")
WebElement email;
@FindBy(id = "password")
WebElement password;
@FindBy(id = "register")
WebElement registerButton;
public RegistrationPage(WebDriver driver) {
PageFactory.initElements(driver, this);
}
public void register(String first,
String last,
String emailAddress,
String passwordValue) {
firstName.sendKeys(first);
lastName.sendKeys(last);
email.sendKeys(emailAddress);
password.sendKeys(passwordValue);
registerButton.click();
}
}
36. Page Factory With Lists of WebElements
Page Factory can also represent multiple matching elements using a list.
@FindBy(css = ".product-card")
List<WebElement> products;
Example:
for (WebElement product : products) {
System.out.println(product.getText());
}
37. Product Page Example
public class ProductPage {
WebDriver driver;
@FindBy(css = ".product-card")
List<WebElement> products;
@FindBy(css = ".add-to-cart")
WebElement addToCartButton;
public ProductPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public int getProductCount() {
return products.size();
}
public void clickAddToCart() {
addToCartButton.click();
}
}
38. Page Factory With Dropdowns
Page Factory can represent the dropdown element, while Selenium's Select class can be used to interact with a standard HTML select element.
@FindBy(id = "country")
WebElement countryDropdown;
Usage:
Select country = new Select(countryDropdown);
country.selectByVisibleText("India");
39. Page Factory With Checkboxes
@FindBy(id = "terms")
WebElement termsCheckbox;
public void acceptTerms() {
if (!termsCheckbox.isSelected()) {
termsCheckbox.click();
}
}
40. Page Factory With Radio Buttons
@FindBy(id = "male")
WebElement maleRadio;
public void selectMale() {
if (!maleRadio.isSelected()) {
maleRadio.click();
}
}
41. Page Factory With Alerts
Browser alerts are not ordinary WebElements, so they are handled through WebDriver's alert API.
driver.switchTo().alert().accept();
This demonstrates an important point: Page Factory is for page elements; it does not replace Selenium's other interaction APIs.
42. Page Factory With Frames
Frames also require WebDriver context switching.
driver.switchTo().frame("paymentFrame");
After completing the interaction:
driver.switchTo().defaultContent();
43. Page Factory With Multiple Windows
Window handling is also performed through WebDriver window handles.
String originalWindow = driver.getWindowHandle();
for (String window : driver.getWindowHandles()) {
if (!window.equals(originalWindow)) {
driver.switchTo().window(window);
break;
}
}
44. Page Factory With Actions Class
Advanced mouse and keyboard interactions can be performed using the Selenium Actions API.
@FindBy(id = "menu")
WebElement menu;
Actions actions = new Actions(driver);
actions.moveToElement(menu).perform();
45. Page Factory With JavaScriptExecutor
JavaScriptExecutor can be used when JavaScript-level interaction is required.
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(
"arguments[0].click();",
loginButton
);
Normal Selenium interactions should generally be preferred when they work correctly. JavaScript should not be used merely to bypass a synchronization or locator problem.
46. Page Factory With Data-Driven Testing
Page Factory works well with TestNG DataProvider because page interaction remains inside the page class while different test data is supplied by the test layer.
@DataProvider(name = "loginData")
public Object[][] loginData() {
return new Object[][] {
{"admin", "admin123"},
{"user1", "password1"},
{"user2", "password2"}
};
}
@Test(dataProvider = "loginData")
public void loginTest(String username, String password) {
LoginPage loginPage = new LoginPage(driver);
loginPage.login(username, password);
}
47. Page Factory With Excel Data
In larger frameworks, test data can be stored in Excel or CSV files. The data layer supplies values, while Page Factory page classes perform browser interactions.
Excel File
↓
Data Reader
↓
TestNG DataProvider
↓
Test Method
↓
Page Factory Page Object
↓
Web Application
48. Page Factory and Keyword-Driven Framework
Page Factory can also be combined with a keyword-driven framework. The keyword layer decides what action should occur, while page objects contain the element interactions.
Keyword: ENTER_USERNAME
↓
Keyword Engine
↓
LoginPage.enterUsername()
↓
@FindBy username
↓
WebElement.sendKeys()
49. Page Factory and Hybrid Framework
A hybrid Selenium framework can combine Page Factory with TestNG, data-driven testing, reusable utilities, reporting, logging, configuration management, and CI/CD.
Hybrid Framework
|
+-- Page Factory / Page Objects
|
+-- TestNG
|
+-- Data-Driven Testing
|
+-- Utility Classes
|
+-- Configuration
|
+-- Reporting
|
+-- Logging
|
+-- Screenshots
|
+-- Selenium Grid
|
+-- CI/CD
This fits naturally with the framework topics covered in JustAcademy's Selenium curriculum, including POM, data-driven frameworks, keyword-driven frameworks, hybrid framework design, reusable architecture, reporting, logging, Selenium Grid, and CI/CD. :contentReference[oaicite:1]{index=1}
50. Page Factory Project Structure
SeleniumProject
│
├── src/test/java
│ ├── base
│ │ └── BaseTest.java
│ │
│ ├── pages
│ │ ├── LoginPage.java
│ │ ├── HomePage.java
│ │ ├── ProductPage.java
│ │ ├── CartPage.java
│ │ └── CheckoutPage.java
│ │
│ ├── tests
│ │ ├── LoginTest.java
│ │ ├── ProductTest.java
│ │ └── CheckoutTest.java
│ │
│ ├── utilities
│ │ ├── ExcelUtil.java
│ │ ├── ScreenshotUtil.java
│ │ └── ConfigReader.java
│ │
│ └── listeners
│ └── TestListener.java
│
├── src/test/resources
│ ├── config.properties
│ └── testdata.xlsx
│
└── pom.xml
51. Page Factory Login Project
A practical Login Automation project can contain the following components:
- Chrome WebDriver.
- LoginPage using Page Factory.
- TestNG test class.
- BaseTest for browser setup.
- Explicit waits.
- Assertions.
- Screenshot capture.
- Test reports.
- Logging.
52. Complete Login Page
public class LoginPage {
private WebDriver driver;
@FindBy(id = "username")
private WebElement username;
@FindBy(id = "password")
private WebElement password;
@FindBy(css = "button[type='submit']")
private WebElement loginButton;
@FindBy(css = ".error-message")
private WebElement errorMessage;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void enterUsername(String value) {
username.clear();
username.sendKeys(value);
}
public void enterPassword(String value) {
password.clear();
password.sendKeys(value);
}
public void clickLogin() {
loginButton.click();
}
public void login(String user, String pass) {
enterUsername(user);
enterPassword(pass);
clickLogin();
}
public String getErrorMessage() {
return errorMessage.getText();
}
}
53. Why Keep WebElements Private?
Page objects should generally encapsulate their implementation details.
Instead of allowing tests to directly manipulate every WebElement:
loginPage.username.sendKeys("admin");
prefer:
loginPage.enterUsername("admin");
This follows encapsulation and makes future locator changes easier to manage.
54. Business Methods in Page Factory
A good page object should expose meaningful user actions rather than forcing test classes to perform low-level Selenium commands.
Less desirable:
username.sendKeys("admin");
password.sendKeys("1234");
loginButton.click();
Better:
loginPage.login("admin", "1234");
55. Page Chaining
A page method can return another page object when an action navigates to another page.
public HomePage clickLogin() {
loginButton.click();
return new HomePage(driver);
}
Then:
HomePage homePage = loginPage.clickLogin();
56. Complete E-Commerce Page Factory Flow
LoginPage
↓
Login
↓
HomePage
↓
ProductPage
↓
Add Product
↓
CartPage
↓
CheckoutPage
↓
Order Confirmation
57. LoginPage
public class LoginPage {
WebDriver driver;
@FindBy(id = "username")
WebElement username;
@FindBy(id = "password")
WebElement password;
@FindBy(id = "login")
WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public HomePage login(String user, String pass) {
username.sendKeys(user);
password.sendKeys(pass);
loginButton.click();
return new HomePage(driver);
}
}
58. HomePage
public class HomePage {
WebDriver driver;
@FindBy(id = "products")
WebElement productsLink;
public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public ProductPage openProducts() {
productsLink.click();
return new ProductPage(driver);
}
}
59. ProductPage
public class ProductPage {
WebDriver driver;
@FindBy(css = ".add-to-cart")
WebElement addToCart;
@FindBy(id = "cart")
WebElement cart;
public ProductPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void addProductToCart() {
addToCart.click();
}
public CartPage openCart() {
cart.click();
return new CartPage(driver);
}
}
60. CartPage
public class CartPage {
WebDriver driver;
@FindBy(id = "checkout")
WebElement checkoutButton;
public CartPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public CheckoutPage checkout() {
checkoutButton.click();
return new CheckoutPage(driver);
}
}
61. End-to-End Test
@Test
public void purchaseProductTest() {
LoginPage loginPage = new LoginPage(driver);
HomePage homePage =
loginPage.login("admin", "admin123");
ProductPage productPage =
homePage.openProducts();
productPage.addProductToCart();
CartPage cartPage =
productPage.openCart();
CheckoutPage checkoutPage =
cartPage.checkout();
checkoutPage.placeOrder();
}
62. Page Factory With Explicit Wait Utility
A reusable wait utility can simplify synchronization across page classes.
public class WaitUtil {
private WebDriver driver;
private WebDriverWait wait;
public WaitUtil(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
}
public void waitForVisible(WebElement element) {
wait.until(
ExpectedConditions.visibilityOf(element)
);
}
public void waitForClickable(WebElement element) {
wait.until(
ExpectedConditions.elementToBeClickable(element)
);
}
}
63. Page Factory and Dynamic Elements
Modern applications frequently generate dynamic IDs, asynchronous content, AJAX components, overlays, and changing DOM structures.
For such applications:
- Prefer stable locators.
- Avoid unnecessary absolute XPath expressions.
- Use explicit waits for meaningful application states.
- Avoid fixed
Thread.sleep() values wherever possible.
- Be careful when elements are replaced in the DOM.
- Design page methods around user actions and application states.
64. Page Factory and StaleElementReferenceException
A StaleElementReferenceException can occur when an element reference no longer points to the current DOM element, for example after a page refresh or DOM replacement.
Example scenario:
Element located
↓
DOM changes
↓
Old reference becomes invalid
↓
Interaction attempted
↓
StaleElementReferenceException
Solutions include:
- Locate the element again.
- Wait for the correct application state.
- Use stable page-object methods.
- Avoid unnecessary caching of dynamic elements.
65. @CacheLookup
@CacheLookup has historically been used with Page Factory to cache an element reference after it is located.
@CacheLookup
@FindBy(id = "username")
WebElement username;
However, caching can become problematic when the DOM changes or the element is replaced. Therefore, it should be used cautiously and generally avoided for dynamic elements.
66. AjaxElementLocatorFactory
AjaxElementLocatorFactory is another Page Factory-related mechanism that can provide delayed element lookup with a timeout.
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(
new AjaxElementLocatorFactory(driver, 10),
this
);
}
This can be useful in certain traditional Page Factory designs, but it should not be treated as a complete replacement for explicit waits and proper synchronization strategies.
67. Page Factory With Maven
A Selenium Page Factory project can be managed using Maven.
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>YOUR_VERSION</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>YOUR_VERSION</version>
<scope>test</scope>
</dependency>
</dependencies>
68. Page Factory With Reporting
Page Factory page objects can be integrated with reporting libraries. The page class performs the action, while the test framework or listener records the result.
Test
↓
Page Object Action
↓
Selenium Interaction
↓
Result
↓
TestNG Listener
↓
Report
JustAcademy's Selenium curriculum includes test execution, reporting, logging, and debugging as part of its automation framework learning path. :contentReference[oaicite:2]{index=2}
69. Page Factory With Logging
Logging can help identify which page action was executed before a failure.
logger.info("Entering username");
loginPage.enterUsername("admin");
logger.info("Entering password");
loginPage.enterPassword("admin123");
logger.info("Clicking login");
loginPage.clickLogin();
70. Page Factory With Screenshots
Screenshots can be captured when a test fails.
public void takeScreenshot(String fileName) throws IOException {
File source =
((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
Files.copy(
source.toPath(),
Paths.get("screenshots/" + fileName + ".png")
);
}
71. Page Factory and Selenium Grid
Page Factory does not prevent tests from running on Selenium Grid. The WebDriver implementation can be local or remote while page objects continue to interact with the browser.
Test
↓
Page Factory
↓
RemoteWebDriver
↓
Selenium Grid
↓
Chrome / Firefox / Edge
↓
Application
JustAcademy's Selenium curriculum includes Selenium Grid, parallel execution, remote execution, and cross-browser automation. :contentReference[oaicite:3]{index=3}
72. Page Factory and Cross-Browser Testing
The same page objects can generally be reused across browsers when the application's DOM and behavior remain consistent.
LoginTest
|
+---- Chrome
|
+---- Firefox
|
+---- Edge
|
+---- Remote Grid
This is one reason centralized page-object design can help reduce duplication in automation projects.
73. Page Factory and CI/CD
Page Factory-based Selenium tests can be executed through CI/CD pipelines.
Developer Commit
↓
Git Repository
↓
Jenkins / CI Server
↓
Maven Build
↓
TestNG
↓
Selenium Tests
↓
Browser / Grid
↓
Reports
↓
Build Result
JustAcademy's current Selenium course information includes Git, Jenkins/CI/CD concepts, framework development, reporting, and Selenium Grid among its broader automation topics. :contentReference[oaicite:4]{index=4}
74. Page Factory vs Traditional POM
| Traditional POM With By | Page Factory POM |
Uses By locators. | Commonly uses @FindBy. |
Element obtained using driver.findElement(). | Element represented by a WebElement field. |
| Very explicit element lookup. | More declarative element declaration. |
| Works naturally with modern Selenium patterns. | Useful for understanding and maintaining existing Page Factory frameworks. |
| No PageFactory initialization required. | Usually requires PageFactory.initElements(). |
75. Traditional POM Example
private By username =
By.id("username");
public void enterUsername(String value) {
driver.findElement(username)
.sendKeys(value);
}
76. Page Factory Equivalent
@FindBy(id = "username")
private WebElement username;
public void enterUsername(String value) {
username.sendKeys(value);
}
77. Which Approach Should You Understand?
For Selenium automation learning, it is useful to understand both approaches. Page Factory is common in many existing or traditional Selenium frameworks, while direct By-based page objects are also widely used in modern framework designs.
The important concept is not simply choosing annotations; it is designing page objects that have clear responsibilities, stable locators, good synchronization, reusable methods, and clean separation between test logic and UI implementation.
78. Advantages of Page Factory
- Clean annotation-based element declarations.
- Easy-to-read page classes.
- Works naturally with Page Object Model.
- Encapsulates page-specific elements.
- Can reduce repetitive element lookup syntax.
- Supports lists of WebElements.
- Works with TestNG and other test frameworks.
- Can be integrated into larger automation frameworks.
79. Limitations of Page Factory
- Page Factory is not required to implement POM.
- It does not automatically solve synchronization problems.
- Dynamic DOM changes can still cause stale-element problems.
- Overuse of annotations can make complex locator strategies harder to reason about.
- Existing Page Factory code may require modernization depending on the Selenium version and framework architecture.
- Developers still need a strong understanding of Selenium locators and WebDriver behavior.
80. Common Mistakes in Page Factory
Mistake 1: Forgetting initElements()
public LoginPage(WebDriver driver) {
this.driver = driver;
}
Better:
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
Mistake 2: Using Unstable XPath
/html/body/div[2]/div[1]/form/input[1]
Prefer stable attributes when available.
Mistake 3: Using Thread.sleep() Everywhere
Thread.sleep(5000);
Prefer condition-based synchronization.
Mistake 4: Putting Assertions Everywhere
Keep most test validations in the test layer and expose useful page-state methods from page objects.
Mistake 5: Making Everything Public
Use appropriate encapsulation and expose business-level methods.
81. Best Practices for Page Factory
- Keep page classes focused on one page or meaningful component.
- Use private WebElement fields where appropriate.
- Use stable locators.
- Prefer IDs and stable attributes when available.
- Keep test logic outside page classes.
- Create reusable business methods.
- Use explicit waits for dynamic conditions.
- Avoid unnecessary
Thread.sleep().
- Avoid unnecessary
@CacheLookup on dynamic pages.
- Keep browser setup in a BaseTest or driver-management layer.
- Use meaningful page and method names.
- Keep reporting and logging responsibilities separated where practical.
- Review whether Page Factory is appropriate for the specific framework rather than using it automatically.
82. Naming Conventions
| Item | Recommended Example |
| Page Class | LoginPage |
| Test Class | LoginTest |
| WebElement | loginButton |
| Method | clickLogin() |
| Boolean Method | isLoginDisplayed() |
| Data Method | getProductName() |
83. Component Objects With Page Factory
Large web applications may contain reusable components such as navigation bars, headers, sidebars, product cards, menus, or checkout widgets.
Instead of putting everything into one large page class, reusable components can be represented separately.
Page
|
+-- Header
|
+-- Navigation
|
+-- ProductList
|
+-- Footer
This approach can improve maintainability in large automation suites.
84. Page Object vs Component Object
| Page Object | Component Object |
| Represents a complete page or major application screen. | Represents a reusable UI section. |
| Example: LoginPage. | Example: HeaderComponent. |
| Usually tied to a URL or page state. | Can appear on multiple pages. |
85. Page Factory in a Real-Time Framework
Selenium Automation Framework
|
+------------------+------------------+
| | |
Driver Pages Tests
| | |
| Page Factory TestNG
| | |
| @FindBy Assertions
| | |
+------------------+------------------+
|
Utilities
|
+-------------+-------------+
| | |
Excel Reports Logging
|
CI/CD
|
Selenium Grid
86. Practical Project: Login Automation
Project Objective: Automate a web application's login workflow using Selenium WebDriver, Java, TestNG, Page Object Model, and Page Factory.
Project Requirements
- Open browser.
- Navigate to login page.
- Enter username.
- Enter password.
- Click login.
- Verify successful login.
- Capture screenshot on failure.
- Generate execution report.
Automation Flow
Open Browser
↓
Open Login URL
↓
Create LoginPage
↓
Initialize Page Factory
↓
Enter Username
↓
Enter Password
↓
Click Login
↓
Verify Dashboard
↓
Report Result
87. Practical Project: E-Commerce Automation
Build an e-commerce automation framework using Page Factory.
Pages
- LoginPage
- HomePage
- ProductPage
- CartPage
- CheckoutPage
- OrderConfirmationPage
Test Scenarios
- Valid login.
- Invalid login.
- Search product.
- Open product.
- Add product to cart.
- Update quantity.
- Remove product.
- Checkout.
- Place order.
- Verify order confirmation.
88. Interview Question: What Is Page Factory?
Answer: Page Factory is a Selenium-supported mechanism commonly used with Page Object classes to initialize WebElement fields declared using annotations such as @FindBy. It provides an annotation-based way of representing page elements.
89. Interview Question: Is Page Factory the Same as POM?
Answer: No. POM is a design pattern used to organize page-specific behavior and separate it from test logic. Page Factory is an implementation mechanism that can be used within POM classes to initialize and represent elements.
90. Interview Question: What Does PageFactory.initElements() Do?
Answer: It initializes the WebElement fields defined in a page object, including fields represented through Page Factory annotations such as @FindBy.
91. Interview Question: What Is @FindBy?
Answer: @FindBy is a Selenium annotation used to specify how a WebElement should be located, for example by ID, name, CSS selector, XPath, class name, link text, or other supported strategies.
92. Interview Question: Does Page Factory Automatically Wait for Elements?
Answer: No. Page Factory's element initialization or lazy lookup behavior should not be confused with explicit synchronization. Dynamic applications may still require explicit waits such as WebDriverWait.
93. Interview Question: What Is @CacheLookup?
Answer: @CacheLookup has traditionally been used to cache an element reference. It should be used cautiously because cached references can become invalid when the DOM changes.
94. Interview Question: Can Page Factory Handle Multiple WebElements?
Answer: Yes. A Page Factory page object can represent multiple WebElements and can also declare collections such as List<WebElement>.
95. Interview Question: Can Page Factory Be Used With TestNG?
Answer: Yes. Page Factory can be used with TestNG for organizing tests, assertions, setup/teardown, DataProvider-based testing, and parallel execution.
96. Interview Question: Can Page Factory Be Used in a Hybrid Framework?
Answer: Yes. Page Factory can be one part of a hybrid framework alongside TestNG, data-driven testing, reusable utilities, configuration management, reporting, logging, screenshots, Grid, and CI/CD.
97. Interview Question: What Is the Difference Between @FindBy and By?
| @FindBy | By |
| Annotation-based element declaration. | Locator object. |
| Commonly paired with Page Factory. | Can be used directly with WebDriver. |
| Usually represented as WebElement fields. | Typically passed to findElement() or related APIs. |
98. Interview Question: Which Is Better, Page Factory or By-Based POM?
Answer: There is no universal requirement to use one approach. The choice depends on the framework, team conventions, Selenium version, application behavior, and maintainability requirements. Page Factory is useful to understand and can be found in existing frameworks, while direct By-based page objects are also a common design choice.
99. Common Interview Coding Question
Question: Create a LoginPage using Page Factory.
public class LoginPage {
WebDriver driver;
@FindBy(id = "username")
WebElement username;
@FindBy(id = "password")
WebElement password;
@FindBy(id = "login")
WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void login(String user, String pass) {
username.sendKeys(user);
password.sendKeys(pass);
loginButton.click();
}
}
100. Page Factory Quick Revision
| Concept | Remember |
| Page Factory | Annotation-based element initialization approach. |
| POM | Design pattern for page-object-based automation. |
| @FindBy | Defines element locator. |
| PageFactory.initElements() | Initializes Page Factory fields. |
| WebElement | Represents a page element. |
| WebDriver | Controls the browser. |
| WebDriverWait | Provides explicit synchronization. |
| @CacheLookup | Caches an element reference; use cautiously. |
| @FindBys | Combines locator conditions. |
| @FindAll | Provides multiple possible locator strategies. |
101. Page Factory Learning Flow
Java Basics
↓
OOP
↓
Selenium WebDriver
↓
Locators
↓
WebElements
↓
Page Object Model
↓
Page Factory
↓
TestNG
↓
Explicit Waits
↓
Data-Driven Testing
↓
Hybrid Framework
↓
Reporting & Logging
↓
Selenium Grid
↓
CI/CD
102. Page Factory Best-Practice Checklist
- Understand POM before implementing Page Factory.
- Initialize page fields correctly.
- Use stable locators.
- Keep locators inside page classes.
- Keep test logic inside test classes.
- Use business-level page methods.
- Use explicit waits for dynamic conditions.
- Avoid unnecessary hard waits.
- Be careful with dynamic DOM elements.
- Avoid unnecessary element caching.
- Use meaningful names.
- Keep page classes maintainable.
- Use reusable utilities for common operations.
- Integrate reporting and logging at the framework level.
- Run the framework across browsers when required.
- Integrate automated execution with CI/CD when appropriate.
103. Important Difference to Remember
The most important concept is:
POM = Design Pattern
Page Factory = Element Initialization / Declaration Approach
TestNG = Test Execution Framework
WebDriver = Browser Automation API
WebDriverWait = Synchronization Mechanism
Maven = Build & Dependency Management
Selenium Grid = Remote / Parallel Browser Execution
104. Real-Time Framework Relationship
Test Automation Framework
|
+-----------+-----------+
| |
Tests Pages
| |
TestNG Page Objects
|
Page Factory
|
@FindBy
|
WebElements
|
WebDriver
|
Browser
|
Application
105. Summary
Page Factory is a Selenium-supported approach commonly used with Page Object Model classes to declare and initialize web elements through annotations such as @FindBy. The central initialization statement is PageFactory.initElements(driver, this).
Page Factory helps make page classes more declarative and readable, but it does not replace good automation architecture, stable locators, synchronization, assertions, test-data management, reporting, logging, or framework design.
For real-world Selenium automation, Page Factory should be understood as one possible page-object implementation style. A strong automation engineer should also understand direct By-based page objects, explicit waits, TestNG, data-driven testing, framework architecture, reporting, Grid, and CI/CD.
106. Course Resources
Learn more through the Selenium Training course, which covers Selenium WebDriver, TestNG, Page Object Model, automation frameworks, data-driven testing, reporting, debugging, Grid, and related automation concepts. :contentReference[oaicite:5]{index=5}
To enquire about the course and training options, use Register for Course Demo.
107. One-Line Revision
Page Factory is an annotation-based Selenium approach commonly used inside Page Object classes to declare and initialize WebElements using mechanisms such as @FindBy and PageFactory.initElements().
108. Final Learning Formula
Page Factory
=
@FindBy
+
WebElement
+
PageFactory.initElements()
+
Page Object Model
+
Reusable Page Methods
+
Proper Synchronization
+
TestNG
+
Framework Architecture