S08.2 - Page Object y Page Factory
Sin Page Object¶
Se buscan los campos con driver.findElement(By.) y se ejecutan las acciones de manera directa en el mismo driver.
private WebDriver driver;
// Mis credenciales del test de creación
private static final String EXISTING_EMAIL = "iguijarrolillo2@mail.com";
private static final String EXISTING_PASSWORD = "Hjxpk1932..";
@BeforeEach
public void setup() {
driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.get("http://demo.magento.recolize.com");
Dimension dimension = new Dimension(1500, 1000);
driver.manage().window().setSize(dimension);
}
@Tag("R2R3")
public void R2_requirement_loginOK_should_login_with_success_when_user_account_exists() throws InterruptedException {
// 1. Verificar título de la home
assertEquals("Madison Island", driver.getTitle());
// 2. Abrir menú Account → Login
driver.findElement(By.cssSelector("#header > div > div.skip-links > div > a")).click();
driver.findElement(By.cssSelector("#header-account > div > ul > li.last > a")).click();
// 3. Verificar título de la página de login
assertEquals("Customer Login", driver.getTitle());
// 4. Rellenar el email y enviar sin password
driver.findElement(By.id("email")).sendKeys(EXISTING_EMAIL);
Thread.sleep(500);
driver.findElement(By.cssSelector("button[title='Login']")).click();
// 5. Verificar mensaje de campo requerido en contraseña
WebElement errorPass = driver.findElement(
By.cssSelector("#advice-required-entry-pass")
);
assertEquals("This is a required field.", errorPass.getText());
// 6. Rellenar la contraseña y volver a enviar
driver.findElement(By.id("pass")).sendKeys(EXISTING_PASSWORD);
Thread.sleep(500);
driver.findElement(By.cssSelector("button[title='Login']")).click();
Thread.sleep(500);
// 7. Verificar que estamos en "My Account" y mensaje de bienvenida
assertEquals("My Account", driver.getTitle());
WebElement welcome = driver.findElement(By.cssSelector("p.hello"));
assertTrue(
welcome.getText().startsWith("Hello,"),
"Debe mostrar mensaje de bienvenida con 'Hello,'"
);
}
Page Object¶
El método Page Object se basa en delegar y separar la creación de objetos y acceso a los campos de la web, a clases que representan una página completa de la web.
Este acceso se realiza mediante funciones que llaman a los selectores correspondientes.
@Test
public void R4_requierement_PO_loginOK_should_login_with_success_when_user_account_exists() {
HomePage home = new HomePage(driver);
home.clickAccount();
CustomerLoginPage login = home.clickLogin();
// Paso 4: solo email
login.enterEmail(EXISTING_EMAIL);
// Paso 6: contraseña y submit
login.enterPassword(EXISTING_PASSWORD);
MyAccountPage account = login.clickLoginButton();
// Paso 7: verificaciones
assertEquals("My Account", account.getTitle());
}
public class HomePage {
private final WebDriver driver;
private final By accountMenu = By.cssSelector("#header > div > div.skip-links > div > a");
private final By loginLink = By.cssSelector("#header-account > div > ul > li.last > a");
public HomePage(WebDriver driver) {
this.driver = driver;
}
// Abre el menú “Account”
public void clickAccount() {
driver.findElement(accountMenu).click();
}
// Hace click en “Log In” y devuelve la página de login
public CustomerLoginPage clickLogin() {
driver.findElement(loginLink).click();
return new CustomerLoginPage(driver);
}
}
Page Object + Page Factory¶
Con el patrón Page Factory, en lugar de instanciar Los objetos Page Object directamente se delega a la Page Factory usando una función PageFactory.initElements(driver, Clase.class);
De esta manera se crea el objeto Page Object y se inicializan los @FindBy para no tener que instanciarlos con .findElements(). Pero es obligatorio que en la clase instanciada se defina un constructor por defecto:
public MyAccountPage(WebDriver driver) {
this.driver = driver;
}
Esto inicializa los @FindBy y prepara el Page Object para ejecutar las acciones sobre la página.
@Test
public void R6_requirement_PO_compareShoes_should_clear_comparison_when_TwoShoes_are_compared_and_cleared() {
// 1. MyAccountPage
MyAccountPage acct = PageFactory.initElements(driver, MyAccountPage.class);
assertEquals("My Account", acct.getTitle());
// 2–3. Hover Accessories -> Shoes
ShoesPage shoes = acct.goToShoes();
assertEquals("Shoes - Accessories", shoes.getTitle());
// 4. Seleccionamos los dos últimos zapatos
shoes.selectShoeToCompare(5);
shoes.selectShoeToCompare(6);
// 5–6. Pulsar COMPARE y cambio a ventana hija
ProductComparisonPage comp = shoes.clickCompare();
assertTrue(comp.getTitle().contains("Products Comparison List"));
// 7–8. Cerrar ventana comparativa y volver a ShoesPage
shoes = comp.closeComparison();
assertEquals("Shoes - Accessories", shoes.getTitle());
// 9. Clear All y leer alerta
String alertText = shoes.clearComparisonAlert();
assertEquals(
"Do you like to remove all products from your comparison?",
alertText
);
// 10. Mensaje final
String clearedMsg = shoes.getClearedMessage();
assertTrue(
clearedMsg.contains("the comparison list was cleared"),
"Debe mostrar mensaje de lista vaciada"
);
}
public class MyAccountPage {
private final WebDriver driver;
@FindBy(xpath = "//a[normalize-space()='Accessories']") WebElement accessoriesMenu;
public MyAccountPage(WebDriver driver) {
this.driver = driver;
}
/** Título de la página */
public String getTitle() {
return driver.getTitle();
}
/** Hover → devuelve la PO de Shoes */
public ShoesPage goToShoes() {
new Actions(driver).moveToElement(accessoriesMenu).perform();
return PageFactory.initElements(driver, ShoesPage.class);
}
}
Lo normal es utilizar métodos como el goToShoes() en los que se ejecutan las acciones sobre el driver y luego se redirige a la siguiente página instanciando el PageFactory.initElements().