如何在返回值之前等待 Cypress then() 命令完成?

How to wait for Cypress then() command to finish before returning a value?

我正在尝试在 .then() 命令中设置一个变量,该命令在其外部声明,并且在整个块完成后(.then())我正在 return值。

问题是,当我 return 值时,变量未定义,但在 .then() 块中,变量被加载。

示例代码如下:

public getValueFromElement(): string {
  cy.log("Obtaining the Value");

  let myNumber: string; // Here I'm declaring my variable

  cy.get(this.labelWithText).then(($element) => {

    let originalLabelText: string = $element.text();
    let splittedText: string[];
    splittedText = originalLabelText.split(": ");

    myNumber = splittedText[1]; // Here I'm assigning the value 
    cy.log("Inside the THEN" + myNumber); //This logs the number correctly

  });
        
  return myNumber; // But after I return it using the function, the value is `undefined`!
}

我假设这可能与异步/同步问题有关,因为调用函数时会立即执行 return 语句,并且 .then() 创建的承诺是仍然 运行,但我不知道如何解决这个问题。

你知道我如何等待 .then() 先完成然后再 return 计算值吗?

谢谢!!

你说“问题是,当我 return 值时,变量是未定义的”。

那是因为 return myNumber 行在 之前运行 cy.get(this.labelWithText).then(($element) => { 完成,因为命令是 运行 异步。

您需要 return 命令本身,派生的 myNumber 是从 .then().

内部 return 编辑的
public getValueFromElement(): Chainable<string> {  // cannot return the raw string 
  cy.log("Obtaining the Value");
        
  return cy.get(this.labelWithText).then(($element) => {
    ...
    const myNumber = splittedText[1]; 
    cy.log("Inside the THEN " + myNumber)
    
    return myNumber
  })
}

这样使用

getValueFromElement().then(myNumber => {
  cy.log("Outside the function " + myNumber)
})

这是一个错误的答案,但出于教育目的,我将其保留在这里,以防其他人偶然发现同样的问题。

您可以像这样使用await

public async getValueFromElement(): string {
        cy.log("Obtaining the Value");
        
        let myNumber: string; // Here I'm declaring my variable

        let $element = await cy.get(this.labelWithText);

        let originalLabelText: string = $element.text();
        let splittedText: string[];
        splittedText = originalLabelText.split(": ");

        myNumber = splittedText[1];
        
        return myNumber
}

但请注意,现在这个函数是异步的,它本身 returns 是一个承诺。


为什么

文档是这样说的:

If you're a modern JS programmer you might hear "asynchronous" and think: why can't I just use async/await instead of learning some proprietary API?

Cypress's APIs are built very differently from what you're likely used to: but these design patterns are incredibly intentional. We'll go into more detail later in this guide.

你可以这样同步

public getValueFromElement(): string {  
  cy.log("Obtaining the Value");
        
  const $element = Cypress.$(this.labelWithText)

  const originalLabelText: string = $element.text()
  const splitText = originalLabelText.split(": ")
  const myNumber = splitText[1]
    
  return myNumber
}

在这里你牺牲了异步命令中内置的重试选项。

Cypress 表示只有当您确定该元素已经存在时才使用它,这取决于您文本的上下文。

@MikhailBolotov 的确如此。这就是你的处理方式

cy.get("myOpenElementSelector").click()     // async code
  .then(() => {                             // must wrap sync code in then
    const myNumber = getValueFromElement()  // to ensure correct sequence 
    expect(+myNumber).to.eq(64)
  })

@Mihi 有惯用的方法,但是在编写页面对象方法时有时会遇到困难。

我得出的结论是:

   public async getTheNumber(): Promise<string> { 

        return new Promise((resolve, reject) => {

            cy.log("Retrieving the number");

            cy.get(this.selector).then(($element) => {
                let myNumber = $element.text().split(": ")[1];

                cy.log(`The Number is ${myNumber}`);
                resolve(myNumber);
            });
        });
    }

当我从测试中读取它时,我正在这样做:

myNumberAtTestLevel = await myObject.getTheNumber();

事情是我已经看到我必须将我的 it() 方法更改为 async 才能使其工作。

但是,我看到了 Cypress 的文档: https://docs.cypress.io/api/utilities/promise#Syntax

我正在尝试使用 Cypress.Promises 实现相同的功能,但我做不到。

有什么想法吗?