簡體   English   中英

在 Cypress 的 for 循環中等待異步方法

[英]Wait for async method in for loop in Cypress

編輯:為什么這不是重復的:因為Cypress ,只是讀取而不是將所有內容標記為重復。

編輯 2:另外,請參閱答案以更好地理解通常的 async for循環問題與此問題之間的差異。


我正在編寫 cypress 測試,我想創建一個 cypress 命令,用用戶列表填充我的數據庫。 我希望創建循環在移動到下一個用戶之前等待創建每個用戶(因為我希望以特定順序完成)。

現在,我的循環如下所示:

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

當然,這個循環在移動到下一個用戶之前不會等待每個用戶被創建(我想要“順序處理”,而不是“並行然后等待所有承諾解決”)

我在這里閱讀了有關異步 for 循環的答案:

但我似乎找不到我想要的東西,主要是因為 cypress 不允許我將我的函數聲明為異步,如下所示:

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

如果我不將其聲明為async我將無法使用await

是不是有一些get()方法之王只是同步等待 Promise 解析?

使用wrapeach cypress 命令的組合,我能夠實現一個循環,該循環等待每次迭代,並且無需全局變量即可返回完整結果。

我使用wrap命令的唯一原因是因為each cypress 命令each要求將它與之前的 cypress 命令鏈接起來。 each命令將評估每次迭代並最終調用then ,您可以在其中返回完整的結果數組。 我正在使用它來上傳多個文件並返回密鑰列表,但您可以根據自己的需要修改它。

Cypress.Commands.add("uploadMultipleFiles", (files) => {
    var uploadedS3Keys = []
    cy.wrap(files).each((file, index, list) => {
        cy.uploadFileToOrdersApi(file)
            .then(s3Key => uploadedS3Keys.push(s3Key))
    }).then(() => uploadedS3Keys)
})

事實證明,cypress 對等待異步方法解決的操作如此嚴格是有原因的:它總是按順序自動運行所有異步命令,因為它們被調用,而不是並行,所以這將在即使createUser是 Async 的正確順序:

Cypress.Commands.add("populateDb", (users) => {
  for (const user in users) {
    cy.createUser(user).then(response => {
      console.log(response)
    })
  }
})

如果您想獲取返回的值(在我的情況下,我需要用戶 ID 以便稍后刪除它們),您可以將它們存儲在文件根級別的var ,並添加一個返回該 var 的 cypress 命令。

var createdItems = []

Cypress.Commands.add("getCreatedItems", () => {
  return createdItems
})

Cypress.Commands.add("populateDb", (users) => {
  for (const user in users) {
    cy.createUser(user).then(response => {
      createdItems.unshift(response) // I unshift() because I need to delete them in FILO order later
    })
  }
})

然后在 cypress 測試文件中,您可以按照需要執行的順序調用它們:

cy.populateDb(users)
cy.getCreatedItems().then(response => {
  //response is my createdItems Array, and cy.getCreatedItems() will run only when cy.populateDb() is resolved
})

你也可以這樣做:

Cypress.Commands.add("populateDb", (users) => {
  for (const user in users) {
    cy.createUser(user).then(response => {
      createdItems.unshift(response) // I unshift() because I need to delete them in FILO order later
    })
  }

  return createdItems;
})

cy.populateDb(users).then(response => {
  // ... runs after populate ...
})

但另一個答案也是正確的。 每個cy.xxxxx命令實際上都被添加到命令隊列中並一個接一個地運行。 如果在隊列執行期間調用了新的cy.xxxxx2命令,它們將被添加到隊列的前面。

下面簡單舉例說明cypress命令隊列和同步代碼的執行順序:

const a = 1; // a == 1

cy.cmd1().then(() => {
  cy.cmd2().then(() => {
    a += 1; // a == 5
  });

  a += 1; // a == 3

  cy.cmd3()
  a += 1; // a == 4
});

cy.cmd4().then(() => {
  a += 1; // a == 6
});

a += 1; // a == 2

// at this point cypress command queue starts running the queue that is cmd1, cmd4

// 1. cmd1 runs and adds cmd2 and cmd3 to front of command queue also adds +2 to a
// 2. cmd2 runs and adds +1 to a
// 3. cmd3 runs
// 4. cmd4 runs and adds +1 to a
// ... all done ...

所以從這個例子你可以看到,在你的情況下,你的循環將被串行執行,因為每個cy.createUser被添加到 cypress 命令隊列中,然后按順序執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM