Lección 1 de 6 · 2 min
El runner y tu primer test
Setup
npm init -y && npm install -D cypress
npx cypress open
El runner abre un navegador real donde ves cada comando ejecutarse, con snapshot del DOM en cada paso — el famoso time-travel debugging.
Primer test
// cypress/e2e/reservas.cy.js
describe('Flujo de reservas', () => {
it('muestra los servicios disponibles', () => {
cy.visit('https://ejemplo.cl');
cy.contains('h2', 'Nuestros servicios').should('be.visible');
cy.get('[data-cy="service-card"]').should('have.length.at.least', 3);
});
});
El modelo mental: comandos encolados
Esto es lo que más confunde viniendo de otros frameworks. Los comandos Cypress no se ejecutan al llamarlos — se encolan y corren después, con reintentos automáticos:
// ❌ Esto NO funciona: el comando no devuelve el elemento
const card = cy.get('[data-cy="service-card"]');
card.click(); // encola sobre un Chainable, no un elemento
// ✅ Encadena
cy.get('[data-cy="service-card"]').first().click();
// ✅ O usa .then() si necesitas el valor
cy.get('[data-cy="price"]').then(($el) => {
const precio = parseInt($el.text().replace(/\D/g, ''));
expect(precio).to.be.greaterThan(0);
});
Asserts con reintento incorporado
.should() reintenta hasta 4 segundos por defecto — por eso Cypress casi no necesita esperas manuales:
cy.get('[data-cy="total"]').should('contain', '$18.500');
cy.get('form').should('not.have.class', 'loading');
cy.url().should('include', '/confirmacion');
Si te descubres escribiendo cy.wait(3000), detente: en la lección 2 verás cómo esperar lo que realmente importa.
Ejercicio
Escribe un test contra cualquier sitio público que: visite la home, verifique que el título principal es visible, haga clic en un enlace de navegación y verifique la URL de destino. Míralo correr en el runner y usa el time-travel para inspeccionar el DOM en cada paso.