Selenium has a built-in PageFactory that uses @FindBy annotations to declare elements. It looks cleaner but has a critical flaw. Let us compare both approaches and understand why most modern frameworks avoid PageFactory.
// Regular POM — finds elements FRESH each time
public class LoginPage extends BasePage {
private By usernameField = By.id("username");
private By passwordField = By.id("password");
private By loginButton = By.cssSelector("button[type='submit']");
public LoginPage(WebDriver driver) {
super(driver);
}
public void enterUsername(String username) {
type(usernameField, username); // Finds element NOW
}
}import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPageFactory {
private WebDriver driver;
@FindBy(id = "username")
private WebElement usernameField;
@FindBy(id = "password")
private WebElement passwordField;
@FindBy(css = "button[type='submit']")
private WebElement loginButton;
public LoginPageFactory(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this); // Initialize all @FindBy
}
public void enterUsername(String username) {
usernameField.clear();
usernameField.sendKeys(username); // Uses cached reference
}
}| Regular POM (Recommended) | PageFactory (@FindBy) |
|---|---|
| Elements found FRESH each time a method is called | Elements initialized ONCE via initElements() |
| No StaleElementReferenceException risk | Risk of StaleElementReferenceException if DOM changes |
| More reliable with dynamic pages and SPAs | Can fail on dynamic pages that re-render |
| Easier to debug — clear findElement calls | Less boilerplate — cleaner annotation syntax |
| Industry recommendation — most modern frameworks use this | Falling out of favor in the industry |
PageFactory caches element references. If the DOM changes after initialization (common in React/Angular apps), you get StaleElementReferenceException. The By-based approach finds elements fresh every time, avoiding this problem entirely. Use the By-based approach for new projects.
Q: What is the difference between PageFactory and regular POM?
A: Regular POM uses By locators and finds elements fresh each time a method is called. PageFactory uses @FindBy annotations and caches WebElement references after initElements(). The problem with PageFactory: if the DOM changes after initialization (common in modern single-page apps), cached references become stale and throw StaleElementReferenceException. The By-based approach is more reliable and is the industry standard for modern frameworks. I use the By-based approach because it works consistently with dynamic pages.
Key Point: Prefer By-based POM over PageFactory. PageFactory caches elements and can cause StaleElementReferenceException on dynamic pages.