Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for async method in for loop in Cypress

Edit: Why this is not a duplicate: because Cypress, just read instead of tagging everything as duplicate.

Edit 2: Also, see answer for better understanding of the differences between usual async for loops problems and this question.


I am writing cypress tests and I want to create a cypress command that populates my database with a list of users. I want the creation loop to wait for each user to be created before it moves on to the next one (because I want that done in a specific order).

For now, my loop looks like this:

Cypress.Commands.add("populateDb", (users) => {
  var createdItems = []

  for (const user of users) {
    cy.createUser(user, 'passe').then(response => {
      createdUsers.unshift(response.body.user)
    })
  }
  return createdItems
})

Of course, this loop does not wait for each user to be created before moving onto the next one (I want 'sequential treatment', NOT 'parallel and then wait for all promise to resolve')

I have read the answers about async for-loop here:

  • JavaScript ES6 promise for loop
  • Using async/await with a forEach loop
  • How do I return the response from an asynchronous call?

But I can't seem to find what I want, mainly because cypress wont allow me to declare my function as async as follow :

Cypress.Commands.add("populateDb", async (users) => {
    //Some code
})

And If I don't declare it async I am not able to use await.

Isn't there some king of get() method that just synchronously wait for a Promise to resolve?

like image 629
Tom Avatar asked Oct 10 '18 14:10

Tom


People also ask

How do you wait for async to finish in Cypress?

wait('@createUser', { timeout: 10000}); Use another third-party library that changes how cypress works with async/await, like cypress-promise. This lib may help you to treat cypress commands as promises that you can await in your before code (read more about it in this article).

Can we use async await in Cypress?

Nesting a single level is pretty straight-forward, but multiple levels of nesting can become much harder to understand. Async/await makes it much easier to unwrap values, but Commands are not Promises. Using await on a Cypress chain will not work as expected. Using async/await removed a nesting level.

Does async wait for response?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.


1 Answers

Using a combination of wrap and each cypress command I was able to achieve a loop that waits for each iteration and can return the full results without needing a global variable.

The only reason I use the wrap command is because the cypress command each requires it to be chained off a previous cypress command. The each command will evaluate each iteration and finally call the then where you can return the complete results array. I am using this to upload multiple files and return the list of keys, but you can modify this for your own need.

Cypress.Commands.add("uploadMultipleFiles", (files) => {
    var uploadedS3Keys = []
    cy.wrap(files).each((file, index, list) => {
        cy.uploadFileToOrdersApi(file)
            .then(s3Key => uploadedS3Keys.push(s3Key))
    }).then(() => uploadedS3Keys)
})
like image 149
SidewaysGravity Avatar answered Sep 23 '22 09:09

SidewaysGravity