Page Object Model: cómo escribir automatización que sobreviva a un rediseño
El patrón que separa qué se prueba de cómo se pulsa, con los errores habituales al aplicarlo y cuándo conviene dar el salto a un modelo de tareas tipo Screenplay.
El síntoma que lo justifica
Hay una anécdota que se repite en todas las organizaciones que automatizan sin arquitectura: alguien cambia el formulario de acceso y hay que modificar ciento ochenta scripts. Ese es el momento en que se descubre, tarde, que los detalles de la interfaz estaban copiados en cada prueba.
El Page Object Model resuelve exactamente eso. Cada pantalla —o cada componente reutilizable— se encapsula en una clase que expone acciones con lenguaje de negocio y guarda dentro los localizadores y las esperas. Si cambia la interfaz, se corrige en un único sitio.
Cómo se ve la diferencia
Sin abstracción
await page.fill('#user_email_input', 'ana@example.com');
await page.fill('#user_pwd_input', 'secreto');
await page.click('.btn-primary.submit-lg');
await page.waitForTimeout(3000);
expect(await page.textContent('.dashboard-greeting')).toContain('Ana');Con Page Object
const login = new LoginPage(page);
const dashboard = await login.iniciarSesionComo(usuarios.ana);
await expect(dashboard.saludo()).toHaveText('Hola, Ana');La segunda versión no es más corta por gusto estético: es que el caso de prueba ya no sabe nada de selectores ni de esperas. Se lee como una especificación y, cuando falla, el mensaje habla del negocio y no del DOM.
Reglas que evitan que el patrón se degrade
- El objeto de página expone acciones y consultas de negocio ("iniciar sesión", "saldo mostrado"), no métodos que reproducen clics uno a uno.
- Las aserciones viven en el test, no dentro del objeto de página: si el objeto afirma, deja de ser reutilizable.
- Nada de esperas fijas. La espera es responsabilidad del objeto de página y debe ser explícita, basada en una condición observable.
- Los localizadores se declaran en un solo lugar y usan atributos pensados para pruebas, acordados con desarrollo, en lugar de rutas posicionales del DOM.
- Una acción que navega a otra pantalla devuelve el objeto de esa pantalla: así el flujo del test se lee sin ambigüedad.
- Los datos de prueba se construyen con factorías o builders, no se incrustan en el objeto de página.
Los límites del patrón
Con suites grandes, el POM tiende a producir clases enormes que acumulan todo lo que se puede hacer en una pantalla, y flujos que atraviesan seis pantallas se convierten en cadenas difíciles de reutilizar. Ahí entra el modelo de tareas, popularizado como Screenplay: en lugar de pantallas con métodos, se modelan actores que ejecutan tareas y hacen preguntas. La unidad de reutilización pasa a ser la tarea de negocio, que es la que de verdad se repite entre pruebas.
No es una migración obligatoria. Con una suite de cincuenta pruebas, el POM bien aplicado es suficiente y más fácil de enseñar al equipo. Con quinientas y varios equipos compartiendo componentes, el modelo de tareas se paga.
Y el punto que se olvida: los wrappers de la herramienta
El POM te protege de los cambios del producto. No te protege de los cambios de la herramienta. Si cada objeto de página llama directamente a la API de tu librería de automatización, una migración futura te obliga a tocar toda la suite.
La solución es una capa propia delgada —lo que el syllabus del CTAL-TAE llama capa de adaptación— que envuelva las operaciones que realmente usas: abrir, escribir, pulsar, esperar condición, leer texto. Es media tarde de trabajo y convierte un cambio de herramienta en un problema localizado en lugar de un proyecto.