如何解决Cypress中API响应ID无法跨异步步骤复用的问题?
解决Cypress中异步操作导致变量无法正确赋值的问题
你遇到的这个问题是Cypress的异步执行模型导致的:所有cy.开头的命令都是异步队列执行的,而普通的同步代码(比如你第25行的cy.log(templateID))会先于Cypress命令队列里的代码运行。所以当cy.wait('@api_template_create').then()里的赋值操作真正执行时,第25行的cy.log早就跑完了,此时templateID还是初始的null。
下面给你几个实用的解决方案:
方案1:将依赖templateID的操作放入then回调中
这是最直接的处理方式,因为then回调会在API请求完成后执行,此时templateID已经被正确赋值,所有需要用到这个ID的操作都可以放在这里面:
describe('Templates', function() { let templateID = null before('before once', function() { cy.server(); cy.route({method: 'POST', url:'/api/templates/'}).as('api_template_create') cy.visit(''); }); it('Create a new template', function() { cy.get('.my-form #type').select('book') cy.get('.my-form #title').type('Cyress title test') // ...其他表单操作 cy.get('.my-form input:submit').click() cy.wait('@api_template_create').then(xhr => { const response = xhr.response.body templateID = response.metadata.pid cy.log(templateID) // 此时templateID正确 // 把所有依赖templateID的操作移到这里 cy.log(templateID) // 现在能拿到正确值了 // 后续测试步骤... // 最后执行清理操作 cy.request('DELETE', `/api/templates/${templateID}`) }) }); });
方案2:使用Cypress别名存储ID(跨测试用例复用)
如果你需要在多个it测试块之间复用这个ID,可以用cy.wrap().as()把ID存为别名,后续通过cy.get('@aliasName')获取,保证异步执行顺序:
describe('Templates', function() { before('before once', function() { cy.server(); cy.route({method: 'POST', url:'/api/templates/'}).as('api_template_create') cy.visit(''); }); it('Create a new template', function() { cy.get('.my-form #type').select('book') cy.get('.my-form #title').type('Cyress title test') // ...其他表单操作 cy.get('.my-form input:submit').click() cy.wait('@api_template_create').then(xhr => { const templateID = xhr.response.body.metadata.pid cy.wrap(templateID).as('newTemplateID') // 存为别名 cy.log(templateID) }) }); it('Use the created template ID', function() { cy.get('@newTemplateID').then(templateID => { // 在这里使用templateID做后续操作,比如验证或者清理 cy.log(templateID) // 正确获取到ID cy.request('DELETE', `/api/templates/${templateID}`) }) }); });
方案3:使用Cypress环境变量(适合测试后清理)
如果只是需要在测试结束时统一清理资源,可以把ID存到Cypress的环境变量中,在after钩子中调用:
describe('Templates', function() { before('before once', function() { cy.server(); cy.route({method: 'POST', url:'/api/templates/'}).as('api_template_create') cy.visit(''); }); after('Clean up created template', function() { const templateID = Cypress.env('newTemplateID') if (templateID) { cy.request('DELETE', `/api/templates/${templateID}`) } }) it('Create a new template', function() { cy.get('.my-form #type').select('book') cy.get('.my-form #title').type('Cyress title test') // ...其他表单操作 cy.get('.my-form input:submit').click() cy.wait('@api_template_create').then(xhr => { const templateID = xhr.response.body.metadata.pid Cypress.env('newTemplateID', templateID) // 存入环境变量 cy.log(templateID) }) }); });
额外提示
如果你的Cypress版本在v6及以上,官方推荐使用cy.intercept()代替旧的cy.server()和cy.route(),替换后代码更简洁:
// 替换原来的cy.server()和cy.route() cy.intercept('POST', '/api/templates/').as('api_template_create')
内容的提问来源于stack exchange,提问作者Renaud Michotte
相关产品推荐
相关产品推荐

