Careeroza
PageFactory vs By Fields
PageFactory and @FindBy
Selenium also ships PageFactory, which fills WebElement fields annotated with @FindBy. You will see it in many older company frameworks.
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 {
@FindBy(id = "email") private WebElement email;
@FindBy(id = "password") private WebElement password;
@FindBy(id = "login-btn") private WebElement loginButton;
@FindBy(css = ".product-card") private List<WebElement> productCards;
public LoginPage(WebDriver driver) {
PageFactory.initElements(driver, this); // creates lazy proxies for every @FindBy field
}
public void loginAs(String user, String pwd) {
email.sendKeys(user);
password.sendKeys(pwd);
loginButton.click();
}
}Which One to Use
By fields | PageFactory @FindBy | |
|---|---|---|
| Element lookup | when the method runs | lazy proxy, looked up on each use |
| Works with explicit waits | directly: wait.until(visibilityOfElementLocated(email)) | needs visibilityOf(element); harder with dynamic pages |
| Dynamic locators | easy: By.xpath("//a[text()='" + name + "']") | not possible (annotation values are constants) |
| StaleElementReferenceException | rare (fresh lookup each time) | possible with @CacheLookup |
| Selenium team view | recommended | still supported, not recommended for new code |
Note: Interviewers often ask "PageFactory or POM?". Answer: POM is the pattern; PageFactory is just one way to initialise elements inside page objects. New frameworks usually use By fields with explicit waits.
Practice
Exercise: Convert this PageFactory field into a By field and a method that waits for it: @FindBy(id = "cart-count") WebElement cartCount;
Show answer
private final By cartCount = By.id("cart-count");
public String cartCount() {
return new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.visibilityOfElementLocated(cartCount))
.getText();
}