Cypress自动保存拦截API响应为fixture文件问题排查
问题原因
原有代码无法生成fixture文件的核心原因:
cy.*系列命令必须加入Cypress全局串行命令队列才能被调度执行,req.continue()传入的响应回调是网络层触发的独立异步回调,不属于Cypress命令链上下文,这里直接调用cy.writeFile不会被Cypress识别执行,因此没有实际写文件操作。console.log是浏览器原生API,不需要走Cypress调度,所以能正常打印日志,造成代码执行到写文件步骤的错觉。- 额外隐患:如果匹配的URL带查询参数、多层路径,直接拼接的文件路径可能包含非法文件名字符、不存在的父目录,即使writeFile执行也会失败。
正确实现步骤
第一步:(可选但推荐)在Cypress配置中注册Node层写文件任务
如果需要自动创建多级目录、格式化JSON内容,推荐在cypress.config.js中注册task,利用Node原生fs模块处理文件操作,稳定性更高:
const { defineConfig } = require("cypress"); const fs = require('fs'); const path = require('path'); module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { on('task', { saveFixture({ filePath, content }) { const fullPath = path.join(config.fixturesFolder, filePath); // 递归创建父目录,避免多级路径写入失败 fs.mkdirSync(path.dirname(fullPath), { recursive: true }); // 格式化写入JSON,方便后续手动修改查看 const writeContent = typeof content === 'object' ? JSON.stringify(content, null, 2) : content; fs.writeFileSync(fullPath, writeContent); return null; } }) } } })
第二步:修改saveResponse方法
核心是把Cypress命令包装成Cypress.Promise返回,让Cypress拦截逻辑等待写文件操作完成,同时处理路径中的非法字符:
const saveResponse = (req) => { req.continue((res) => { // 处理文件路径:移除域名、去掉查询参数、拼接json后缀 const filePath = req.url .replace('https://covfefe/', '') .split('?')[0] + '.json'; console.log('saving fixture to', filePath); // 使用自定义task写文件(推荐,兼容性更好) return new Cypress.Promise((resolve) => { cy.task('saveFixture', { filePath, content: res.body }, { log: false }) .then(resolve); }); // 如果不想修改配置,直接用内置cy.writeFile,可替换上面的Promise逻辑 // return new Cypress.Promise((resolve) => { // cy.writeFile(`cypress/fixtures/${filePath}`, res.body, { log: false }) // .then(resolve); // }); }) }
后续使用建议
第一次运行测试用例时,Cypress会自动把所有匹配规则的接口响应存到对应fixture路径下。后续测试只需要修改拦截逻辑,优先读取本地fixture,不存在时再走真实请求并自动缓存,不需要重复修改代码:
// 通用拦截逻辑,可放在support/commands.js里全局生效 const autoFixtureHandler = (req) => { const filePath = req.url .replace('https://covfefe/', '') .split('?')[0] + '.json'; // 先尝试读本地fixture cy.fixture(filePath, { timeout: 50 }).then((fixture) => { req.reply(fixture); }).catch(() => { // 本地不存在fixture时走真实请求,自动保存 req.continue((res) => { return new Cypress.Promise((resolve) => { cy.task('saveFixture', { filePath, content: res.body }, { log: false }) .then(() => resolve()); }); }); }); } // 测试用例里直接传入handler即可 cy.intercept('https://covfefe/redfish/v1/Chassis/Asrock/PCIeDevices/**', autoFixtureHandler)
内容的提问来源于stack exchange,提问作者activedecay
相关产品推荐
相关产品推荐

