在Cypress中遍历数组并断言:API响应键值对匹配问题
问题描述
场景说明
我从某API调用得到如下响应数组:
[ { "IsDatalakeEnabled": true, "RecoveryHr": { "IsRecoveryHREnabled": false, "RecoveryHeartRateInterval": 120, "RecoveryHeartRateSessionTime": 300 } } ]
需要提取其中所有键值对,断言它们都存在于另一个API的响应体中,目标响应体结构片段如下:
... "StudioAddress": null, "StudioProfileLanguage": { "LanguageName": "English", "LanguageCode": "en" }, "IsDiversityChannel": true, "TotalDiversityRadios": 2, "IsDatalakeEnabled": false, "IsNetpulse": false, "RecoveryHeartRateInterval": 120, "RecoveryHeartRateSessionTime": 300, "IsRecoveryHREnabled": false, "StudioPhysicalLocationId": null, "StudioLocation": null, "IsIntroCapacityEnabled": false, "Status": null, "IsWeb": false, "OrangeBook": null, "IsFeReservationEnabled": true, "TimeZone": "America/New_York", "IsModifyMaxHr": false, "IsRunRowEnabled": false, "WeightMeasure": "LB", ...
遇到的问题
尝试用cy.each()遍历,但它把整个数组当成单个对象处理:
{ "TotalDiversityRadios": "0", "IsDatalakeEnabled": true }
也试过用_.castArray()把响应体转成数组,以及Object.entries(),都没解决问题。
2023年1月14日更新:测试代码及报错
我的测试代码如下:
validateStudioSettings() { cy.intercept('POST', '**/studio-settings').as('post') cy.contains('APPLY').should('be.enabled').click() cy.get('.dialog-content').should('be.visible').and('have.text', 'Are you sure you want to apply these settings?') cy.contains('AGREE').click() cy.get('.notification').should('be.visible').and('contain', 'Success').and('contain', 'Update studio settings successfully.') cy.wait('@post').then(post => { expect(post.response.statusCode).equal(200) expect(post.response.statusMessage).equal('OK') expect(post.response.body).equal('Update studio settings successfully.') let studios = _.castArray(post.request.body.StudioIds) let settings = _.castArray(post.request.body.Settings)//.map(([key, val]) => key + ': ' + val); console.log('Studios: ', studios) console.log('Settings: ', settings) cy.wrap(studios).each((studioId, index) => { console.log('StudioId: ', studioId, index) let idToken = localStorage.getItem("idToken") cy.request({ method: "GET", url: `/` + studioId, headers: { 'authorization-cognito': idToken } }).then(response => { cy.wrap(settings).each((setting) => { console.log('Setting: ', setting) cy.wrap(response).its('body').then(body => { let el = _.castArray(body) console.log('Body: ', el) expect(el).to.contain(setting) }) }) }) }) }) }
运行后Cypress测试器报错。
解决方案
核心问题分析
- 嵌套结构未展开:原始响应里的
RecoveryHr是嵌套对象,直接遍历外层对象会漏掉内部的键值对; - 断言方式错误:
expect(el).to.contain(setting)是数组包含对象的逻辑,但目标响应是扁平对象,这种断言不适用; _.castArray()误用:目标响应body本身就是对象,转成数组后破坏了原有结构,导致断言失败。
修正步骤
1. 编写扁平化工具函数
先把带嵌套的设置对象转成扁平的键值对集合,确保所有字段都能被遍历到:
// 扁平化嵌套对象的工具函数 const flattenSettings = (obj) => { let result = {}; for (const key in obj) { if (typeof obj[key] === 'object' && obj[key] !== null) { Object.assign(result, flattenSettings(obj[key])); } else { result[key] = obj[key]; } } return result; }
2. 调整测试代码逻辑
替换原有的处理逻辑,用扁平化后的键值对逐一断言:
validateStudioSettings() { cy.intercept('POST', '**/studio-settings').as('post') cy.contains('APPLY').should('be.enabled').click() cy.get('.dialog-content').should('be.visible').and('have.text', 'Are you sure you want to apply these settings?') cy.contains('AGREE').click() cy.get('.notification').should('be.visible').and('contain', 'Success').and('contain', 'Update studio settings successfully.') cy.wait('@post').then(post => { expect(post.response.statusCode).equal(200) expect(post.response.statusMessage).equal('OK') expect(post.response.body).equal('Update studio settings successfully.') const studios = _.castArray(post.request.body.StudioIds) // 扁平化所有设置对象,处理嵌套结构 const flattenedSettings = Object.assign({}, ...post.request.body.Settings.map(setting => flattenSettings(setting))) cy.wrap(studios).each(studioId => { const idToken = localStorage.getItem("idToken") cy.request({ method: "GET", url: `/${studioId}`, headers: { 'authorization-cognito': idToken } }).then(response => { const responseBody = response.body // 遍历扁平化后的键值对,逐一验证存在且值匹配 Object.entries(flattenedSettings).forEach(([key, value]) => { expect(responseBody).to.have.property(key, value) }) }) }) }) }
3. 关键修正点说明
- 扁平化嵌套对象:通过工具函数把
RecoveryHr内部的键值对提取到顶层,确保所有需要断言的字段都被覆盖; - 正确断言逻辑:使用
expect(responseBody).to.have.property(key, value)直接验证目标响应体包含指定键且值一致,这是针对对象的标准断言方式; - 移除无效转换:不再将目标响应
body转成数组,直接使用原始对象结构进行断言。
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

