九、重塑你的“测试习惯”——避开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) // 临时改超时时间
相关推荐
肖师叔爱抽风5 分钟前
使用nvm use切换版本时出现虚假成功信息,使用nvm ls,实际显示没有切换成功,解决方法
前端
猩猩程序员8 分钟前
Rust为什么需要Borrow Trait
前端
BUG收容所所长8 分钟前
Zustand状态管理如何驱动低代码平台的数据流?
前端·javascript·设计
司宸11 分钟前
学习笔记十四 —— 嵌套JSON树结构 实现模糊匹配返回搜索路径
前端
盗德12 分钟前
Vue渲染引擎的范式革命:从虚拟DOM到Vapor模式
前端·vue.js
BUG收容所所长13 分钟前
React递归渲染与react-dnd——低代码平台的组件拖拽与动态渲染实践
前端·javascript·设计
阿华的代码王国29 分钟前
【Android】日期选择器
android·xml·java·前端·后端
张拭心1 小时前
拭心 7 月日复盘|个体在 AI 时代的挑战
前端
这是个栗子1 小时前
express-jwt报错:Error: algorithms should be set
前端·npm·node.js
Dolphin_海豚1 小时前
vapor 的 IR 是如何被 generate 到 render 函数的
前端·vue.js·vapor