九、重塑你的“测试习惯”——避开Cypress的那些“坑”

重塑你的"测试习惯"------避开Cypress的那些"坑"

如果你用过Selenium这类传统测试工具,刚上手Cypress可能会觉得"不习惯":明明写对了代码,却拿不到元素值;想用async/await处理异步,结果报错......其实不是你写错了,而是Cypress的设计思路和传统工具不一样。这一章咱们就聊聊这些"特殊习惯",帮你少踩坑。

一、Cypress的"坑":这些操作千万别做

1. 别用"同步思维"写异步代码

Cypress的命令都是异步执行 的,和JavaScript的setTimeout类似,不会立刻执行,而是先"排队",再按顺序执行。比如下面这段代码,你以为会先打印id,实际却会打印undefined

javascript 复制代码
// 错误示例:以为能拿到元素id
let userId
cy.get('[data-cy=user-id]').then(($el) => {
  userId = $el.text() // 这里的赋值是异步的
})
console.log(userId) // 同步代码,会先执行,所以是undefined

正确做法 :用then回调处理异步结果,所有依赖这个结果的操作都要放在then里:

javascript 复制代码
cy.get('[data-cy=user-id]').then(($el) => {
  const userId = $el.text()
  console.log(userId) // 正确:在回调里处理
  // 后续操作也放这里
})

2. 别用箭头函数定义用例或钩子

如果用箭头函数(() => {})定义itbeforeEach,里面的this会指向全局,无法使用this.skip()等方法:

javascript 复制代码
// 错误示例:箭头函数里的this有问题
it('测试用例', () => {
  if (someCondition) {
    this.skip() // 报错:this.skip is not a function
  }
})

正确做法 :用function定义,this才会指向当前测试上下文:

javascript 复制代码
it('测试用例', function() {
  if (someCondition) {
    this.skip() // 正常工作:跳过用例
  }
})

3. 别用async/await处理Cypress命令

Cypress命令虽然是异步的,但它不返回Promise,所以async/await无效:

javascript 复制代码
// 错误示例:await对Cypress命令无效
async function test() {
  await cy.visit('/login') // 不会等待访问完成
  cy.get('input').type('username') // 可能在页面加载完之前执行
}

正确做法 :用Cypress的链式命令或then回调处理顺序:

javascript 复制代码
// 正确:链式执行,自动等待前一步完成
cy.visit('/login')
  .get('input[name=username]').type('jane')
  .get('input[name=password]').type('123')

4. 别在一次测试中访问多个域名

由于浏览器的同源策略限制,Cypress不允许在一个测试用例里访问不同域名(比如先访问http://a.com,再访问http://b.com),会直接报错。

解决办法 :如果必须跨域,拆分到多个测试用例;或者确保访问的是同一主域名下的子域(比如http://blog.a.comhttp://shop.a.com)。

二、Cypress的"独特技巧":这样用更顺手

1. 用闭包保存临时变量

想在测试中保存临时数据(比如接口返回的token),可以用闭包或then回调:

javascript 复制代码
describe('测试', function() {
  let token // 闭包变量
  
  it('获取token', function() {
    cy.request('/api/login').then((res) => {
      token = res.body.token // 保存到闭包
    })
  })
  
  it('使用token', function() {
    cy.visit('/profile', {
      headers: { Authorization: `Bearer ${token}` } // 直接使用
    })
  })
})

2. 用asget共享数据

通过cy.wrap().as('别名')给数据起别名,后续用cy.get('@别名')访问,适合跨步骤共享:

javascript 复制代码
// 第一步:保存数据到别名
cy.fixture('user.json').as('userData') // 从fixture取数据
// 或从接口取数据
cy.request('/api/user').then((res) => {
  cy.wrap(res.body).as('userInfo')
})

// 后续步骤:用@别名访问
it('使用用户数据', function() {
  cy.get('@userData').then((user) => {
    cy.get('input[name=username]').type(user.name)
  })
})

3. 用Cypress.env()设置全局变量

想在不同测试文件间共享配置(比如测试环境的域名),可以在cypress.json里定义环境变量,或运行时通过--env传入:

json 复制代码
// cypress.json
{
  "env": {
    "baseUrl": "http://test.com",
    "timeout": 10000
  }
}

代码里用Cypress.env('baseUrl')获取,也可以动态修改:

javascript 复制代码
Cypress.env('timeout', 15000) // 临时改超时时间
相关推荐
一只叁木Meow几秒前
JavaScript数学库深度对比
前端
顾辰逸you2 分钟前
uniapp--咸虾米壁纸项目(一)
前端·微信小程序
方方洛17 分钟前
电子书阅读器:epub电子书文件的解析
前端·产品·电子书
idaibin18 分钟前
Rustzen Admin 前端简单权限系统设计与实现
前端·react.js
GISer_Jinger24 分钟前
Trae Solo模式生成一个旅行足迹App
前端·javascript
zhangbao90s24 分钟前
Intl API:浏览器原生国际化API入门指南
前端·javascript·html
艾小码27 分钟前
构建现代前端工程:Webpack/Vite/Rollup配置解析与最佳实践
前端·webpack·node.js
跟橙姐学代码32 分钟前
Python 集合:人生中最简单的真理,只有一次
前端·python·ipython
复苏季风33 分钟前
站在2025 年 来看,现在应该怎么入门CSS
前端·css
pepedd86434 分钟前
深度解剖 Vue3 架构:编译时 + 运行时的协作
前端·vue.js·trae