Un test que falla porque el equipo de frontend cambió el texto de un botón no es un fallo de tu aplicación. Es un fallo en cómo escribiste el test.
Si tienes 40 tests de Playwright y el selector de ese botón está copiado en 14 archivos distintos, un cambio puramente visual rompe 14 tests a la vez, aunque la funcionalidad no haya cambiado en nada. Eso no es un problema de testing, es un problema de arquitectura.
El patrón que resuelve esto se llama Page Object Model (POM) y es, con diferencia, el primer paso serio hacia un framework de automatización mantenible. Si ya diste el salto y escribiste tu primer test automatizado con Playwright, este es el siguiente escalón: dejar de escribir tests que se rompen solos.
Qué es el Page Object Model
Page Object Model es un patrón de diseño para tests automatizados. Cada pantalla, o cada componente reutilizable (un header, un modal de cookies, un formulario que aparece en varias páginas), se representa con una clase.
Esa clase guarda dos cosas: los selectores de los elementos de esa pantalla y los métodos para interactuar con ellos. El test deja de hablar con el DOM directamente y empieza a hablar con la clase.
No es un patrón nuevo ni exclusivo de Playwright. Nació en el ecosistema de Selenium hace más de una década y se ha convertido en el estándar de facto en prácticamente cualquier framework de automatización basado en navegador, incluidos Cypress y Playwright.
- El selector del botón de login está copiado en 14 archivos de test
- El frontend cambia el texto del botón y rompe los 14 a la vez
- Cada test repite desde cero la lógica de rellenar usuario y contraseña
Actualizas LoginPage.js una vez. Los 14 tests vuelven a pasar.
Cómo estructurar las carpetas de un proyecto con POM
La estructura más habitual separa los Page Objects (las clases que describen cada pantalla) de los specs (los archivos con los tests propiamente dichos):
tests/
pages/
LoginPage.js
CheckoutPage.js
specs/
login.spec.js
checkout.spec.js
playwright.config.jsLa carpeta pages/ es la única que conoce la estructura real del HTML. Si el equipo de frontend cambia un selector, el cambio se hace en un solo archivo dentro de pages/, nunca dentro de specs/.
Un Page Object real, paso a paso
Así se ve la clase que describe una pantalla de login. Guarda los selectores en el constructor y expone métodos con nombres que describen una acción, no un clic suelto:
class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.getByLabel('Correo electronico');
this.passwordInput = page.getByLabel('Contrasena');
this.submitButton = page.getByRole('button', { name: 'Entrar' });
}
async goto() {
await this.page.goto('https://miapp.com/login');
}
async login(email, password) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}
module.exports = { LoginPage };Y así se ve el test que la usa. Fíjate en lo que falta: ni un solo selector, ni una sola referencia al DOM.
const { test, expect } = require('@playwright/test');
const { LoginPage } = require('../pages/LoginPage');
test('el login funciona con credenciales validas', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('usuario@example.com', 'password123');
await expect(page.getByText('Bienvenido')).toBeVisible();
});El test lee como una descripción del comportamiento: entra, haz login, comprueba que aparece el mensaje de bienvenida. Nada de page.locator('.css-3xk21 > button') perdido en medio de la lógica.
El Page Object esconde los selectores de la pantalla. El test nunca toca un selector directamente, solo llama a métodos.
Las comprobaciones (expect) viven en el test, no en el Page Object. La clase describe la pantalla, no decide si algo está bien.
Cada Page Object representa una pantalla o un componente reutilizable, nunca la aplicación entera metida en una sola clase.
Errores comunes al aplicar Page Object Model
El patrón es sencillo de explicar, pero hay cuatro formas de aplicarlo mal que aparecen una y otra vez:
- Meter aserciones dentro del Page Object. Un método como
loginYComprobarBienvenida()acopla la clase a un escenario concreto. Deja de servir para el test que quiere comprobar un login fallido. - Un "God Object" que representa toda la aplicación. Cuando un único
AppPage.jscrece hasta las 600 líneas y nadie quiere tocarlo, ya no cumple su función: divídelo por pantalla o por componente. - Duplicar selectores entre Page Objects en vez de componer. Si el header aparece en diez pantallas, crea una clase
Header.jsaparte y reutilízala, no la copies diez veces. - Métodos pensados para un solo test. Un Page Object describe lo que se puede hacer en una pantalla, no los pasos exactos de un test concreto. Si solo lo usa un test, probablemente no debería vivir en el Page Object.
En el curso de automatización avanzada, el error que más veces corregimos no es de sintaxis: es gente que mete un expect() dentro del método del Page Object. El test sigue pasando, pero la clase deja de ser reutilizable en cuanto otro escenario necesita el mismo flujo sin esa comprobación concreta.
Cuándo no conviene montar Page Object Model
No todo proyecto necesita esta estructura desde el primer test. Vale la pena ser honesto sobre cuándo es overhead, no solución:
- Para dos o tres tests de humo que vas a usar un día y tirar, montar carpetas de
pages/yspecs/es más trabajo del que ahorra. - Si el proyecto no va a crecer más allá de una docena de tests y lo mantiene una sola persona, un archivo plano bien organizado es más rápido de leer.
- Si el framework ya resuelve el problema de otra forma. Cypress, por ejemplo, combina a menudo el patrón con comandos personalizados en
cypress/support/commands, que cumplen un papel parecido sin montar clases completas.
De aquí a un framework completo
Page Object Model resuelve el problema de los selectores duplicados, pero es solo una pieza. Un framework de automatización maduro añade fixtures para preparar datos antes de cada test, y un pipeline de CI/CD para que la suite corra sola en cada cambio de código, sin que nadie tenga que acordarse de lanzarla a mano.
Ese es el recorrido completo que separa "sé escribir un test" de "puedo construir y mantener un framework de automatización". No hace falta llegar ahí en un día: Page Object Model es, de las tres piezas, la que más rápido cambia cómo se ve tu código.
Preguntas frecuentes
¿Qué es el Page Object Model en testing?
Es un patrón de diseño para tests automatizados en el que cada pantalla (o componente reutilizable) de la aplicación se representa con una clase. Esa clase guarda los selectores y los métodos para interactuar con esa pantalla, y el test deja de hablar con el DOM directamente para hablar con la clase.
¿Cuándo debería empezar a usar Page Object Model en mis tests?
En cuanto tu suite pase de 4 o 5 tests, o en cuanto notes que el mismo selector aparece copiado en más de un archivo. Para dos o tres tests de humo que vas a usar un día y tirar, montar la estructura completa es sobrecarga innecesaria.
¿Se puede usar Page Object Model con Cypress o Selenium, no solo con Playwright?
Sí. El patrón nació en el ecosistema de Selenium y es independiente del framework: solo necesitas una clase (o un objeto, en frameworks menos orientados a objetos) por pantalla. Cypress lo combina a menudo con comandos personalizados en cypress/support/commands, que cumplen un papel parecido.
¿Los Page Objects deberían incluir aserciones (expect)?
No, salvo excepciones puntuales muy justificadas. La aserción decide si el test pasa o falla, y esa decisión pertenece al test, no a la clase que describe la pantalla. Meter expect() dentro del Page Object acopla la clase a un escenario concreto y la hace menos reutilizable.
¿Qué diferencia hay entre Page Object Model y Screenplay Pattern?
Page Object Model organiza el código por pantalla. Screenplay Pattern (más habitual en proyectos Java grandes) organiza el código por actor y tarea, pensado para equipos con suites muy complejas. Para la gran mayoría de proyectos QA, Page Object Model es suficiente y mucho más fácil de aprender.
¿Dónde se aprende a estructurar un framework de automatización completo?
El curso de automatización avanzada de 17lab cubre Page Object Model, fixtures y CI/CD sobre un proyecto real con Playwright, Cypress y pytest. Si todavía no has escrito tu primer test automatizado, el curso de automatización QA es el paso anterior.
¿Quieres entrar al sector?
Aprende QA desde cero, con formación práctica y orientada al mercado español.