Software Testing & QA Services

Automatizando la Web Moderna: Cypress y Playwright para pruebas End-to-End

Tags: Tecnologías
cypress

 

El desarrollo web moderno —SPAs, micro-frontends, apps progresivas— exige pruebas que garanticen que toda la experiencia del usuario funcione sin problemas, desde el login hasta la interacción más compleja con la UI.

 

Las pruebas end-to-end (E2E) verifican que el frontend, backend, APIs y la red funcionen de manera integrada. Entre los frameworks más populares para E2E se encuentran Cypress y Playwright, que ofrecen diferentes filosofías, ventajas y flujos de trabajo.

 

¿Qué es el testing E2E y por qué es importante?

 

El End-to-End testing (o pruebas de extremo a extremo) es una metodología de QA que verifica un flujo completo de usuario, reproduciendo la experiencia real en un entorno lo más parecido posible a producción.

 

En lugar de probar funciones aisladas (como en unit tests) o módulos específicos (como en integration tests), las pruebas E2E:

 

  • Abren la aplicación como lo haría un usuario real.
  • Interactúan con botones, formularios, navegación, APIs, cookies, localStorage, sesiones, etc.
  • Comprueban que todo el sistema responde correctamente.
  • Las pruebas E2E verifican flujos completos de usuario:
  • Login → Dashboard → Interacción → Logout
  • Interacciones con APIs y servicios externos
  • Manejo de estados persistentes y asincronía

 

A diferencia de pruebas unitarias o de integración, las E2E validan la integración completa del sistema, asegurando que los cambios en el código no rompan la experiencia del usuario final. Las pruebas unitarias e integrales no garantizan que la aplicación funcione en su conjunto.

 

El E2E asegura:

 

  • Que la UI responde
  • Que el backend funciona
  • Que el sistema completo está integrado
  • Que no hay regresiones funcionales

 

Cypress vs Playwright

 

Cypress como Playwright son frameworks líderes para testing E2E, pero tienen filosofías distintas. La elección depende del tipo de proyecto, arquitectura, equipo y necesidades de CI/CD.

 

Cypress

 

  • Corre dentro del navegador, inyectado en la propia ventana de la aplicación.
  • Excelente para observar la ejecución paso a paso.
  • Limita algunos escenarios que requieran múltiples pestañas o ventanas.
  • No soporta todos los eventos del navegador porque no tiene control completo del motor.
  • Debugging muy intuitivo (time-travel, UI interactiva).

 

Playwright

 

  • Controla el navegador desde fuera, a través de su API.
  • Soporta múltiples páginas, contextos y usuarios paralelos.
  • Permite automatizar navegadores reales sin restricciones.
  • Más poder, más flexibilidad y más funcionalidades a nivel de navegador.

 

Ejemplos prácticos

 

Login Flow con Cypress (cypress/e2e/login.cy.js)

 

describe('Flujo de login', () => {
  it('inicia sesión correctamente y muestra el dashboard', () => {
    cy.visit('https://mi-app.com/login')
    cy.get('input[name="email"]').type('usuario@ejemplo.com')
    cy.get('input[name="password"]').type('miPassword{enter}')
    cy.url().should('include', '/dashboard')
    cy.contains('Bienvenido, Usuario')
    cy.get('button[aria-label="Cerrar sesión"]').click()
    cy.url().should('include', '/login')
  })
})

 

Nota: Cypress maneja esperas automáticas, reduciendo tests frágiles

 

Login Flow con Playwright (tests/login.spec.js)

 

import { test, expect } from '@playwright/test';
test('flujo de login exitoso', async ({ page }) => {
  await page.goto('https://mi-app.com/login');
  await page.fill('input[name="email"]', 'usuario@ejemplo.com');
  await page.fill('input[name="password"]', 'miPassword');
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL(/.*\/dashboard/);
  await expect(page.locator('h1')).toContainText('Bienvenido, Usuario');
  await page.click('button[aria-label="Cerrar sesión"]');
  await expect(page).toHaveURL(/.*\/login/);
});

 

Configuración avanzada en Playwright (playwright.config.ts)

 

import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  fullyParallel: true,
  retries: 1,
  use: {
    baseURL: 'https://mi-app.com',
    headless: true,
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
    viewport: { width: 1280, height: 720 },
  },
});

 

Mocking de APIs

 

cy.intercept('POST', '/api/login', { statusCode: 200, body: { token: '12345' } }).as('loginRequest');
cy.get('button[type="submit"]').click();
cy.wait('@loginRequest');
await page.route('**/api/login', route =>
  route.fulfill({ status: 200, body: JSON.stringify({ token: '12345' }) })
);
await page.click('button[type="submit"]');

 

Testing de accesibilidad (a11y)

 

import { injectAxe, checkA11y } from '@axe-core/playwright';
await page.goto('/');
await injectAxe(page);
await checkA11y(page);

 

Medición y Mitigación del Flakiness

 

await page.locator('button#submit').waitFor({ state: 'visible' });
await page.locator('button#submit').click();

 

Buenas Prácticas

 

  • Usa un Testing Pyramid: Unit > Integration > E2E.
  • Prioriza los flujos de negocio más importantes para el usuario.
  • Mantén tests pequeños, legibles y aislados.
  • Evitar waits fijos.
  • Mantener tests independientes.

 

Elección entre Cypress y Playwright

 

Usar Cypress cuando los tests no requieren multi-tab ni Safari/iOS reales.

Usar Playwright cuando se necesita soporte completo de navegadores y paralelización real.

 

Te recomendamos en video