13.12.2025, Por Stephan Schwab
¿Y si cada demo de producto también sirviera como quality gate en tu pipeline de CI/CD? Cypress, tradicionalmente posicionado como herramienta de tests end-to-end, puede usarse para crear demos ejecutables que presentan features a los stakeholders y validan los user journeys críticos. Este enfoque ofrece doble valor con una sola inversión, manteniendo tu pirámide de testing equilibrada.
La mayoría de los equipos conocen Cypress como “otro framework de testing de UI”. Instalarlo, escribir selectores, hacer clic en botones, verificar resultados. La documentación enfatiza el testing, los tutoriales se centran en el testing, y los equipos añaden tests de Cypress a sus suites — a menudo duplicando cobertura que ya tienen en niveles inferiores.
Hay una forma más poderosa de pensar en Cypress: como una herramienta para crear demos ejecutables que además funcionan como tests.
Antes de entrar en detalle, revisemos la pirámide de testing — un concepto que sigue siendo tan relevante hoy como cuando Mike Cohn lo introdujo. La pirámide sugiere que la mayor parte de tus tests automatizados deberían ser unit tests rápidos y aislados en la base. Por encima, una capa menor de tests de integración valida que los componentes funcionan juntos. En la cima, una capa delgada de tests end-to-end (E2E) confirma que los user journeys críticos funcionan a través del sistema completo.
/\
/ \ Tests E2E (pocos, lentos, costosos)
/----\
/ \ Tests de integración (moderados)
/--------\
/ \ Unit tests (muchos, rápidos, baratos)
--------------
La forma de pirámide es intencional. Los tests E2E son lentos, flaky y costosos de mantener. Requieren que todo el stack esté corriendo. Un solo cambio de selector puede romper docenas de tests. Los equipos que invierten esta pirámide — escribiendo más tests E2E que unit tests — terminan ahogados en mantenimiento mientras siguen shippeando bugs.
Entonces, ¿por qué usar Cypress? Porque esos pocos tests E2E en la cima de la pirámide cumplen un propósito que los unit tests y tests de integración no pueden: validan que la aplicación funciona como un usuario la experimentaría, a través de un browser real, con todas las interacciones de JavaScript, CSS y networking intactas.
La clave está en ser estratégico sobre qué testeas a este nivel.
Considera el ritmo típico de un equipo de desarrollo. Los features se construyen, y luego alguien necesita hacer la demo — a product owners, stakeholders o en el sprint review. Estas demos siguen un script: “Primero, hago login como admin. Luego navego a settings. Miren cómo actualizo las preferencias de notificación. Vean cómo aparece el mensaje de confirmación.”
¿Y si ese script de demo fuera código ejecutable?
describe('Demo: Preferencias de Notificación', () => {
it('permite a un administrador actualizar la configuración de notificaciones', () => {
// Autenticarse como usuario administrador
cy.login('admin@example.com', 'securepassword')
// Navegar al área de configuración
cy.get('[data-cy="settings-menu"]').click()
cy.get('[data-cy="notifications-tab"]').click()
// Actualizar preferencias de notificación por email
cy.get('[data-cy="email-notifications-toggle"]')
.should('be.visible')
.click()
// Ajustar frecuencia de notificaciones
cy.get('[data-cy="frequency-dropdown"]').select('Weekly')
// Guardar cambios
cy.get('[data-cy="save-preferences"]').click()
// Verificar que aparece la confirmación
cy.get('[data-cy="success-message"]')
.should('be.visible')
.and('contain', 'Preferences saved successfully')
})
})
Este código hace tres cosas a la vez:
Para presentaciones a stakeholders, corre los tests en modo headless con cypress run — Cypress graba videos automáticamente que puedes pausar y narrar a tu ritmo. Alternativamente, añade cy.pause() en momentos clave del código; al correr en modo interactivo con cypress open, la ejecución se detiene en cada pause, permitiéndote explicar qué está pasando antes de hacer clic en “Resume”. El mismo código que usas para la demo también corre en tu pipeline para asegurar que este user journey crítico no tiene regresiones.
El cambio mental es sutil pero importante. Cuando te propones “escribir un test”, te enfocas en cobertura, edge cases y assertions. Cuando te propones “escribir una demo”, te enfocas en el user journey, la narrativa y los resultados visibles.
Esto cambia cómo estructuras el código:
describe('Flujo de Order Fulfillment', () => {
beforeEach(() => {
// Setup: un cliente ha hecho un pedido
cy.task('seedOrder', { status: 'pending', items: 3 })
cy.login('warehouse@example.com')
})
it('demuestra el proceso completo de fulfillment', () => {
// El equipo de warehouse ve los pedidos pendientes en su dashboard
cy.visit('/fulfillment/dashboard')
cy.get('[data-cy="pending-orders"]')
.should('contain', '1 order awaiting fulfillment')
// Abren los detalles del pedido
cy.get('[data-cy="order-row"]').first().click()
cy.get('[data-cy="order-items"]')
.find('li')
.should('have.length', 3)
// Cada item se escanea y marca como picked
cy.get('[data-cy="scan-item-input"]').type('SKU-001{enter}')
cy.get('[data-cy="picked-count"]').should('contain', '1 of 3')
cy.get('[data-cy="scan-item-input"]').type('SKU-002{enter}')
cy.get('[data-cy="scan-item-input"]').type('SKU-003{enter}')
cy.get('[data-cy="picked-count"]').should('contain', '3 of 3')
// El pedido se marca como ready for shipping
cy.get('[data-cy="complete-fulfillment"]').click()
cy.get('[data-cy="order-status"]')
.should('contain', 'Ready for Shipping')
})
})
Fíjate en los comentarios. Se leen como un script de demo, no como documentación de tests. Cuando presentas esto a stakeholders, puedes literalmente leer los comentarios en voz alta mientras Cypress ejecuta los pasos.
Resiste la tentación de seleccionar elementos por clases CSS o paths del DOM complejos. Los data attributes como data-cy son explícitos, estables y comunican intención:
// Frágil - se rompe cuando cambian los estilos
cy.get('.btn.btn-primary.submit-form')
// Robusto - sobrevive al refactoring
cy.get('[data-cy="submit-order"]')
Tus demos van a compartir patrones. Encapsúlalos:
// cypress/support/commands.js
Cypress.Commands.add('login', (email, password) => {
cy.visit('/login')
cy.get('[data-cy="email-input"]').type(email)
cy.get('[data-cy="password-input"]').type(password)
cy.get('[data-cy="login-button"]').click()
cy.url().should('not.include', '/login')
})
Cypress.Commands.add('addToCart', (productId) => {
cy.visit(`/products/${productId}`)
cy.get('[data-cy="add-to-cart"]').click()
cy.get('[data-cy="cart-notification"]').should('be.visible')
})
Ahora tus demos se leen mucho más limpio:
it('demuestra un flujo de compra completo', () => {
cy.login('customer@example.com', 'password')
cy.addToCart('product-123')
cy.addToCart('product-456')
cy.visit('/checkout')
// ...continuar el journey
})
Recuerda la pirámide. No estás tratando de testear cada permutación a nivel E2E. Apunta a un puñado de demos que cubran los user journeys críticos — los paths que, si se rompen, harían la app inutilizable o le costarían plata significativa al negocio.
Una aplicación típica podría tener:
Eso son quizás 5-10 demos de Cypress en total, no 500 tests E2E.
En tu config de CI/CD, estas demos se convierten en un quality gate:
# Ejemplo de workflow en GitHub Actions
cypress-demos:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cypress-io/github-action@v6
with:
start: npm run start:ci
wait-on: 'http://localhost:3000'
spec: cypress/e2e/demos/**/*.cy.js
Cuando una demo falla en el pipeline, significa que un user journey crítico está roto. Esta es una señal mucho más fuerte que “un test falló”. Fuerza una conversación: “La demo de order fulfillment está fallando — no podemos shippear este release hasta que el equipo de warehouse pueda completar pedidos.”
El approach tradicional trata demos y tests como actividades separadas. Alguien escribe tests de Cypress para el pipeline. Otra persona prepara slides en PowerPoint y hace clic manualmente por la app para los stakeholders. Estas actividades ocurren de forma independiente, consumen tiempo y a menudo quedan desactualizadas entre sí.
El approach de demo ejecutable colapsa todo en un solo artefacto. La demo que muestras a stakeholders es el mismo código que protege tus deploys a producción. Cuando la app cambia, actualizar la demo actualiza el test. Cuando los stakeholders preguntan “¿puedes mostrarme ese feature otra vez?”, corres la demo — y acabas de verificar que todavía funciona.
No se trata de abandonar el testing apropiado. Tus unit tests siguen cubriendo los edge cases. Tus tests de integración siguen verificando las interacciones entre componentes. Las demos de Cypress se sientan en el ápice de tu pirámide, asegurando que los paths críticos funcionan end-to-end mientras sirven como herramientas de comunicación para stakeholders.
La próxima vez que uses Cypress, pregúntate: ¿estoy escribiendo un test o estoy scripteando una demo? La respuesta podría cambiar cómo abordas todo el ejercicio.
Hablemos de tu situación real. ¿Quieres acelerar la entrega, quitar bloqueos técnicos o validar si una idea merece más inversión? Reserva una conversación breve (20 min): escucho tu contexto, te doy 1–2 recomendaciones prácticas sin compromiso ni discurso comercial. Si encaja, seguimos; si no, te llevas claridad. Confidencial y directo.
¿Prefieres correo? Escríbeme: sns@caimito.net