Lección 3 de 412 min
Pruebas end-to-end: Playwright, Cypress y Selenium
Automatizar un navegador real para probar la aplicación como lo haría una persona, sin pruebas inestables.
Todas las pruebas unitarias pasan y los componentes funcionan por separado… y aun así nadie puede pagar, porque el frontend envía el importe en céntimos y el backend lo espera en euros. Ese tipo de error solo aparece cuando pruebas la aplicación entera, como lo haría un cliente.
Las pruebas end-to-end (E2E) automatizan un navegador real que recorre la aplicación de punta a punta. En esta lección verás cuándo merecen la pena, en qué se diferencian Playwright, Cypress y Selenium y cómo evitar el gran problema de este tipo de pruebas: la inestabilidad.
Probar la aplicación entera
Qué es una prueba end-to-end
Un navegador automatizado recorre la aplicación real, del clic a la base de datos.
Una prueba E2E arranca la aplicación completa (frontend, backend y base de datos) y la maneja a través de un navegador: abre la página, rellena el formulario, pulsa el botón y comprueba lo que aparece. Si pasa, sabes que todas las piezas encajan entre sí.
Son las pruebas que más confianza dan, pero también las más lentas, las más caras de mantener y las más difíciles de diagnosticar cuando fallan. Por eso ocupan la cima de la pirámide: pocas, y para los flujos críticos, como registrarse, iniciar sesión, comprar o pagar.
Úsalo cuando
Para los recorridos que no pueden fallar nunca y que cruzan varias partes del sistema. Suelen ejecutarse en el pipeline contra un entorno de pruebas, antes de desplegar a producción.
Ten en cuenta
Si intentas cubrir cada caso con E2E (cada mensaje de error, cada validación), el pipeline tardará una eternidad. Esas variaciones van en pruebas unitarias o de componentes.
Las herramientas
Las tres controlan navegadores reales, pero de formas distintas, y eso decide qué pueden hacer y lo cómodo que resulta depurarlas.
Playwright
El framework de Microsoft para Chromium, Firefox y WebKit, con esperas automáticas.
- Creado por:
- Microsoft
- Motores:
- Chromium, Firefox y WebKit
Playwright controla desde fuera los tres grandes motores de navegador, Chromium, Firefox y WebKit (el de Safari), con pruebas en TypeScript, JavaScript, Python, Java o .NET. Cada prueba recibe un contexto de navegador limpio y aislado, y los archivos de prueba se ejecutan en paralelo por defecto.
Su gran ventaja es el auto-waiting: antes de hacer clic, espera a que el elemento exista, sea visible y esté habilitado, y las aserciones como toBeVisible() se reintentan hasta que se cumplen. Sus locators (getByRole, getByLabel, getByText) siguen la misma filosofía que Testing Library.
Para depurar, el trace viewer guarda un registro de cada paso con capturas, red y consola, y codegen (npx playwright codegen) genera código mientras navegas. También maneja varias pestañas, varios dominios y descargas sin trucos.
Úsalo cuando
En proyectos nuevos, cuando necesitas probar en varios navegadores (incluido el motor de Safari) o flujos con varias pestañas o dominios.
Ten en cuenta
El WebKit de Playwright se parece mucho a Safari, pero no es Safari: para detalles muy concretos, prueba también en un dispositivo real. Y aunque espere solo, una prueba mal diseñada puede seguir siendo inestable.
import { test, expect } from "@playwright/test";
test("una persona puede comprar una taza", async ({ page }) => {
await page.goto("/tienda");
await page.getByRole("link", { name: "Taza de cerámica" }).click();
await page.getByRole("button", { name: "Añadir al carrito" }).click();
await page.getByRole("link", { name: "Carrito" }).click();
// Reintenta la comprobación hasta que se cumple (o se agota el tiempo)
await expect(page.getByText("Total: 12,00 €")).toBeVisible();
});Cypress
Pruebas que se ejecutan dentro del navegador, con viaje en el tiempo para depurar.
- Lenguajes:
- JavaScript y TypeScript
- Se ejecuta:
- dentro del navegador
Cypress ejecuta tus pruebas dentro del navegador, en el mismo bucle que tu aplicación. Eso le da acceso directo a la página y a la red: con cy.intercept() espías o falseas peticiones sin montar nada más. Los comandos (cy.get(), cy.contains(), .click()) se encadenan y se reintentan solos hasta que se cumple la condición.
Su punto fuerte es la experiencia de desarrollo: una ventana interactiva muestra la prueba en marcha y, gracias al viaje en el tiempo, puedes pasar el ratón por cada paso del registro de comandos y ver cómo estaba la página en ese momento. También permite pruebas de componentes.
Úsalo cuando
En aplicaciones web de una sola página, cuando el equipo valora mucho depurar de forma visual y escribe en JavaScript o TypeScript.
Ten en cuenta
Correr dentro del navegador tiene límites: no maneja varias pestañas y, para visitar otro dominio en la misma prueba, necesitas cy.origin(). Sus comandos no son promesas, así que no uses async ni await con ellos. Y la paralelización integrada se apoya en su servicio de pago, Cypress Cloud.
describe("carrito", () => {
it("añade un producto", () => {
// Respuesta falsa del servidor, para no depender del stock real
cy.intercept("GET", "/api/productos/7", { fixture: "taza.json" });
cy.visit("/productos/7");
cy.contains("button", "Añadir al carrito").click();
cy.get("[data-cy=contador-carrito]").should("have.text", "1");
});
});Selenium
El veterano del sector, basado en el estándar W3C WebDriver y disponible en muchos lenguajes.
- Desde:
- 2004
- Estándar:
- W3C WebDriver
Selenium automatiza navegadores desde 2004, y su protocolo, WebDriver, acabó convertido en estándar del W3C: cada navegador publica un driver que lo implementa. Por eso funciona con Chrome, Firefox, Edge y Safari, y tiene librerías oficiales para Java, Python, C#, Ruby y JavaScript.
Selenium Grid reparte las pruebas entre muchas máquinas y navegadores a la vez, y muchos servicios en la nube que ofrecen navegadores y dispositivos reales hablan WebDriver. Las versiones recientes descargan solas el driver adecuado para cada navegador.
Úsalo cuando
En equipos que escriben las pruebas en Java, C# o Python, en empresas con años de pruebas en Selenium o cuando necesitas una granja de navegadores con Grid.
Ten en cuenta
No espera por ti: si no añades esperas explícitas, las pruebas fallan al azar. Su API es de más bajo nivel, así que el runner, las aserciones y los informes los pones tú.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
try:
driver.get("https://tienda.ejemplo.com/login")
driver.find_element(By.NAME, "correo").send_keys("ana@ejemplo.com")
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# Espera explícita: Selenium no espera por ti
WebDriverWait(driver, 5).until(EC.title_contains("Mi cuenta"))
finally:
driver.quit()Pruebas inestables
Pruebas inestables (flaky tests)
Pruebas que unas veces pasan y otras fallan sin que el código haya cambiado.
Una prueba flaky falla de vez en cuando sin motivo aparente: la relanzas y pasa. Es peor que no tener prueba, porque el equipo aprende a ignorar el rojo y, el día que el fallo es real, nadie lo mira.
Las causas más comunes son las esperas fijas (un sleep de dos segundos basta en tu portátil y se queda corto en el pipeline), los datos compartidos entre pruebas (una borra el usuario que otra necesita) y depender del orden de ejecución, de servicios externos, de la hora o de las animaciones.
Se arreglan esperando a condiciones, no a tiempos; haciendo que cada prueba cree sus propios datos, con identificadores únicos; sustituyendo los servicios externos y fijando el reloj. Los reintentos automáticos evitan bloquear el pipeline, pero solo esconden el problema: úsalos junto a las trazas para encontrar la causa.
Úsalo cuando
En cuanto una prueba falle «a veces»: investígala enseguida o ponla en cuarentena con una persona responsable y una fecha, pero no la dejes ahí sin más.
Ten en cuenta
No siempre es culpa de la prueba: a veces una prueba inestable destapa una condición de carrera real en tu aplicación, que tus usuarios también sufren.
// Inestable: espera un tiempo fijo y confía en que baste
await page.getByRole("button", { name: "Guardar" }).click();
await page.waitForTimeout(2000);
expect(await page.getByRole("status").textContent()).toBe("Guardado");
// Estable: espera a que se cumpla la condición
await page.getByRole("button", { name: "Guardar" }).click();
await expect(page.getByRole("status")).toHaveText("Guardado");Pruébalo
Para destapar una prueba inestable, ejecútala muchas veces seguidas: en Playwright, npx playwright test --repeat-each=20. Si falla alguna vez, abre la traza de esa ejecución y busca qué esperaba la prueba que todavía no había pasado.
Interactivo
Playwright, Cypress y Selenium
Activa o desactiva opciones para compararlas cara a cara.
| Característica | Playwright | Cypress | Selenium |
|---|---|---|---|
| Dónde se ejecuta | Fuera del navegador, que controla por protocolo | Dentro del navegador, junto a tu aplicación | Fuera del navegador, mediante WebDriver |
| Navegadores | Chromium, Firefox y WebKit | Familia Chrome, Firefox y Electron; WebKit experimental | Todos los principales, incluido Safari |
| Lenguajes | TypeScript, JavaScript, Python, Java y .NET | JavaScript y TypeScript | Java, Python, C#, Ruby, JavaScript y más |
| Esperas | Automáticas | Automáticas, con reintentos | Explícitas: las escribes tú |
| Varias pestañas y dominios | Sí, sin restricciones | Sin varias pestañas; otros dominios con cy.origin() | Sí |
| Depuración | Trace viewer, modo UI y codegen | Viaje en el tiempo en el registro de comandos | Depende del runner que elijas |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Necesitas probar que el pago funciona en los motores de Chrome, Firefox y Safari, y el flujo abre una ventana del banco en otro dominio.
Para recordar
- Las pruebas E2E manejan la aplicación entera en un navegador real: pocas, y para los flujos que no pueden fallar.
- Playwright cubre Chromium, Firefox y WebKit con esperas automáticas y trazas; Cypress corre dentro del navegador con una depuración muy visual; Selenium es el estándar WebDriver, disponible en muchos lenguajes.
- Una prueba inestable es peor que ninguna, porque enseña al equipo a ignorar el rojo.
- Espera condiciones, no tiempos, y haz que cada prueba cree sus propios datos.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.¿Por qué conviene tener pocas pruebas end-to-end?
2.¿Qué significa que Playwright tenga auto-waiting?
3.¿Cuál es una limitación conocida de Cypress?
4.¿Qué tiene de especial Selenium WebDriver?
5.Una prueba pulsa «Guardar», espera dos segundos fijos y comprueba el mensaje. A veces falla en el pipeline. ¿Cuál es la mejor solución?