Playwright de principio a fin: guía completa de testing E2E
Playwright se ha convertido en el estándar de facto del testing E2E. Esta guía va más allá de la instalación: selectores que no se rompen, fixtures reutilizables y arquitectura de suite mantenible.
Instalar Playwright y grabar un test con el codegen lleva cinco minutos. Mantener una suite de cientos de tests E2E que no se rompa cada vez que alguien cambia una clase CSS es un problema de ingeniería completamente distinto. Esta guía asume que ya sabes lo primero y se centra en lo segundo: cómo escribir selectores que sobreviven a rediseños, cómo estructurar fixtures para no repetir setup, y cómo organizar una suite que crece sin volverse inmantenible.
Playwright, mantenido por Microsoft, se ha consolidado como la herramienta dominante de testing E2E: la encuesta State of JavaScript 2025 le otorgó el reconocimiento de herramienta “más adoptada” del año, con una diferencia de satisfacción frente a Cypress —su competidor histórico más cercano— más amplia que en ediciones anteriores. Publica una nueva versión aproximadamente cada seis semanas, lo que en la práctica significa que el proyecto evoluciona rápido y conviene revisar el changelog con cierta frecuencia.
Selectores: la causa número uno de suites frágiles
El error más habitual al empezar con Playwright es tratarlo como si fuera Selenium con mejor sintaxis: seleccionar por clases CSS o IDs generados automáticamente por el framework de turno. Ese tipo de selector se rompe en cuanto alguien toca el CSS o el bundler renombra una clase.
Playwright resuelve esto con locators basados en cómo un usuario real percibe la página, no en su implementación interna:
// Frágil: acoplado a la implementación
await page.locator('.btn.btn-primary.submit-btn-v2').click();
// Robusto: acoplado al rol semántico y al texto visible
await page.getByRole('button', { name: 'Enviar pedido' }).click();
El orden de preferencia recomendado por la propia documentación de Playwright es:
getByRole— el rol de accesibilidad ARIA y el nombre accesible. Es el más resistente a cambios visuales porque describe la función del elemento, no su apariencia.getByLabel— para campos de formulario, usando la etiqueta asociada.getByText— para contenido no interactivo identificado por su texto.getByTestId— un atributodata-testidexplícito, cuando ninguna de las anteriores es viable (por ejemplo, elementos sin semántica clara o textos que cambian con el idioma).
Los selectores CSS o XPath crudos quedan como último recurso, reservados para casos que de verdad no tienen alternativa semántica.
Auto-waiting: por qué (casi) nunca deberías necesitar un sleep
Una de las señales más claras de un test E2E mal escrito es un page.waitForTimeout(2000) metido a modo de parche. Playwright fue diseñado explícitamente para eliminar esa necesidad: antes de ejecutar una acción (click, fill, check…), comprueba una serie de condiciones de “accionabilidad” —que el elemento esté adjunto al DOM, visible, estable (sin animaciones en curso), que reciba eventos sin estar tapado por otro elemento, y que esté habilitado— y reintenta automáticamente hasta que se cumplen o hasta agotar el timeout configurado.
Esto no significa que las esperas explícitas desaparezcan del todo. Siguen siendo necesarias cuando esperas un estado que no es una acción sobre un elemento, como una respuesta de red concreta o un cambio de URL:
// Esperar una navegación tras una acción
await Promise.all([
page.waitForURL('**/checkout/confirmacion'),
page.getByRole('button', { name: 'Confirmar pago' }).click(),
]);
// Esperar una respuesta de red específica, no un tiempo arbitrario
await Promise.all([
page.waitForResponse((res) => res.url().includes('/api/pedidos') && res.ok()),
page.getByRole('button', { name: 'Enviar pedido' }).click(),
]);
El patrón común a ambos ejemplos es esperar por un evento verificable, no por un número de milisegundos que funcionó “la mayoría de las veces” en tu máquina.
Fixtures: la pieza que evita la duplicación de setup
Casi todo test E2E necesita algún estado previo: un usuario autenticado, datos de prueba en la base de datos, una página ya abierta en una ruta concreta. Repetir ese setup en cada test es la forma más rápida de acabar con una suite ilegible. Las fixtures de Playwright Test resuelven esto extendiendo el objeto test con dependencias inyectables y reutilizables:
// fixtures.ts
import { test as base, expect } from '@playwright/test';
type MisFixtures = {
usuarioAutenticado: { email: string; token: string };
};
export const test = base.extend<MisFixtures>({
usuarioAutenticado: async ({ page, request }, use) => {
const respuesta = await request.post('/api/auth/login', {
data: { email: '[email protected]', password: 'test-password' },
});
const { token } = await respuesta.json();
await page.addInitScript((t) => {
window.localStorage.setItem('auth_token', t);
}, token);
await use({ email: '[email protected]', token });
},
});
export { expect };
// checkout.spec.ts
import { test, expect } from './fixtures';
test('un usuario autenticado puede completar el checkout', async ({ page, usuarioAutenticado }) => {
await page.goto('/checkout');
await expect(page.getByText(usuarioAutenticado.email)).toBeVisible();
});
La ventaja frente a un beforeEach tradicional es que las fixtures son composables y perezosas: solo se ejecutan si el test las declara como dependencia, y Playwright gestiona su ciclo de vida (setup y teardown) de forma automática. Un test que no necesita autenticación no paga el coste de ese login.
Testing multi-navegador: cuándo importa de verdad
Playwright ejecuta la misma suite contra los motores Chromium, Firefox y WebKit sin cambiar una línea de código de test, lo que en teoría cubre el equivalente a Chrome/Edge, Firefox y Safari. En la práctica, no todos los proyectos necesitan ejecutar toda la suite en los tres motores en cada pipeline:
- Si tu tráfico real es abrumadoramente Chromium (Chrome + Edge), ejecutar el 100% de la suite en los tres motores en cada commit puede ser un gasto de CI que no se traduce en bugs encontrados.
- Un patrón razonable: ejecutar la suite completa en Chromium en cada PR, y reservar Firefox/WebKit para una ejecución nocturna o previa a release, salvo que el proyecto tenga una base de usuarios de Safari/iOS significativa —en cuyo caso WebKit merece la misma prioridad que Chromium, porque WebKit es el motor que más discrepancias reales suele revelar frente a Chromium.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});
Estructurando una suite que no se pudra con el tiempo
Los problemas de mantenibilidad casi nunca aparecen con 10 tests. Aparecen a partir de 100, cuando la duplicación y el acoplamiento a la UI empiezan a multiplicar el coste de cada cambio de diseño. Algunas decisiones estructurales que marcan la diferencia:
- Page Objects o Component Objects, con moderación. Encapsular las interacciones con una pantalla o componente en una clase reduce la duplicación cuando un selector cambia, pero un Page Object gigantesco con cien métodos es tan difícil de mantener como los selectores sueltos que pretendía evitar. Mantenlos pequeños y centrados en una responsabilidad.
- Datos de prueba aislados por test, no compartidos entre ellos. Un test que depende del orden de ejecución o del estado dejado por otro test anterior es una bomba de relojería en CI paralelo. Playwright ejecuta tests en paralelo por defecto: si tus tests comparten estado mutable, vas a tener fallos intermitentes (flaky) difíciles de depurar.
- Separar tests de humo (smoke) de la suite de regresión completa. No todos los tests necesitan ejecutarse en cada PR. Una suite de smoke pequeña y rápida da feedback en minutos; la suite completa puede vivir en un pipeline separado.
- Usar
test.step()para hacer legibles los reportes, especialmente en tests largos con múltiples fases, y aprovechar el trace viewer (npx playwright show-trace) como primera herramienta de depuración ante un fallo en CI, en vez de intentar reproducirlo a ciegas en local.
Testing con IA dentro del propio Playwright
Desde 2025, Playwright integra un servidor MCP oficial y, más recientemente, agentes de test (planificador, generador y reparador) que operan sobre el árbol de accesibilidad de la página en vez de sobre capturas de pantalla. Esto permite generar y reparar tests a partir de descripciones en lenguaje natural, apoyándose en los mismos locators robustos que recomienda esta guía. Es una capacidad con matices importantes sobre cuánta confianza depositar en ella sin supervisión, que tratamos en detalle en testing con IA: generación de tests y self-healing locators, hasta dónde confiar.
Dónde encaja Playwright en tu estrategia de testing
Playwright resuelve la capa E2E, pero una suite E2E completa no sustituye a los tests unitarios ni a los de integración: sustituye a la parte de la pirámide que específicamente valida flujos de usuario reales de principio a fin. Si tu proyecto también usa Vitest para testing unitario, lo habitual es que ambas herramientas convivan sin fricción, cada una en la capa que le corresponde. Qué proporción de esfuerzo dedicar a cada capa es una pregunta que merece su propio análisis, sobre todo ahora que las herramientas E2E son mucho más rápidas de lo que eran hace unos años — lo desarrollamos en la pirámide de testing en 2026: ¿sigue teniendo sentido?
Artículos relacionados
La pirámide de testing en 2026: ¿sigue teniendo sentido?
Unit en la base, poco E2E arriba: el modelo lleva más de una década repitiéndose sin cuestionarlo. Con herramientas E2E mucho más rápidas que en 2009, revisamos si la proporción clásica sigue siendo la correcta.
Mutation testing: la técnica que revela tests que no prueban nada
Un test puede pasar, tener cobertura del 100% y no detectar nada si el código se rompe. Mutation testing introduce bugs deliberados para comprobarlo. Así funciona en el ecosistema JavaScript y TypeScript.
Testing con IA: generación de tests y self-healing locators, hasta dónde confiar
Los agentes de IA ya generan y reparan tests de Playwright solos. Analizamos qué hacen de verdad, qué benchmarks dicen sobre su fiabilidad y cómo evitar que una suite verde deje de significar algo.