Anderson David Chicaiza Tenesaca
excelente esto de los custom commands
¿Qué son y cómo se implementan los custom commands en Cypress?
Cypress, una herramienta poderosa para pruebas automáticas, ofrece la posibilidad de crear comandos personalizados o custom commands. Esta alternativa se presenta ante la tradicional metodología Page Object Model, brindando una manera más flexible y personalizable de extender funcionalidades en nuestras pruebas.
¿Cómo creamos un comando personalizado en Cypress?
Para empezar a trabajar con comandos personalizados en Cypress, primero necesitamos identificar el archivo donde guardaremos estos comandos. En este caso, es un archivo de comandos que, por defecto, viene con ejemplos y la documentación necesaria.
El proceso de creación de un comando personalizado implica los siguientes pasos:
add para añadir un nuevo comando.Aquí un ejemplo de cómo podría lucir un comando para iniciar sesión:
Cypress.Commands.add('login', (email, password) => { const emailInput = 'input[name=email]'; const passwordInput = 'input[name=password]'; const loginButton = 'button[type=submit]'; cy.visit('/login'); cy.get(emailInput).type(email); cy.get(passwordInput).type(password); cy.get(loginButton).click(); });
¿Cómo utilizamos estos comandos personalizados en nuestras pruebas?
Una vez definido, podemos utilizar nuestros comandos personalizados en las pruebas de manera sencilla y clara, logrando que nuestro código sea más legible y fácil de mantener:
describe('Login Tests', () => { it('Realiza un login con un usuario erróneo', () => { cy.login('usuario@inexistente.com', 'contrasenaIncorrecta'); // Aquí, puedes agregar validaciones para ver si el login falló correctamente. }); });
¿Es posible sobreescribir comandos ya existentes en Cypress?
Sí, Cypress permite sobreescribir comandos preexistentes para personalizarlos aún más. Un ejemplo común es el comando type, que se podría modificar para añadir funcionalidades como ocultar contraseñas en los logs de Cypress:
Cypress.Commands.overwrite('type', (originalFn, element, text, options = {}) => { if (options.sensitive) { options.log = false; Cypress.log({ name: 'type', message: '*'.repeat(text.length), }); } return originalFn(element, text, options); });
Con este enfoque, uno puede controlar cómo y cuándo ciertas informaciones se ven reflejadas en los logs durante la ejecución de las pruebas, protegiendo información sensible como contraseñas.
¿Cuál es la ventaja de usar comandos personalizados?
Uno de los principales beneficios de los comandos personalizados es su capacidad de reutilización y simplicidad para añadir lógica compleja en pocos pasos. Son especialmente útiles cuando necesitas realizar la misma serie de interacciones en múltiples pruebas o cuando deseas simplificar acciones en componentes que no requieren un modelo de página completo, como ventanas modales o validaciones específicas.
Con los comandos personalizados, Cypress no solo permite la extensión del framework sino que también ofrece la flexibilidad de personalizar o sobreescribir comportamientos ya implementados, lo que puede ser una herramienta poderosa para personalizar las pruebas según las necesidades del proyecto.
¡Te animamos a seguir explorando y creando tus propios comandos personalizados! Con ellos podrás abordar retos específicos de tu aplicación de manera eficiente y creativa.
Estos son los comandos personalizados que he añadido:
Cypress.Commands.add("login", (email, password) => { const userInput = "#user_login"; const passwordInput = "#user_password"; const loginButton = "#login_form > div.form-actions > input"; cy.visit("<Login page>"); cy.get(userInput).should("be.visible").type(email); cy.get(passwordInput) .should("be.visible") .type(password, { sensitive: true }); cy.get(loginButton).should("be.visible").click(); return cy; }); Cypress.Commands.add("is", (chainer) => { if (chainer === "login.error") { const error = ".alert.alert-error"; cy.get(error).should("be.visible"); } else if (chainer === "login.success") { const tabs = { account_summary_tab: "#account_summary_tab", account_activity_tab: "#account_activity_tab", transfer_founds_tab: "#transfer_funds_tab", }; cy.get(tabs.account_activity_tab).should("be.visible"); cy.get(tabs.account_summary_tab).should("be.visible"); cy.get(tabs.transfer_founds_tab).should("be.visible"); } else { throw new Error(`${chainer} is not recognized as valid chainer`); } return cy; });
De tal manera que la prueba me queda así:
describe("Login with custom command", () => { it("error login", () => { cy.login("aaaa", "aaaa").is("login.error"); }); it("success login", () => { cy.login("username", "password").is("login.success"); }); });
Anderson David Chicaiza Tenesaca
excelente esto de los custom commands
Miguel Giraldo Duque
Otro uso que encuentro para overWrite es realizar las verificaciones de flaky test bajo parametro, o simplmente que de forma preterminada realize la verificacción
Cypress.Commands.overwrite("type", (origanlFn, $element, text, options) => { if (options && options.secureType) { return cy .wrap($element) .should("be.visible") .should("not.be.disabled") .then(($el) => { return origanlFn($el, text, options); }); } return origanlFn($element, text, options); });
Francisco Antonio Hernandez Sabatino
Seba Cardoso
podrias hacer un login por api mucho mas rapido que usando la interfaz
Cypress.Commands.add('loginByApi', (email, password) => { cy.request({ method: 'POST', url: `${api}/login`, body: { email, password }, }) .its('body') .then((body) => { cy.setCookie('access_token', body.data.access_token); cy.wrap(body.data.access_token).as('token'); }); });
Erick Vicentin
Me encantó la opcion de redefinir funciones nativas de Cypress, para ofuscar el password por ejemplo. Pero seguiria trabajando con POM, me parece mas organizado y legible.
//comands.js /** * Realiza la acción de rellenar los campos y hacer clic en el botón de login. * @example cy.doLogin('standard_user', 'secret_sauce') */ Cypress.Commands.add('doLogin', (username, password) => { cy.get('[data-test="username"]').type(username); cy.get('[data-test="password"]').type(password); cy.get('[data-test="login-button"]').click(); }); /** * Realiza la secuencia de clics para cerrar la sesión de un usuario. * @example cy.doLogout() */ Cypress.Commands.add('doLogout', () => { cy.get('#react-burger-menu-btn').click(); cy.get('#logout_sidebar_link').click(); });
// ------------------------------------------------------------------------- // 🧪 DATOS DE PRUEBA (Se mantienen igual) // ------------------------------------------------------------------------- const VALID_USER = { username: 'standard_user', password: 'secret_sauce' }; const INVALID_USER = { username: 'bad_user', password: 'bad_password' }; // ------------------------------------------------------------------------- // 📄 SUITE DE PRUEBAS: Login con Comandos Personalizados en saucedemo.com // ------------------------------------------------------------------------- describe('🧪 Pruebas de Login usando Comandos Personalizados', () => { // ⚙️ Este `beforeEach` se ejecuta antes de cada prueba. // Ahora visita la página directamente. beforeEach(() => { cy.visit('https://www.saucedemo.com/'); }); // ▶️ CASO DE PRUEBA 1: Login Fallido it('❌ Debería mostrar un mensaje de error con credenciales incorrectas', () => { // ACT - Usamos nuestro comando personalizado para la acción. cy.log('Intentando hacer login con datos inválidos...'); cy.doLogin(INVALID_USER.username, INVALID_USER.password); // ASSERT - La aserción se queda en la prueba, ¡haciéndola explícita! cy.log('Verificando que el mensaje de error es visible...'); cy.get('[data-test="error"]') .should('be.visible') .and('contain', 'Username and password do not match'); // Texto exacto del error // Verificación extra: La URL no debería haber cambiado. cy.url().should('eq', 'https://www.saucedemo.com/'); }); // ▶️ CASO DE PRUEBA 2: Login Exitoso it('✅ Debería permitir el login de un usuario con credenciales correctas', () => { // ACT - Usamos el mismo comando con datos válidos. cy.log('Haciendo login con un usuario válido...'); cy.doLogin(VALID_USER.username, VALID_USER.password); // ASSERT - Verificamos el resultado directamente en la prueba. cy.log('Verificando que la página de productos se ha cargado...'); cy.get('.title').should('have.text', 'Products'); // Verificación extra: La URL debería haber cambiado a la página de inventario. cy.url().should('include', '/inventory.html'); }); // ▶️ CASO DE PRUEBA 3: Logout it('👋 Debería permitir a un usuario desloguearse correctamente', () => { // ARRANGE - Para desloguearse, primero hay que loguearse. cy.log('Haciendo login primero para poder desloguearse...'); cy.doLogin(VALID_USER.username, VALID_USER.password); // ACT - Usamos el nuevo comando de logout. cy.log('Haciendo clic en logout...'); cy.doLogout(); // ASSERT - Verificamos que hemos vuelto a la página de login. cy.log('Verificando que hemos vuelto a la pantalla de login...'); cy.get('[data-test="login-button"]').should('be.visible'); cy.url().should('eq', 'https://www.saucedemo.com/'); }); });