You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cypress:封装获取元素href属性方法返回空值,如何正确处理?

问题:Cypress页面对象方法无法正确返回异步获取的元素属性值

问题重现

原本在测试用例中稳定运行的逻辑:获取元素hrefAppTheme的href属性,验证其是否属于字符串数组appThemes中的值:

describe('...',() => {
    it('should ...', () => {
      // ...
      let defaultAppTheme = '';
      onMenuPage.hrefAppTheme.invoke('attr', 'href')
        .then(hrefVal => {
          if (typeof hrefVal !== 'undefined') {
            expect(hrefVal).to.be.oneOf(onMenuPage.appThemes);
            defaultAppTheme = hrefVal;

            // 后续引用defaultAppTheme变量...
          }
        });
    });
});

为了复用逻辑,将其提取到页面对象类的getUserTheme方法中:

export default class MenuPage {
  // ...
  getUserTheme(): string {
    let userTheme = '';
    cy.then(() => {
      this.hrefAppTheme.invoke('attr', 'href')
        .then(resVal => {
          if (typeof resVal !== 'undefined') {
            userTheme = resVal;
          }
        });
    });
    return userTheme;
  }
}

调用时始终返回空字符串,断言失败:

describe('...',() => {
    it('should ...', () => {
      // ...
      let defaultAppTheme = '';
      cy.wrap(onMenuPage.getUserTheme()).then(resVal => {
        defaultAppTheme = resVal;
        expect(defaultAppTheme).to.be.oneOf(onMenuPage.appThemes);
      });

      // 后续引用defaultAppTheme变量...
    });
});

错误信息:

AssertionError: expected '' to be one of [ 'theme-light.css', 'theme-dark.css' ]
      + expected - actual

      +[ 'theme-light.css', 'theme-dark.css' ]

问题根源

Cypress的所有命令都是异步执行的,getUserTheme方法中:

  1. cy.then和invoke('attr', 'href')都是异步操作,会被放入Cypress的命令队列延后执行
  2. 方法会立即返回初始值'',等异步操作完成并赋值userTheme时,返回值已经被拿到,因此始终得到空字符串

解决方案

方案1:返回Cypress链式命令(推荐)

让页面对象方法直接返回Cypress的命令链,利用异步队列机制保证顺序,同时可封装断言逻辑:

export default class MenuPage {
  // ...
  getUserTheme() {
    // 返回Cypress.Chainable<string>,无需指定string类型
    return this.hrefAppTheme.invoke('attr', 'href')
      .then(hrefVal => {
        if (typeof hrefVal !== 'undefined') {
          // 将断言封装到方法内,简化测试用例
          expect(hrefVal).to.be.oneOf(this.appThemes);
          return hrefVal;
        }
        // 处理属性不存在的情况,可根据需求返回默认值或抛出错误
        return '';
      });
  }
}

调用方式:

describe('...',() => {
  it('should ...', () => {
    let defaultAppTheme = '';
    onMenuPage.getUserTheme().then(hrefVal => {
      defaultAppTheme = hrefVal;
      // 后续对defaultAppTheme的操作必须放在此回调内,或继续链式调用保证顺序
    });
  });
});

方案2:使用async/await(需配置)

若习惯同步写法,可开启Cypress异步支持后使用async/await:

export default class MenuPage {
  // ...
  async getUserTheme(): Promise<string> {
    const hrefVal = await this.hrefAppTheme.invoke('attr', 'href');
    if (typeof hrefVal !== 'undefined') {
      expect(hrefVal).to.be.oneOf(this.appThemes);
      return hrefVal;
    }
    return '';
  }
}

调用方式:

describe('...',() => {
  it('should ...', async () => {
    const defaultAppTheme = await onMenuPage.getUserTheme();
    expect(defaultAppTheme).to.be.oneOf(onMenuPage.appThemes);
    // 后续可直接引用defaultAppTheme
  });
});

更优封装建议

  • 封装断言逻辑:将属性验证逻辑放入页面对象方法,测试用例只需关注业务流程,避免重复代码
  • 处理边界情况:明确href属性为undefined时的处理逻辑,比如返回默认主题或抛出错误,避免后续异常
  • 遵循Cypress异步模型:优先使用链式命令而非async/await,减少异步适配成本,更贴合框架设计

内容的提问来源于stack exchange,提问作者Jan and RESTless

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:07:44