Cypress测试中如何通过循环正确发送网络请求
Cypress循环发送请求的实现方法
先排查你现有代码的显性问题
你贴的示例存在几个基础语法错误,会直接导致请求不触发:
- for循环判断条件写反:
for(let i = 0; 0 > 3; i++)里0>3恒为false,循环体根本不会执行,属于笔误,正常应该是i < 3 expect断言语句缺少右括号,语法不合法projectId赋值行多了冗余的单引号
就算修正了这些语法错误,直接用原生同步的for/while包裹cy.request()也不会按预期运行。Cypress的所有命令(包括cy.request())都是异步排队执行的,同步循环会在Cypress命令队列开始实际执行前就跑完所有迭代,会出现变量取值错乱、请求执行顺序不符合预期的问题,和递归无关,是Cypress本身的执行机制决定的。
稳定可用的循环请求实现
不要用原生同步循环,根据你的场景选下面两种写法即可:
场景1:遍历已知数组/固定次数发请求
用cy.wrap()搭配.each()遍历,这是最稳定的官方推荐写法,所有请求会按顺序入队执行,不会出现时序问题:
const query = 'query bla bla bla' // 替换成你从数组/数据库读取到的projectId列表 const projectIdList = [/* 填入你要遍历的所有projectId */] let preResult = null; describe('Tests', () => { it('按顺序发送graphql请求并做结果断言', () => { cy.wrap(projectIdList).each((currentProjectId) => { cy.request({ method: 'POST', url: 'https://www.blabla.com/api2', body: { operationName: 'bla bla', variables: { campaignProjectId: null, ids: [ { type: 'project', id: currentProjectId } ], userData: null, }, query, }, headers: { accept: '*/*', 'content-type': 'application/json', }, }).then((response) => { const currentData = JSON.stringify(response.body.data) // 第一次请求无前置结果,从第二次开始和上一次返回做对比 if (preResult) { expect(currentData).to.equal(preResult) } // 缓存本次结果供下一次断言使用 preResult = currentData }) }) }) })
场景2:需要动态判断循环终止条件(对应while循环需求)
如果你没法提前确定遍历列表,需要根据接口返回值、动态读取的数据判断要不要继续发请求,用递归封装请求逻辑即可,保证每一次请求都在上一次执行完成后再触发:
const query = 'query bla bla bla' const MAX_LOOP_LIMIT = 10 // 必须设置最大循环次数,避免接口异常导致死循环 let loopCount = 0 let preResult = null function sendRequestRecursively() { // 循环终止条件:达到最大次数/满足你的自定义退出规则 if (loopCount >= MAX_LOOP_LIMIT) return // 这里替换成你每次动态获取projectId的逻辑(比如读数据库、从上一次响应取值) const currentProjectId = getProjectIdDynamic() cy.request({ method: 'POST', url: 'https://www.blabla.com/api2', body: { operationName: 'bla bla', variables: { campaignProjectId: null, ids: [ { type: 'project', id: currentProjectId } ], userData: null, }, query, }, headers: { accept: '*/*', 'content-type': 'application/json', }, }).then((response) => { const currentData = JSON.stringify(response.body.data) if (preResult) { expect(currentData).to.equal(preResult) } preResult = currentData loopCount++ // 发起下一次请求 sendRequestRecursively() }) } describe('Tests', () => { it('动态条件循环发送graphql请求', () => { sendRequestRecursively() }) })
注意事项
- 不要在Cypress测试逻辑里写同步死循环,会直接阻塞测试线程
- 所有依赖请求返回结果的逻辑、变量赋值,都要写在
.then()回调里,不要写在循环外层的同步代码块中 - 动态循环必须设置明确的终止上限,避免因为接口报错、逻辑异常导致测试无限运行
内容的提问来源于stack exchange,提问作者Idan QA
相关产品推荐
相关产品推荐

