Cy.intercept()循环仅首次调用,React SPA测试二次迭代失败排查
问题
存在一个包含5个地区选项的下拉框,每次迭代中Cypress点击一个选项,等待React单页应用的页面数据通过接口响应更新。但从第二次迭代开始,cy.wait(@getCountry${item.region})步骤测试失败。
原测试代码:
it('Check all world regions in selector by clicking each option', () => { cy.get<RegionsT>('@regionsData').then((regionsData) => { regionsData.regions.forEach((item) => { cy.intercept('GET', `/region/${item.region}`).as(`getCountry${item.region}`) countries.openDropdown() countries.selectDropdownItem(item.region) cy.wait(`@getCountry${item.region}`).its('response.statusCode').should('eq', 200) countries.selectCountryByIndex(0).should('contain.text', item.firstCountryName) }) }) })
我用以下实现可以通过测试,但希望用intercept()方法简化测试,请问问题出在哪里?
it('Check all world regions in selector by clicking each option', () => { cy.get<RegionsT>('@regionsData').then((regionsData) => { regionsData.regions.forEach((item) => { let prevCountryName = '' countries .getFirstCountryName() .then(($el) => { prevCountryName = $el.text() }) .then(() => { countries.openDropdown() countries.selectDropdownItem(item.region) countries.waitUntilCountriesLoaded(prevCountryName) countries.selectCountryByIndex(0).should('contain.text', item.firstCountryName) }) }) }) })
原因分析与解决方案
问题根源
- 拦截器与请求的顺序不匹配:原生
forEach是同步执行的,会一次性把所有cy.intercept和后续命令加入Cypress的异步命令队列。但Cypress的命令是按队列异步执行的,这会导致第二次迭代时,页面触发请求的时间早于拦截器注册完成的时间,cy.wait找不到对应的拦截器别名,从而失败。 - 拦截器注册时机错误:循环同步注册所有拦截器的逻辑,会导致拦截器的注册和请求的触发顺序混乱,无法保证每次迭代中拦截器先就绪再发送请求。
修正方案
改用Cypress原生的.each()命令替代forEach,它会确保每次迭代的所有命令执行完成后,再进入下一次迭代,严格保证拦截器注册、请求触发、等待响应的顺序:
it('Check all world regions in selector by clicking each option', () => { cy.get<RegionsT>('@regionsData').then((regionsData) => { // 用Cypress的each命令控制异步迭代顺序 cy.wrap(regionsData.regions).each((item) => { // 先注册当前地区的拦截器 cy.intercept('GET', `/region/${item.region}`).as(`getCountry${item.region}`) countries.openDropdown() countries.selectDropdownItem(item.region) cy.wait(`@getCountry${item.region}`).its('response.statusCode').should('eq', 200) countries.selectCountryByIndex(0).should('contain.text', item.firstCountryName) }) }) })
额外说明
Cypress的命令队列是异步执行的,原生JS的同步循环(如forEach)无法感知Cypress的命令执行状态,会导致命令顺序混乱。而.each()是Cypress专门设计的异步迭代命令,会等待当前迭代的所有命令完成后再处理下一项,完美适配Cypress的执行逻辑。
内容的提问来源于Stack Exchange,提问作者PrinceOFF
相关产品推荐
相关产品推荐

