Rohit Jain
Rohit Jain

Reputation: 119

How to use a while loop in cypress? The control of is NOT entering the loop when running this spec file? The way I am polling the task is correct?

The way i am polling tasks for async POST call, is it correct??? Because program control doesn't enter 'while' loop in spec file. Please help! Previous query: How to return a value from Cypress custom command

beforeEach(function () {
    cy.server()
    cy.route('POST', '/rest/hosts').as("hosts")
})


it('Create Host', function () {

    let ts =''
    let regex = /Ok|Error|Warning/mg 

    // Some cypress commands to create a host. POST call is made when I create a host. I want to poll 
    // task for this Asynchronous POST call.

    cy.wait("@hosts").then(function (xhr) {
        expect(xhr.status).to.eq(202)
        token = xhr.request.headers["X-Auth-Token"]
        NEWURL = Cypress.config().baseUrl + xhr.response.body.task
    })


    while((ts.match(regex)) === null) { 
        cy.pollTask(NEWURL, token).then(taskStatus => {
        ts= taskStatus
        })
    }
})

-------------------------

//In Commands.js file, I have written a function to return taskStatus, which I am using it in spec 
 file above

Commands.js -

Cypress.Commands.add("pollTask", (NEWURL, token) => {

    cy.request({
        method: 'GET',
        url: NEWURL ,
        failOnStatusCode: false,
        headers: {
            'x-auth-token': token
        }
    }).as('fetchTaskDetails')


    cy.get('@fetchTaskDetails').then(function (response) {
        const taskStatus = response.body.task.status
        cy.log('task status: ' + taskStatus)
        cy.wrap(taskStatus)
    })

})  

Upvotes: 11

Views: 26491

Answers (3)

Beto Aveiga
Beto Aveiga

Reputation: 3670

With recursion, you can simulate loops.

Add this to your custom commands file (/cypress/support/commands.js):

Cypress.Commands.add('recursionLoop', {times: 'optional'}, function (fn, times) {
  if (typeof times === 'undefined') {
    times = 0;
  }

  cy.then(() => {
    const result = fn(++times);
    if (result !== false) {
      cy.recursionLoop(fn, times);
    }
  });
});

On your tests, just define a function that does what you want for one iteration, and return false if you don't want to iterate again.

cy.recursionLoop(times => {
  cy.wait(1000);
  console.log(`Iteration: ${times}`);
  console.log('Here goes your code.');
  return times < 5;
});

Upvotes: 7

Jonathan Irvin
Jonathan Irvin

Reputation: 1062

You can't use while/for loops with cypress because of the async nature of cypress. Cypress doesn't wait for everything to complete in the loop before starting the loop again. You can however do recursive functions instead and that waits for everything to complete before it hits the method/function again.

Here is a simple example to explain this. You could check to see if a button is visible, if it is visible you click it, then check again to see if it is still visible, and if it is visible you click it again, but if it isn't visible it won't click it. This will repeat, the button will continue to be clicked until the button is no longer visible. Basically the method/function is called over and over until the conditional is no longer met, which accomplishes the same thing as a loop, but actually works with cypress.

clickVisibleButton = () => {
        cy.get( 'body' ).then( $mainContainer => {
            const isVisible = $mainContainer.find( '#idOfElement' ).is( ':visible' );
            if ( isVisible ) {
                cy.get( '#idOfElement' ).click();
                this.clickVisibleButton();
            }
        } );
    }

Then obviously call the this.clickVisibleButton() in your test. I'm using typescript and this method is setup in a class, but you could do this as a regular function as well.

Upvotes: 7

Davide Carpini
Davide Carpini

Reputation: 1711

while loop is not working for me, so as a workaround I did a for loop, a sort of while loop with a timeout of retries

let found = false
const timeout = 10000
for(let i = 0; i<timeout && !found;i++){
      if(..){
           // exiting from the loop
           found = true
      }
}

it is not helpful for everyone, I know.

Upvotes: 1

Related Questions