Mientras escribía la prueba de Cypress, encontré este problema que no me permite actualizar la variable deseada. Lo que estoy tratando de lograr es ejecutar un ciclo y actualizar la variable questionId
dentro del ciclo para alguna consulta API. La variable deseada cambia con cada iteración, el problema es que toma el valor inicial 0
pero no se actualiza dentro del ciclo. He leído varios artículos sobre los procedimientos de sincronización/sincronización de Cypress, pero nada parece ayudar.
Aquí está el fragmento de prueba:
it('Should pass', function () { cy.visit(`${Cypress.env('appUrl')}/url`) let questionId: number = 0 for (let index = 0; index < 9; index++) { cy.intercept({ method: 'GET', path: `${questionId}` }).as('questionData') cy.log('next question id: ' + questionId) cy.intercept({ method: 'POST', path: 'answers' }).as('answers') cy.contains('button', 'Submit answer').click() cy.wait('@answers') .then((xhr: any) => { expect(xhr.response.statusCode).to.eq(200) questionId = xhr.response.body.data.next_question_id cy.log('new question id: ' + questionId) cy.contains('span', 'You are correct!').should('be.visible') cy.contains('button', 'view solution').click() cy.contains('button', 'continue').click() }) } })
Cypress se comporta de forma extraña con los bucles for tradicionales. En lugar de usar un bucle for tradicional, intente usar la función times
de Cypress lodash. (El enlace lleva a un artículo sobre la función de times
de Lodash, ya que Cypress._
es solo un envoltorio alrededor de Lodash).
... let questionId = 0; Cypress._.times(9, () => { cy.intercept({ method: 'GET', path: `${questionId}` }).as('questionData') cy.log('next question id: ' + questionId) cy.intercept({ method: 'POST', path: 'answers' }).as('answers') cy.contains('button', 'Submit answer').click() cy.wait('@answers') .then((xhr: any) => { expect(xhr.response.statusCode).to.eq(200) questionId = xhr.response.body.data.next_question_id cy.log('new question id: ' + questionId) cy.contains('span', 'You are correct!').should('be.visible') cy.contains('button', 'view solution').click() cy.contains('button', 'continue').click() }) });
El problema es que los bucles síncronos como
for (let index = 0; index < 9; index++) {...}
ejecute hasta que finalice antes de que cualquier comando de Cypress comience a ejecutarse.
Lo mismo se aplica a Cypress._.times(9, () => {...})
.
Una forma de manejarlo es con una función recursiva.
Esto esperará a que se complete el código asíncrono en cada paso antes de pasar al siguiente (lo cual es vital ya que el siguiente paso depende de los resultados del anterior)
const handleQuestion = (questionId, iteration=0) => { if (iteration === 9) return // finished, exit cy.intercept({ method: 'GET', path: `${questionId}` }).as('questionData') // what does the intercept above do? // Do you need to wait on it, and what triggers the GET? cy.log('next question id: ' + questionId) cy.intercept({ method: 'POST', path: 'answers' }).as('answers') cy.contains('button', 'Submit answer').click() cy.wait('@answers').then((xhr: any) => { expect(xhr.response.statusCode).to.eq(200) const nextQuestionId = xhr.response.body.data.next_question_id cy.log('new question id: ' + nextQuestionId) cy.contains('span', 'You are correct!').should('be.visible') cy.contains('button', 'view solution').click() cy.contains('button', 'continue').click() .then(() => { cy.contains('button', 'Submit answer') // check that the submit button .should('be.visible') // is ready for the next question .and('be.enabled') handleQuestion(nextQuestionId, ++iteration) // move on to next question }) }) } handleQuestion(0) // start with question #0
La verificación antes de la próxima iteración puede necesitar algún ajuste
cy.contains('button', 'Submit answer') .should('be.visible') .and('be.enabled')
Este bloque está destinado a esperar a que la página esté lista para la siguiente pregunta.
También puede buscar algún texto que indique el estado listo como
cy.contains('Please submit your answer')