Cypress 10跨it测试用例多变量共享传递方案问询
Cypress 10 跨用例多值共享实现方案
核心问题本质是单key读写的task设计不适合批量场景,通过批量能力改造或封装,可以从根源上避免回调嵌套、冗余临时变量问题,同时解决外部变量方案的异步时序隐患。
方案1:改造cy.task支持批量读写(推荐)
该方案性能最优、代码最简洁,完全规避嵌套和冗余变量问题,同时兼容原有单值读写逻辑。
- 修改
cypress.config.js中的task定义,新增批量读写方法:// cypress.config.js const { defineConfig } = require("cypress"); // 原有全局变量存储容器,如果是基于文件/缓存存储替换对应逻辑即可 const globalTestStore = {}; module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { on("task", { // 保留原有单值存值逻辑兼容旧代码 setValue({ key, value }) { globalTestStore[key] = value; return null; }, // 保留原有单值取值逻辑兼容旧代码 getValue({ key }) { return globalTestStore[key] ?? null; }, // 新增批量存值方法 setBatchValues({ kvMap }) { Object.entries(kvMap).forEach(([k, v]) => { globalTestStore[k] = v; }); return null; }, // 新增批量取值方法 getBatchValues({ keys }) { return keys.reduce((res, k) => { res[k] = globalTestStore[k] ?? null; return res; }, {}); } }); return config; }, }, }); - 前置用例存值时,单次调用存入所有需要跨用例复用的字段:
it("前置接口请求获取公共测试数据", () => { cy.request("/your/biz/api").then((res) => { // 从接口响应中解构所有需要复用的字段 const { userId, token, orderId, skuId, addrId, couponId, ...restFields } = res.body; // 单次task调用完成所有值存储 cy.task("setBatchValues", { kvMap: { userId, token, orderId, skuId, addrId, couponId, ...restFields } }) }) }) - 后续用例取值时,单次调用拿到所有需要的字段,直接解构使用,无嵌套无冗余变量:
it("依赖公共参数的业务测试用例", () => { cy.task("getBatchValues", { // 传入当前用例需要的key列表即可 keys: ["userId", "token", "orderId", "skuId"] }).then(({ userId, token, orderId, skuId }) => { // 所有依赖返回值的逻辑直接写在这里,时序100%正确 if(userId === null && token === null && orderId === null && skuId === null) { // 执行业务逻辑 } }) })
注意:之前用外部let变量逐个赋值的写法存在严重异步时序隐患:Cypress命令是排队异步执行的,如果在命令队列外部直接判断临时变量,执行判断逻辑时cy.task的赋值操作还未完成,大概率会拿到undefined,批量取值的写法把逻辑放在then回调内,完全规避了这个问题。
方案2:封装前端侧批量取值命令(兼容方案)
如果不方便修改Node端的task配置,可以直接在cypress/support/commands.js中封装自定义批量取值命令,不用写嵌套回调:
// cypress/support/commands.js Cypress.Commands.add("getMultiTaskValues", (keyList) => { const valueMap = {}; // 串行执行task,避免回调嵌套 return keyList.reduce((chain, key) => { return chain.then(() => { return cy.task("getValue", { key }).then(val => { valueMap[key] = val; }) }) }, cy.wrap(null)).then(() => valueMap); })
使用时直接调用自定义命令即可,逻辑和批量task方案一致:
it("测试用例", () => { cy.getMultiTaskValues(["one", "two", "three", "four"]).then(({one, two, three, four}) => { // 直接使用解构后的变量写逻辑 if(one === null && two === null && three === null && four === null) { // 业务逻辑 } }) })
该方案缺点是仍然会多次跨进程调用cy.task,取值性能比原生批量task方案差,适合临时兼容场景使用。
内容的提问来源于stack exchange,提问作者Adrian22
相关产品推荐
相关产品推荐

