skip to Main Content

I’m new to Cypress and JavaScript. I want to create a loop that executes a request with different values until I get a certain response.

let continue_loop = 1;

loginLoop: for (let i = 1; i < 100; i++) {
  cy.request({
    // url: Cypress.env("web_api")+"/1.0/user/login",
    url: Cypress.env("api").staging + "/1.0/user/login",
    method: "POST",
    failOnStatusCode: false,
    body: {
      email: "email" + i + "@email.com",
      password: "Helloworld10",
    },
  }).then((response) => {
    if (response.status == 403) {
      continue_loop = 2;
    }
  });

  if (continue_loop == 2) {
    break loginLoop;
  }
}

It seems that continue_loop only gets the value 2 within the then block, because after it always returns to 1 so the loop never breaks. I also tried to use Cypress aliases but it’s the same result. How can I achieve this?

2

Answers


  1. Cypress, annoyingly, does not use promises but "something that has a .then function" instead. Of course, we can just turn those into real promises by wrapping them and then awaiting those:

    const MAX_FAIL_COUNT = ...;
    
    for (let failures = 0, i = 1; failures < MAX_FAIL_COUNT && i < 100; i++) {
      // Await the request with a simple wrapper
      const response = await new Promise(resolve => cy.request(
        ...
      ).then(resolve));
    
      // And don't use == unless your statement *only* works with type coercion
      if (response.status === 403) {
        failures++;
      }
    }
    
    Login or Signup to reply.
  2. Cypress aliases are provided to bridge the gap between synchronous code like for-loops and asynchronous commands like cy.request().

    You would need to

    • bring the code checking break condition inside the loop,
    • invert the logic so that you only continue if continue_loop is true

    This reproducible example shows how to do equivalent logic to async/await in a Cypress test.

    let continue_loop = true
    
    // set up the alias to control the loop
    cy.wrap(continue_loop, {log:false}).as('continue')   
    
    // staring at 95 to keep the example short
    // #101 will be a failing request
    // loops 102 to 200 will be skipped
    
    for (let i = 95; i < 200; i++) {
      cy.get('@continue', {log:false}).then(continue_loop => {
        if (continue_loop) {
          cy.request({
            url: `https://jsonplaceholder.typicode.com/posts/${i}`,
            failOnStatusCode: false,
          }).then((response) => {
    
            // checking for any failed status here
            if (response.status >= 400) {
              continue_loop = false
              cy.wrap(continue_loop, {log:false}).as('continue')  // update the alias
            }
          })
        }
      })
    }
    

    enter image description here


    With a Promise wrapper

    Using a Promise wrapper works for this simple command, but could fail for more complex command chains.

    Cypress issues a warning in the console.

    for (let i = 95; i < 200; i++) {
      const response = await new Promise(resolve => {
        cy.request({
          url: `https://jsonplaceholder.typicode.com/posts/${i}`,
          failOnStatusCode: false,
        }).then(resolve)
      })
      if (response.status >= 400) {
        break 
      }
    }
    

    The warning thrown in the console

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search