Tengo una aplicación Angular y ejecuto E2E-Tests con Cypress. Una prueba normal abriría el sitio con cy.visit('/') y después de la carga, comenzará a navegar en el sitio usando los botones de la barra lateral. El tema utilizado para el menú es PrimeNG Ultima.
La prueba funciona bien en mi máquina de desarrollo local, pero falla en CI. Parece que Cypress activa el evento de clic antes de que Angular haya registrado la lógica necesaria para manejar el clic en el elemento de enlace.
¿Hay alguna manera de que Cypress sepa cuándo Angular terminó su arranque? Preferiría una Solución sin código adicional dentro de la aplicación principal, pero podría hacer cambios dentro de la Parte Angular.
Ya probé los siguientes Snippets sin éxito:
cy.window().its('getAllAngularRootElements' as any).should('exist'); cy.window().then(win => new Cypress.Promise((resolve) => win.requestIdleCallback(resolve)));Otra solución que funcionó parcialmente fue escuchar en la barra de progreso de pace.js incluida con PrimeNG-Theme, pero no fue lo suficientemente confiable para todas las pruebas.
Puede usar el Protocolo de depuración de Chrome como se describe en este artículo ¿Cuándo puede hacer clic la prueba?
El ejemplo dado es
it('clicks on the button when there is an event handler', () => { cy.visit('public/index.html') const selector = 'button#one' cy.CDP('Runtime.evaluate', { expression: 'frames[0].document.querySelector("' + selector + '")', }) .should((v) => { expect(v.result).to.have.property('objectId') }) .its('result.objectId') .then(cy.log) .then((objectId) => { cy.CDP('DOMDebugger.getEventListeners', { objectId, depth: -1, pierce: true, }).should((v) => { expect(v.listeners).to.have.length.greaterThan(0) }) }) // now we can click that button cy.get(selector).click() })donde se instala cy.CDP desde este paquete cypress-cdp
Reintentar el clic
Otro enfoque podría ser volver a intentar hacer clic hasta que surta efecto.
El código exacto dependería de la aplicación, pero el patrón sería
const clickUntilChanged = (linkSelector, changeSelector, attempt = 0) => { if (attempt > 10) throw 'Something went wrong' cy.get(changeSelector).invoke('text') .then(initial => { cy.get(linkSelector).click() // attempt a click cy.get(changeSelector).invoke('text') .then(next => { if (initial === next) { // no change cy.wait(50) // wait a bit then try again clickUntilChanged(linkSelector, changeSelector, ++attempt) } // else click was effective, just exit }) }) }) clickUntilChanged('menu-item', 'page-header')Reintentos de prueba
Otro enfoque es hacer uso de una pequeña prueba inicial con reintentos establecidos
it('tests the link click', {retries: {runMode: 10, openMode: 0}}, () => { cy.get('menu-item').click() cy.get('page-header') .should('have.text', 'new-page-header') // fails and retries // if click had no effect })solo espera
Mirando el último artículo de Gleb Solve The First Click , justo en el medio solo agrega una espera difícil para permitir que los oyentes del evento se conecten.
Este es probablemente mi enfoque preferido dada la simplicidad, y quién notaría 1 segundo adicional en una ejecución de CI.
cy.visit(...) if (!Cypress.config('isInteractive')) { // run mode cy.wait(1000) } cy.get('menu-item').click() // should now be functioning