Skip to content

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().