如何在Cypress测试中保存API Token供后续测试用例调用?
解决Cypress中API Token跨测试用例复用的问题
问题场景
编写了以下Cypress API测试代码,试图在第一个测试用例获取Token后,在第二个创建购物车的用例中复用,但运行时报错 ReferenceError: access_token is not defined。
原代码如下:
const API_STAGING_URL = Cypress.env('API_STAGING_URL') describe('Decathlon API tests', () => { it('Get token',function(){ cy.request({ method:'POST', url: 'https://test.com/as/token.oauth2?grant_type=client_credentials', headers:{ authorization : 'Basic 1aFJueHkxddsvdvsdcd3cSA==' }}).then((response)=>{ expect(response.status).to.eq(200) const access_token = response.body.access_token cy.log(access_token) cy.log(this.access_token) }) cy.log(this.access_token) }), it('Create Cart',function(){ cy.request({ method:'POST', url: `${API_STAGING_URL}`+"/api/v1/cart", headers:{ Authorization : 'Bearer ' + access_token, "Content-Type": 'application/json', "Cache-Control": 'no-cache', "User-Agent": 'PostmanRuntime/7.29.2', "Accept": '*/*', "Accept-Encoding": 'gzip, deflate, br', "Connection": 'keep-alive', "Postman-Token": '<calculated when request is sent>' }, }}).then((response)=>{ //Get statut 200 expect(response.status).to.eq(200) //Get property headers })}) })
问题原因
- 变量作用域限制:第一个测试用例中声明的
const access_token是局部变量,仅在then回调内部有效,无法跨测试用例访问。 - 异步执行顺序问题:
cy.request是异步操作,写在then外部的cy.log(this.access_token)会先执行,此时this.access_token还未被赋值。 - 测试用例隔离性:Cypress的每个
it测试用例独立执行,默认不共享上下文变量。
解决方案
方法1:before钩子+Cypress环境变量(推荐全局复用)
将Token获取逻辑放在所有测试用例执行前的before钩子中,把Token存入Cypress环境变量,实现全局复用:
const API_STAGING_URL = Cypress.env('API_STAGING_URL') describe('Decathlon API tests', () => { // 所有测试用例执行前获取Token before(function() { cy.request({ method: 'POST', url: 'https://test.com/as/token.oauth2?grant_type=client_credentials', headers: { authorization: 'Basic 1aFJueHkxddsvdvsdcd3cSA==' } }).then((response) => { expect(response.status).to.eq(200) // 将Token存入环境变量 Cypress.env('access_token', response.body.access_token) cy.log('获取到的Token:', Cypress.env('access_token')) }) }) it('Create Cart', function(){ cy.request({ method: 'POST', url: `${API_STAGING_URL}/api/v1/cart`, headers: { Authorization: `Bearer ${Cypress.env('access_token')}`, "Content-Type": 'application/json', "Cache-Control": 'no-cache', "User-Agent": 'PostmanRuntime/7.29.2', "Accept": '*/*', "Accept-Encoding": 'gzip, deflate, br', "Connection": 'keep-alive' // Postman-Token无需手动设置,Cypress会自动处理请求标识 } }).then((response) => { expect(response.status).to.eq(200) }) }) })
方法2:cy.wrap+别名(局部用例共享)
如果仅需在当前describe块内共享Token,可使用别名方式:
const API_STAGING_URL = Cypress.env('API_STAGING_URL') describe('Decathlon API tests', () => { it('Get token', function(){ cy.request({ method: 'POST', url: 'https://test.com/as/token.oauth2?grant_type=client_credentials', headers: { authorization: 'Basic 1aFJueHkxddsvdvsdcd3cSA==' } }).then((response) => { expect(response.status).to.eq(200) // 将Token包装为Cypress对象并设置别名 cy.wrap(response.body.access_token).as('accessToken') }) }) it('Create Cart', function(){ // 通过this访问别名(需使用function()而非箭头函数) cy.get('@accessToken').then((access_token) => { cy.request({ method: 'POST', url: `${API_STAGING_URL}/api/v1/cart`, headers: { Authorization: `Bearer ${access_token}`, "Content-Type": 'application/json', "Cache-Control": 'no-cache', "User-Agent": 'PostmanRuntime/7.29.2', "Accept": '*/*', "Accept-Encoding": 'gzip, deflate, br', "Connection": 'keep-alive' } }).then((response) => { expect(response.status).to.eq(200) }) }) }) })
注意事项
- 避免直接用
this赋值共享变量:Cypress异步操作中可能丢失上下文,导致变量无法正确传递。 - 无需手动设置
Postman-Token:Cypress会自动生成请求标识,手动设置可能引发异常。 - 关注Token有效期:若Token过期时间短,可改用
beforeEach钩子在每个用例执行前重新获取Token。
内容的提问来源于stack exchange,提问作者FlutterLover
相关产品推荐
相关产品推荐

