【问题标题】:How to wait for Cypress then() command to finish before returning a value?如何在返回值之前等待 Cypress then() 命令完成?
【发布时间】:2021-11-07 08:20:11
【问题描述】:

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

问题是,当我返回值时,变量是未定义的,但是在 .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() 先完成再返回值吗?

谢谢!!

【问题讨论】:

    标签: javascript typescript promise cypress


    【解决方案1】:

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

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

    您需要返回命令本身,并且派生的myNumber 也是从.then() 内部返回的。

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

    【讨论】:

      【解决方案2】:

      你可以这样同步

      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
      }
      

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

      赛普拉斯说只有在您确定元素已经存在时才使用它,这取决于您的文本上下文。

      @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 有 idomatic 方式,但在组合页面对象方法时有时会很困难。

      【讨论】:

      • 在这种方式下你也应该小心不要混合 sycn 和 async 代码。所以下面的代码不会像你想象的那样工作:cy.get("myOpenElementSelector").click() // 显示目标元素 let myValue = getValueFromElement(); // 问题在这里:此时,目标元素还没有显示
      【解决方案3】:

      我得出的结论是:

         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 实现相同的功能,但我做不到。

      有什么想法吗?

      【讨论】:

        【解决方案4】:

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

        您可以像这样使用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
        }
        

        但请注意,现在这个函数是异步的,它本身会返回一个 Promise。


        为什么

        文档是这样说的:

        如果您是现代 JS 程序员,您可能会听到“异步”并想:为什么我不能只使用 async/await 而不是学习一些专有 API?

        赛普拉斯的 API 的构建与您可能习惯的完全不同:但这些设计模式是非常有意的。我们将在本指南的后面部分详细介绍。

        【讨论】:

        猜你喜欢
        • 2020-04-17
        • 2015-09-22
        • 2016-05-08
        • 2021-06-20
        • 1970-01-01
        • 2019-03-03
        • 2021-12-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多