Cypress es un framework de automatización de pruebas de última generación diseñado específicamente para la web moderna[cite: 2]. A diferencia de otras herramientas, Cypress se ejecuta directamente dentro del mismo ciclo de bucle de eventos que la aplicación (capa de interfaz de usuario)[cite: 2], lo que proporciona ejecuciones nativas extremadamente veloces y reduce la inestabilidad en los resultados.
Para inicializar un proyecto con Cypress, sigue la secuencia de comandos en tu terminal de desarrollo[cite: 5]:
# 1. Asegúrate de contar con Node.js instalado globalmente [cite: 6] node -v # 2. Inicializa el gestor de paquetes de Node dentro del directorio de tu proyecto [cite: 7] npm init -y # 3. Instala Cypress como una dependencia de desarrollo [cite: 8] npm install cypress --save-dev # 4. Abre la interfaz gráfica interactiva de Cypress por primera vez [cite: 9] npm run cypress:open
Si al ejecutar el comando de apertura del entorno del test runner el sistema arroja el siguiente error[cite: 11, 12]:
npm error Missing script: "cypress:open"
Solución: Abre el archivo estructural package.json de la raíz y edita el objeto de comandos
incluyendo el alias correspondiente[cite: 17]:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"cypress:open": "cypress open"
}
Los archivos de pruebas de Cypress utilizan la extensión estándar *.cy.js [cite: 10] y deben ser
ubicados bajo el directorio de trabajo cypress/e2e/[cite: 25]. Su estructura hereda la sintaxis de
las librerías Mocha y Chai mediante las palabras reservadas describe (para definir suites) e
it (para pruebas individuales)[cite: 26, 42].
describe('Suite: Pruebas de Apertura Web', () => {
it('Debería navegar correctamente a la página de inicio y validar su título', () => {
// Visita la URL especificada [cite: 27, 32]
cy.visit('https://www.google.com/');
// Asertar que el título sea coincidente de forma exacta [cite: 28, 33]
cy.title().should('eq', 'Google');
});
});
Tip: Puedes definir una propiedad baseUrl global en el archivo cypress.config.js
para simplificar el uso de cy.visit() en tus archivos[cite: 23].
Cypress proporciona el comando universal cy.get() para capturar nodos del árbol de documentos
(DOM)[cite: 47]. Como estándar profesional, se aconseja priorizar los atributos exclusivos de pruebas (como IDs
o selectores personalizados) antes que clases de diseño que cambien con regularidad[cite: 45].
#)[cite: 47]..)[cite: 47]..type(): Inyecta texto o cadenas de caracteres dentro de un campo de entrada[cite: 38, 48].
.click(): Acciona el evento de clic del ratón sobre el botón o elemento seleccionado[cite: 41,
53].
describe('Suite: Interacción con el Buscador', () => {
it('Debería realizar una búsqueda interactiva en Wikipedia', () => {
cy.visit('https://es.wikipedia.org/wiki/Wikipedia:Portada'); [cite: 51]
// Validar que la URL incluye el término esperado [cite: 44, 52]
cy.url().should('include', 'wikipedia');
// Interactuar con los elementos del DOM [cite: 53, 54, 55]
cy.get('#p-search > .cdx-button--fake-button > .vector-icon').click();
cy.get('#searchform > .cdx-search-input > [name="search"]').type('cypress');
cy.get('#searchform > .cdx-search-input > .cdx-button').click();
// Alternativa semántica para buscar botones por su texto visible [cite: 58, 59]
// cy.contains('button', 'Buscar').click();
// Aserción de existencia del bloque de contenido [cite: 61]
cy.get('.mw-html-heading:contains("Portales")').should('exist');
});
});
A pesar de que Cypress maneja colas de espera inteligentes automáticas, en ocasiones se requieren instrucciones explícitas de sincronización o de control de ventanas del navegador:
| Función / Comando | Descripción Técnica | Ejemplo Práctico |
|---|---|---|
cy.wait() |
Detiene la ejecución del flujo por un tiempo fijo en milisegundos[cite: 63]. (Usar con moderación) | cy.wait(1000); // Espera 1 segundo [cite: 64] |
cy.reload() |
Fuerza la recarga de la página actual en pantalla limpiando estados locales[cite: 65, 66]. | cy.reload(); |
cy.exec() |
Ejecuta un comando nativo a nivel del sistema operativo anfitrión[cite: 67]. | cy.exec('echo "Test running"'); |
{ force: true } |
Fuerza una acción o navegación ignorando si el elemento está oculto o bloqueado[cite: 99]. | cy.visit('https://url-edicion', { force: true }); [cite: 99] |
Si se requiere interactuar con el contexto global o forzar la redirección de enlaces diseñados para abrirse en pestañas nuevas, se puede capturar el objeto de la ventana gráfica directamente[cite: 101]:
cy.window().then((win) => {
win.open('https://es.wikipedia.org/w/index.php?title=Wikipedia:Portada&action=edit'); [cite: 102]
});
Los Fixtures son archivos JSON estáticos que contienen sets de datos estructurados independientes del
código de pruebas[cite: 71]. Se gestionan dentro del directorio por defecto cypress/fixtures/[cite:
73].
[
{
"nombre": "admin@gmail.com",
"password": "juan123"
},
{
"nombre": "user@gmail.com",
"password": "user123"
}
]
describe('Suite: Autenticación con Datos Externos', () => {
beforeEach(() => {
cy.visit("https://es.wikipedia.org/wiki/Especial:Entrar"); [cite: 88]
});
it('Debería cargar y rellenar las credenciales del primer registro', () => {
// Carga el fixture y resuelve la promesa de datos [cite: 91]
cy.fixture('usuarios.json').then((datos) => {
const usuario = datos[0]; [cite: 92]
cy.get('#wpName1').type(usuario.nombre); [cite: 93]
cy.get('#wpPassword1').type(usuario.password);
});
});
});
Cypress no se limita a la interfaz gráfica; también puede actuar como cliente HTTP mediante el comando
cy.request() para realizar llamadas directas a extremos (Endpoints) de API REST[cite: 109, 111,
114].
describe('Suite: Pruebas de Integración de API', () => {
it('Debería validar un método GET correctamente', () => {
cy.request('GET', "https://reqres.in/api/users?page=2").then((response) => {
// Validar código de estado HTTP exitoso [cite: 115]
expect(response.status).to.eq(200);
// Comprobar la existencia estructural y el tipo de dato de las propiedades [cite: 119, 120, 121]
expect(response.body).to.have.property('data');
expect(response.body.data).to.be.an('array');
// Validar datos específicos internos [cite: 142, 143]
expect(response.body.data[0]).to.have.property('id', 7);
});
});
it('Debería dar de alta un recurso mediante un método POST', () => {
const newUser = { "name": "Martín", "job": "QA Automation Lead" }; [cite: 128]
cy.request('POST', "https://reqres.in/api/users", newUser).then((response) => {
expect(response.status).to.eq(201); // 201 Created [cite: 133]
expect(response.body).to.have.property('name', newUser.name); [cite: 134]
expect(response.body).to.have.property('job', newUser.job); [cite: 135]
});
});
});
Separa lógicamente tus archivos de prueba basándote en dominios o módulos funcionales del negocio[cite: 145, 146]:
describe('Módulo: Autenticación de Usuarios', () => { ... }); [cite: 147]
describe('Módulo: Gestión del Perfil de Usuario', () => { ... }); [cite: 149]
describe('Módulo: Procesos de Pago y Pasarela', () => { ... }); [cite: 151]
Asigna identificadores dinámicos amigables a tus consultas para reutilizarlas a lo largo del test sin duplicar localizadores[cite: 153]:
cy.get('img[alt="Logo corporativo"]').as('imagenPrincipal'); [cite: 154]
// Más adelante en tu código:
cy.get('@imagenPrincipal').should('be.visible'); [cite: 69]
Para activar y parametrizar la generación de evidencias en video o capturas automatizadas ante fallas en los pipelines, utiliza los siguientes indicadores[cite: 156]:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
video: true, // Graba un video de la ejecución del test [cite: 158]
videoCompression: false, // Evita ralentizaciones de compresión [cite: 159]
screenshotOnRunFailure: true, // Toma fotos automáticamente si un test falla [cite: 160]
e2e: {
setupNodeEvents(on, config) {
// Eventos del ciclo de vida de Node aquí [cite: 162]
},
},
});
Garantizar que tu portal cumpla con los estándares de accesibilidad internacional es sumamente sencillo acoplando el motor de auditoría axe-core al ecosistema de Cypress[cite: 165].
# Instalación del conector de accesibilidad en el proyecto [cite: 165] npm install --save-dev cypress-axe
import 'cypress-axe'; // Inyección de los comandos de validación accesibles [cite: 167]
describe('Suite: Auditoría de Accesibilidad', () => {
it('La página de inicio no debería poseer infracciones críticas de maquetación', () => {
cy.visit('https://blazedemo.com'); [cite: 170]
// Inyecta de forma interna el motor axe runtime [cite: 171]
cy.injectAxe(); [cite: 171]
// Ejecuta el análisis acotándolo a impactos críticos y serios [cite: 172, 173]
cy.checkA11y(null, {
includedImpacts: ['critical', 'serious'] [cite: 173]
});
});
});
Cypress atrapa y aprueba automáticamente los pop-ups informativos del navegador, pero permite interceptar el texto para auditar su contenido[cite: 183, 184]:
cy.on('window:alert', (textoAlerta) => { [cite: 184]
expect(textoAlerta).to.equal('Product added'); // Valida el string de la alerta [cite: 185]
});
Para comprobar que un descuento promocional alteró de manera real el balance final de una compra, se puede asertar el cambio de valor numérico[cite: 177]:
// Almacenar el estado original del elemento de precio [cite: 178]
const precioAntes = cy.get('.OrderSummary__price');
cy.get('[name="promo"]').type('CUPON_DESCUENTO'); [cite: 179]
cy.get('.btn-aplicar').click(); [cite: 180]
// El nuevo estado no debería ser idéntico al patrón anterior [cite: 181, 182]
const precioDespues = cy.get('.OrderSummary__price');
precioAntes.should('not.equal', precioDespues); [cite: 182]
Para empaquetar de forma portable y limpia tus suites E2E impidiendo que dependan de las librerías gráficas locales de un sistema anfitrión, utiliza contenedores Docker.
# Usar la imagen oficial preconfigurada con todas las dependencias y navegadores necesarios FROM cypress/included:latest # Directorio de trabajo interno del contenedor [cite: 190] WORKDIR /e2e # Copiar el directorio del proyecto local al espacio interno del contenedor [cite: 191] COPY cypress/ ./ COPY cypress.config.js ./ # Comando de ejecución automatizado por defecto al instanciar el contenedor [cite: 192] CMD ["cypress", "run"]
docker build -t cypress-test -f Dockerfile .
docker run cypress-test:latest