Cypress如何在beforeEach钩子初始化组件供测试用例复用
问题背景
我在Cypress自定义命令配置文件中编写了如下组件查询命令,用于快速获取Vue组件实例:
Cypress.Commands.add('component', (name) => { let log = Cypress.log({ 'displayName': 'component', 'name': name }); cy .window({ log: false }) .then($win => { const component = name === 'root' ? $win.app : $win.app.$children.find(e => e.$vnode.tag.includes(name)) log.set({ consoleProps: () => { return { component }; } }); return component; }); })
目前直接在it测试块内调用cy.component可以正常运行,但每个测试用例都要重复调用该命令获取组件,存在大量重复代码。
需求是仅在beforeEach钩子中初始化一次需要用到的组件,后续每个测试用例直接复用该组件实例,无需重复调用查询。
当前测试代码如下(已修正原代码的笔误):
const { LoginPage } = require("../support/pages/pages") const loginPage = new LoginPage() const email = "fabryotranto@gmail.com" const password = "12345" describe('login feature', () => { beforeEach('it opens the url', () => { cy.visit("http://localhost:3000/") cy.component('root') .then(root => { root.showLoginModule = true }) }) it('register with valid credentials', () => { cy.component('Login') .then(login => { login.logSignSwitch() login.signupEmail = email login.signupPassword = password }); loginPage.clickSignUpButton cy.get(loginPage.loggedUser) .should("contain.text", "Log out") }) })
现在新增it测试块时,必须再次调用cy.component('Login')获取组件实例,无法复用之前获取的实例。
实现方案
不要直接用全局普通变量存储组件实例,Cypress命令是异步排队执行的,直接赋值会存在时机不匹配、测试间状态污染的问题。用Cypress原生的别名机制就能实现需求,步骤如下:
- 在
beforeEach中获取到组件实例后,通过.as()给实例绑定别名 - 测试用例中直接从测试上下文读取别名对应的实例即可,不需要重复查询
具体代码修改
首先调整beforeEach逻辑,提前获取Login组件并存为别名:
beforeEach('初始化页面与通用组件', () => { cy.visit("http://localhost:3000/") cy.component('root').then(root => { root.showLoginModule = true }) // 获取Login组件后存为别名,后续用例可直接读取 cy.component('Login').as('loginComp') })
用例中读取别名有两种写法,选一种即可:
写法1:通过this上下文读取(注意不能用箭头函数定义it回调)
// 回调必须用普通function,箭头函数会绑定外层this导致读不到别名 it('register with valid credentials', function() { // 直接取之前存好的组件实例使用 this.loginComp.logSignSwitch() this.loginComp.signupEmail = email this.loginComp.signupPassword = password loginPage.clickSignUpButton cy.get(loginPage.loggedUser) .should("contain.text", "Log out") })
写法2:通过cy.get读取别名(支持箭头函数)
it('register with valid credentials', () => { // 从别名缓存中读取组件实例 cy.get('@loginComp').then(login => { login.logSignSwitch() login.signupEmail = email login.signupPassword = password }) loginPage.clickSignUpButton cy.get(loginPage.loggedUser) .should("contain.text", "Log out") })
注意事项
- 别名是绑定在单个测试用例上下文的,每个用例执行前都会重跑
beforeEach重新查询组件、更新别名值,不会出现测试间状态串扰的问题 - 如果用例中存在页面刷新、组件卸载重挂的操作,需要在操作完成后重新查询组件更新别名即可
- 该方案同样适用于其他需要在beforeEach提前获取、用例内复用的测试对象,不局限于Vue组件实例
内容的提问来源于stack exchange,提问作者Fabrizio Otranto
相关产品推荐
相关产品推荐

