Estoy usando el complemento cypress-wait-until . Tengo una página de prueba HTML con desplazamiento largo y elemento en la parte inferior. Un script simple desplaza el elemento a la vista. Tengo una prueba de Cypress que verifica si aparece un elemento dentro de la ventana gráfica, pero no funciona como se esperaba:
.waitUntil(() => cy.get('#scrollTo').isInViewport()); Con el comando isInViewport
Cypress.Commands.add('isInViewport', { prevSubject: true }, (subject) => { const windowInnerWidth = Cypress.config('viewportWidth'); const windowInnerHeight = Cypress.config('viewportHeight'); const bounding = subject[0].getBoundingClientRect(); const rightBoundOfWindow = windowInnerWidth; const bottomBoundOfWindow = windowInnerHeight; expect(bounding.top).to.be.at.least(0); expect(bounding.left).to.be.at.least(0); expect(bounding.right).to.be.lessThan(rightBoundOfWindow); expect(bounding.bottom).to.be.lessThan(bottomBoundOfWindow); });La prueba falla, no parece esperar hasta que aparezca el elemento (el elemento se desplaza a la vista sin problemas). Tenga en cuenta que el script en sí y el comando scrollIntoView funcionan correctamente, porque cuando hago una prueba de escritura así:
.get('#scrollTo') .wait(1000) .isInViewport();Pasó. Sin embargo, no quiero usar la función de espera. Soy nuevo en Cypress, ¿qué estoy haciendo mal?
Creo que cypress-wait-until necesita la función () => cy.get('#scrollTo').isInViewport() para devolver algo veraz (no estoy seguro, los documentos no son precisos), pero todos los ejemplos que se muestran tienen un false/ verdadero valor devuelto (falso hasta que se cumpla la condición).
Para su caso, eso puede ser tan simple como
Cypress.Commands.add('isInViewport', { prevSubject: true }, (subject) => { ... // NO explicit expects here, they will fail and stop the test //expect(bounding.top).to.be.at.least(0); //expect(bounding.left).to.be.at.least(0); //expect(bounding.right).to.be.lessThan(rightBoundOfWindow); //expect(bounding.bottom).to.be.lessThan(bottomBoundOfWindow); // Return false or true return bounding.top >= 0 && bounding.left >= 0 && bounding.right < rightBoundOfWindow && bounding.bottom < bottomBoundOfWindow }); Dado que es un comando personalizado, es posible que deba cy.wrap()
// Return false or true const result = bounding.top >= 0 && bounding.left >= 0 && bounding.right < rightBoundOfWindow && bounding.bottom < bottomBoundOfWindow; return cy.wrap(result)Así que encontré la solución, la publicaré aquí solo para que conste en caso de que alguien tenga el mismo problema. Primero eliminé mi función beInViewport de los comandos personalizados de Cypress para separar la función auxiliar:
export function beInViewport($el: any): void { const windowInnerWidth = Cypress.config('viewportWidth'); const windowInnerHeight = Cypress.config('viewportHeight'); const bounding = $el.get()[0].getBoundingClientRect(); const rightBoundOfWindow = windowInnerWidth; const bottomBoundOfWindow = windowInnerHeight; expect(bounding.top).to.be.at.least(0); expect(bounding.left).to.be.at.least(0); expect(bounding.right).to.be.lessThan(rightBoundOfWindow); expect(bounding.bottom).to.be.lessThan(bottomBoundOfWindow); } Y luego simplemente lo usé como argumento pasado para should funcione:
cy.get('#element').should(beInViewport);Funciona perfectamente.
Dado que está probando el script que se desplaza al elemento después de la visita, entonces .should() volverá a consultar con un defaultCommandTimeout de 4000 ms. Si esto no es suficiente, puede modificar el tiempo de espera para la consulta específica .
cy.get('#scrollTo',{ timeout: 6000 }) //sets command timeout to 6 seconds .should('be.visible')