变量无法在赛普拉斯的循环内更新

Variable fails to update inside a loop in Cypress

在编写 Cypress 测试时,我遇到了这个问题,它不允许我更新所需的变量。 我想要实现的是 运行 一个循环,并为某些 API 查询更新循环内的 questionId 变量。 期望的变量随着每次迭代而变化,问题是它采用初始值 0 但无法在循环内更新。 我已经阅读了多篇关于赛普拉斯 async/sync 程序的文章,但似乎没有任何帮助。

这是测试片段:

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()
                        })
            }
    
        })

赛普拉斯在传统的 for 循环中表现得怪异。不要使用传统的 for 循环,而是尝试使用 Cypress lodash 的 times 函数。 (link 转到一篇关于 Lodash 的 times 函数的文章,因为 Cypress._ 只是 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()
  })
});

问题是像

这样的同步循环
for (let index = 0; index < 9; index++) {...}

运行 在任何赛普拉斯命令开始执行之前完成。

同样适用于Cypress._.times(9, () => {...})

处理它的一种方法是使用递归函数。

这将等待每一步的异步代码完成,然后再继续下一步(这很重要,因为下一步取决于上一步的结果)

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

下一次迭代前的检查可能需要一些调整

cy.contains('button', 'Submit answer')    
  .should('be.visible')                   
  .and('be.enabled')

此块旨在等待页面进入下一个问题的就绪状态。

您还可以检查一些指示就绪状态的文本,例如

cy.contains('Please submit your answer')