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

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原生的别名机制就能实现需求,步骤如下:

  1. 在beforeEach中获取到组件实例后,通过.as()给实例绑定别名
  2. 测试用例中直接从测试上下文读取别名对应的实例即可,不需要重复查询

具体代码修改

首先调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:36:17