Comandos Personalizados en Cypress: Alternativa al Page Object Model
Clase 11 de 29 • Curso de Cypress Avanzado
Contenido del curso
Clase 11 de 29 • Curso de Cypress Avanzado
Contenido del curso
Iván Ceballos Vega
Jose Parra
Sebastian Segura
Anderson David Chicaiza Tenesaca
Miguel Giraldo Duque
Francisco Antonio Hernandez Sabatino
Seba Cardoso
Erick Vicentin
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"); }); });
Al agregar comandos personalizados, me parece que el archivo commands crecería mucho cada vez que necesitemos crear pruebas. No sería una mala practica?
Buenas! Lei en la documentacion de cypress que es una practica no recomendada hacer el login usando elementos del DOM, en su lugar deberíamos hacerlo programaticamente (enviando el request)
excelente esto de los custom commands
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); });
//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/'); }); });
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'); }); });
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.