首页 > 解决方案 > 赛普拉斯:想将方法定义为 POM

问题描述

我最近才开始参与 Cypress,并有使用 Selenium 的经验。我从 Selenium 了解到,您将元素和方法外包给通过页面对象模型分离的类,然后在测试中访问它们。因此,如果发生变化,您只需更改元素和方法一次,而不是在每次测试中都更改。

赛普拉斯也可以吗?

示例:我想将src图像的 存储在方法中并将其作为返回返回。这是代码:

get_main_image_slider_active_picture_src() {
    cy.get('.heroBanner.swiper-slide.swiper-slide-active img')
    .should('have.attr','src')
    .then((imgSrc) => {
        const src = imgSrc;
    })
    return src;
}

不幸的是,我觉得这不像在 Selenium 中那样工作。

我该如何处理?

标签: cypress

解决方案


关于这个主题有一些 SO 问题,值得一读。

本质上问题是 PO 方法通过同步返回值来工作,但赛普拉斯命令是异步的,你不能await,你只能“链接”它们。

这个序列是一个链,

cy.get('.heroBanner.swiper-slide.swiper-slide-active img')
  .should('have.attr','src')
  .then(...

每个命令都会产生一个“主题”,它会沿链传递,

cy.get('.heroBanner.swiper-slide.swiper-slide-active img')
    // subject === one or more <img> elements meeting the selector criteria
  .should('have.attr','src')
    // subject === the src attribute of the <img>

查找主题可以同步完成,但cy.get()如果元素是从 api 获取或正在制作动画,也会重试。

简单的伪代码是

while (not found and not timeout) {
  found = query the DOM for the selector
}

while 循环运行时间不确定,因此它是异步的。如果元素在超时之前没有出现,每个步骤也可能会失败。

所以使用 Cypress 命令的 PO 方法只能返回一个 Chainer,并且只能像异步 Cypress 命令(或自定义命令)一样使用。

页面对象

class HeroPage {

  get_main_image_slider_active_picture_src() {
    // here returning the final subject of this chain, wrapped as a chainer
    return cy.get('.heroBanner.swiper-slide.swiper-slide-active img')
      .should('have.attr','src')
  }
}

测试

it('tests the picture page for kittens', () => {
  const heroPage = new HeroPage()
  heroPage.get_main_image_slider_active_picture_src()
    .should(src => src.includes('kittens'))              // chained subject
})

我对此的看法是

  • get_main_image_slider_active_picture_src太具体了。在下一个测试中,您想要对<img>自身进行断言,所以现在您创建另一个方法,或者重构所有内容以便返回 img 元素并在测试中执行所有断言。但是接下来你要测试 img 容器,那么合适的抽象级别是多少呢?

  • Cypress 命令本身就很有表现力,那么它们真的需要 PO 抽象吗?

  • 网页测试不像基于组件的框架,您可以在许多页面中重用一个组件。通常,一个,也许两个,规范涵盖一个网页,因此 PO 方法在许多页面上不是很可重用,例如,您的图像英雄 swiper 只会出现在一个页面上。例外情况可能是诸如登录之类的家务事。您可能会尝试参数化方法并使它们更通用 - 但这种努力似乎与获得的可重用性不成比例。

  • 如果您在选择器中使用的元素类预计会发生变化,请使用 PO 仅返回选择器字符串(同步返回),例如

    it('tests the picture page for kittens', () => {
      const heroPage = new HeroPage()
      cy.get(heroPage.activeImage)
        .should('have.attr','src')
        .should(src => src.includes('kittens'))              
    })
    

您可以使用字符串模板构建选择器,

this.heroBanner = '.heroBanner'
this.swiper = `${this.herobanner}.swiper-slide`
this.activeSlide = `${this.swiper}.swiper-slide-active`
this.activeImage = `${this.activeSlide} img`

推荐阅读