如何在Cypress中抽象重复的UI断言链式调用逻辑?
问题:Cypress UI断言重复代码的抽象优化
我在用Cypress编写UI断言测试时,发现大量重复的链式调用代码,想知道能不能把这些逻辑抽象成辅助方法,提升代码可维护性并减少冗余?
示例代码:
it('displays the table column headers', () => { DivisionPage.divisionNameColumnHeader() .should('be.visible') .and('have.css', 'text-transform', 'capitalize') .and('have.css', 'color', 'rgb(35, 40, 43)') .and('have.css', 'background-color', 'rgb(195, 202, 206)') .and('have.css', 'cursor', 'pointer') .and('have.css', 'font-family', '"Open Sans"') .and('have.css', 'position', 'sticky') DivisionPage.teamsColumnHeader() .should('be.visible') .and('have.css', 'text-transform', 'capitalize') .and('have.css', 'color', 'rgb(35, 40, 43)') .and('have.css', 'background-color', 'rgb(212, 217, 220)') .and('have.css', 'cursor', 'pointer') .and('have.css', 'font-family', '"Open Sans"') .and('have.css', 'position', 'sticky') DivisionPage.playersColumnHeader() .should('be.visible') .and('have.css', 'text-transform', 'capitalize') .and('have.css', 'color', 'rgb(35, 40, 43)') .and('have.css', 'background-color', 'rgb(212, 217, 220)') .and('have.css', 'cursor', 'pointer') .and('have.css', 'font-family', '"Open Sans"') .and('have.css', 'position', 'sticky') })
注:已使用页面对象模型,DivisionPage.divisionNameColumnHeader()等价于cy.get('[data-cy="division-name-column-header"]')
解决方案
当然可以通过抽象辅助方法解决重复代码问题,结合你已有的页面对象模型(POM),有两种常用实现方式:
方案1:在页面对象中封装通用断言方法
直接在DivisionPage类里添加通用断言方法,抽离所有列头共享的样式断言,仅针对差异化属性(比如背景色)传入自定义参数。
修改后的DivisionPage代码:
class DivisionPage { // 原有元素定位方法 divisionNameColumnHeader() { return cy.get('[data-cy="division-name-column-header"]'); } teamsColumnHeader() { return cy.get('[data-cy="teams-column-header"]'); } playersColumnHeader() { return cy.get('[data-cy="players-column-header"]'); } // 封装通用列头断言逻辑 assertColumnHeader(element, customStyles = {}) { // 基础样式断言(所有列头共享规则) element .should('be.visible') .and('have.css', 'text-transform', 'capitalize') .and('have.css', 'color', 'rgb(35, 40, 43)') .and('have.css', 'cursor', 'pointer') .and('have.css', 'font-family', '"Open Sans"') .and('have.css', 'position', 'sticky'); // 应用自定义样式(比如不同列的背景色) Object.entries(customStyles).forEach(([prop, value]) => { element.and('have.css', prop, value); }); } } export default new DivisionPage();
简化后的测试用例:
it('displays the table column headers', () => { DivisionPage.assertColumnHeader(DivisionPage.divisionNameColumnHeader(), { 'background-color': 'rgb(195, 202, 206)' }); DivisionPage.assertColumnHeader(DivisionPage.teamsColumnHeader(), { 'background-color': 'rgb(212, 217, 220)' }); DivisionPage.assertColumnHeader(DivisionPage.playersColumnHeader(), { 'background-color': 'rgb(212, 217, 220)' }); });
方案2:自定义全局Cypress命令
如果多个页面都需要类似的列头断言,可以把逻辑封装成全局命令,在所有测试用例中直接调用。
在cypress/support/commands.js中添加自定义命令:
Cypress.Commands.add('assertColumnHeader', { prevSubject: true }, (subject, customStyles = {}) => { cy.wrap(subject) .should('be.visible') .and('have.css', 'text-transform', 'capitalize') .and('have.css', 'color', 'rgb(35, 40, 43)') .and('have.css', 'cursor', 'pointer') .and('have.css', 'font-family', '"Open Sans"') .and('have.css', 'position', 'sticky'); Object.entries(customStyles).forEach(([prop, value]) => { cy.wrap(subject).and('have.css', prop, value); }); });
测试用例中使用方式:
it('displays the table column headers', () => { DivisionPage.divisionNameColumnHeader().assertColumnHeader({ 'background-color': 'rgb(195, 202, 206)' }); DivisionPage.teamsColumnHeader().assertColumnHeader({ 'background-color': 'rgb(212, 217, 220)' }); DivisionPage.playersColumnHeader().assertColumnHeader({ 'background-color': 'rgb(212, 217, 220)' }); });
两种方案对比
- 页面对象封装:贴合POM设计原则,逻辑与具体页面绑定,适合仅当前页面使用的断言,便于页面内维护。
- 自定义全局命令:全局可用,适合多页面共享的通用断言,减少跨页面重复代码。
内容的提问来源于stack exchange,提问作者Rinkala
相关产品推荐
相关产品推荐

