Cambias un margen en el CSS de un componente y el test funcional sigue en verde. El botón sigue existiendo, sigue siendo clicable, la aserción expect(page.getByRole('button')).toBeVisible() no falla. Pero en producción ese botón queda medio tapado por otro elemento en móvil, y nadie se entera hasta que un usuario se queja.
Eso es lo que el testing funcional no ve: los pixeles. Un test que comprueba que un elemento existe y responde a un click no comprueba dónde está, de qué tamaño es, ni si se solapa con otra cosa. Para eso existe el testing de regresión visual, y desde que Playwright lo trae integrado sin plugins de por medio, cada vez más suites de automatización lo incluyen como un matcher más (Playwright, documentación oficial, sección "Visual comparisons").
En este artículo vemos qué es exactamente, cómo montarlo con el comparador nativo de Playwright, por qué los falsos positivos son su problema número uno, y cuándo compensa (o no) pagar por una plataforma cloud en vez de usar lo que ya viene incluido.
Qué es el testing de regresión visual (y qué no)
El testing de regresión visual compara una captura de pantalla de tu interfaz contra una captura de referencia (el "baseline") y marca como fallo cualquier diferencia de pixeles que supere un umbral que tú defines. No lee el DOM, no ejecuta lógica de negocio, no comprueba que un endpoint responda. Solo mira si la interfaz se ve como se supone que debe verse.
Esto lo hace complementario al testing funcional, no un sustituto. Un test funcional te dice que el flujo de compra completa el pago. Un test de regresión visual te dice que el botón de "Pagar" no se ha quedado oculto detrás del footer en la versión móvil, algo que ningún toBeVisible() detecta si el elemento sigue técnicamente presente en el DOM, solo que solapado por otro.
- Que el elemento existe en el DOM
- Que responde a un click o a una entrada de texto
- Que el texto o valor devuelto es el esperado
- Que la petición a la API sale y vuelve bien
Que el elemento se ve donde debe verse, del tamaño que debe tener, sin solaparse con nada.
Cómo funciona toHaveScreenshot en Playwright
Playwright trae el comparador visual integrado en su propio test runner, sin instalar nada aparte. El matcher se llama toHaveScreenshot() y se usa así:
const { test, expect } = require('@playwright/test');
test('la home no cambia visualmente', async ({ page }) => {
await page.goto('https://17lab.pro');
await expect(page).toHaveScreenshot('home.png', {
maxDiffPixelRatio: 0.02,
animations: 'disabled',
});
});La primera vez que ejecutas este test, Playwright no tiene nada con qué comparar, así que necesita generar la captura y guardarla como referencia con el flag --update-snapshots. A partir de la segunda ejecución, compara pixel a pixel la nueva captura contra esa referencia y falla si la diferencia supera el umbral configurado (Playwright, documentación oficial, "Visual comparisons").
La primera vez que montamos esto en un proyecto propio, el test falló en la primera ejecución porque no existía el baseline. No es un bug: hay que correr una vez en modo "actualizar snapshots" antes de que el test sirva para algo.
Dos opciones controlan cuánta diferencia se tolera antes de marcar un fallo: maxDiffPixelRatio (el porcentaje de pixeles distintos permitido sobre el total) y threshold (la sensibilidad de cada pixel individual). La opción animations: 'disabled' evita que una transición CSS a medio ejecutar arruine la comparación.
El problema real: los falsos positivos
Aquí está la parte que nadie cuenta la primera vez que lee la documentación: el testing visual falla constantemente por motivos que no son bugs.
La causa más común es el renderizado distinto entre sistemas operativos y navegadores. La misma página, en el mismo navegador, puede renderizarse con un anti-aliasing de fuente ligeramente distinto según el sistema operativo, la resolución de pantalla o si la aceleración por GPU está activada, y esa diferencia (invisible para un ojo humano) puede disparar un fallo en una comparación pixel a pixel.
Otras causas típicas: contenido dinámico (fechas, contadores, avatares que cambian entre ejecuciones) y animaciones capturadas a medio recorrido.
- Ejecuta siempre en el mismo entorno. Corre los tests en Docker o en el mismo runner de CI donde generaste el baseline, nunca en tu propio portátil.
- Desactiva animaciones. La opción
animations: 'disabled'evita capturar una transición a medio camino. - Enmascara el contenido dinámico. La opción
maskde Playwright sustituye por un recuadro los elementos que cambian entre ejecuciones, y la comparación ignora esa zona por completo. - Ajusta el umbral, no lo desactives. Un
maxDiffPixelRatiodemasiado bajo genera ruido constante, uno demasiado alto deja pasar bugs reales. Se calibra probando en el propio proyecto.
Playwright nativo o plataformas cloud: Percy, Applitools, Chromatic
Playwright resuelve el caso básico gratis y sin dependencias, pero el mercado de testing visual se ha dividido en dos categorías: las librerías nativas de cada framework (Playwright, Cypress, BackstopJS) y las plataformas cloud con diffing asistido por IA (Percy, Applitools, Chromatic), pensadas para filtrar automáticamente el tipo de ruido de renderizado que comentábamos antes.
| Herramienta | Coste | Punto fuerte |
|---|---|---|
| Playwright (nativo) | Incluido, sin coste extra | Cero dependencias nuevas si ya automatizas con Playwright |
| Percy (BrowserStack) | Gratis hasta 5.000 capturas al mes | Integración sencilla con los frameworks de test más usados |
| Applitools Eyes | De pago | IA visual que compara estructura de página, no solo pixeles, para reducir falsos positivos |
| Chromatic | De pago, con capa gratuita | Pensado para equipos que ya construyen su interfaz en Storybook |
Fuentes: documentación oficial de Playwright y blog oficial de Percy (2026).
Cuándo compensa montarlo (y cuándo no)
Honestidad primero: si tu proyecto es pequeño, con poco diseño visual complejo, y cambias más la lógica que la interfaz, montar regresión visual es sobrecoste. Mantener el baseline (actualizarlo cada vez que cambias algo a propósito) tiene un coste real de tiempo que hay que sumar al del propio test.
Donde sí compensa: sistemas de diseño con muchos componentes reutilizados, páginas de checkout o pago donde un pixel movido cuesta dinero, y cualquier proyecto donde el equipo de diseño revisa los cambios visuales antes de publicar. Ahí, un fallo de regresión visual en CI ahorra una ronda entera de revisión manual.
Si ya usas Playwright para tu suite de automatización, algo que trabajamos con ejercicios reales en el módulo de Playwright de nuestro curso de automatización avanzada, añadir regresión visual no cuesta instalar nada nuevo: es la misma herramienta, un matcher más.
Preguntas frecuentes
¿El testing de regresión visual sustituye al testing funcional?
No. Comprueban cosas distintas: el funcional verifica que la lógica y las interacciones funcionan, el visual verifica que el resultado se ve como debe verse. Se usan juntos, no uno en vez del otro.
¿Necesito instalar algo aparte para hacer testing visual con Playwright?
No. El matcher toHaveScreenshot() viene incluido en @playwright/test, sin plugins ni dependencias adicionales.
¿Por qué me falla el test si no he cambiado nada en el código?
Casi siempre es un falso positivo por renderizado: anti-aliasing distinto entre máquinas, una animación capturada a medio camino, o contenido dinámico como una fecha o un avatar que cambia entre ejecuciones. La solución es correr siempre en el mismo entorno (Docker o el mismo runner de CI) y enmascarar el contenido dinámico con la opción mask.
¿Compensa pagar por Percy o Applitools en vez de usar solo Playwright?
Depende del volumen y del equipo. Playwright resuelve el caso básico gratis. Las plataformas cloud aportan un diffing más tolerante al ruido visual y una interfaz para que el equipo de diseño revise los cambios sin tocar código, algo que compensa en equipos grandes con muchos componentes visuales, no en un proyecto pequeño.
¿Cómo genero la primera captura de referencia?
Ejecutando el test con el flag --update-snapshots (npx playwright test --update-snapshots). Esa primera ejecución no compara nada, solo guarda la captura como baseline para las siguientes.
¿Quieres dominar la automatización con Playwright?
Aprende a montar suites de automatización reales, desde el primer test hasta patrones avanzados como este.