Cypress中如何拦截桩化cy.request()发起的请求响应?
cy.intercept() 本身确实无法拦截cy.request()发起的请求——前者的监听逻辑挂载在浏览器的网络层,只能捕获前端应用运行时在浏览器上下文里发出的请求;而cy.request()是Cypress测试运行器在Node进程侧直接发起的HTTP请求,完全绕过了浏览器的网络栈,没有办法被intercept捕获桩化。
要实现离线场景下复用响应完成测试,有几个可落地的方案:
封装请求逻辑增加环境分支(最推荐)
把获取token的逻辑抽成独立的自定义命令,通过环境变量控制走真实请求还是mock响应。第一次在线跑测试时,把真实接口返回的响应存到Cypress的fixture文件里,离线跑的时候直接读取本地存好的fixture作为响应返回即可,不需要依赖远程服务。
示例实现:// 注册到cypress/support/commands.js作为公共自定义命令 Cypress.Commands.add('fetchToken', () => { // 配置环境变量USE_MOCK=true时启用桩响应 if (Cypress.env('USE_MOCK')) { // 读取提前存好的真实响应快照 return cy.fixture('token-response.json').then(mockData => { return cy.wrap({ status: 200, headers: { 'content-type': 'application/json' }, body: mockData }) }) } // 正常环境走真实请求 return cy.request({ method: 'POST', url: 'https://sample.com/token', body: { username: "UserNameSample", password: "PasswordSample" }, form: true, }) }) // 测试用例中调用 cy.fetchToken().then(response => { cy.log(JSON.stringify(response.body)) })如果不想手动复制响应内容,可以加一段自动更新mock数据的逻辑,在线跑的时候自动把最新的真实响应写入fixture文件:
return cy.request(/* 上述真实请求配置 */).then(response => { // 仅在传入UPDATE_MOCK环境变量时执行写入,更新本地mock快照 if (Cypress.env('UPDATE_MOCK')) { cy.writeFile('cypress/fixtures/token-response.json', response.body) } return response })本地网络层代理mock
如果不想改动现有测试代码,可以在本地启动mock代理服务,通过修改Cypress代理配置或者本地host规则,把目标域名的请求转发到本地mock服务,直接返回预设的响应。这种方式对请求来源无要求,不管是浏览器侧的业务请求还是Node层cy.request()发起的请求都会被代理劫持,适合全量接口离线测试的场景,缺点是需要额外维护本地代理服务。绕路实现(不推荐)
如果非要使用cy.intercept()的桩能力,只能放弃直接用cy.request()发请求:新建一个空白测试页面,在页面内用原生fetch/XMLHttpRequest发起对应POST请求,这时候请求走浏览器网络栈,可以被cy.intercept()正常拦截桩化。但这种方式需要额外维护测试页面,实现成本高,没有实用价值。
内容的提问来源于stack exchange,提问作者E. E. Ozkan

