Cypress中对比两个JSON文件并输出差异的实现方法
在Cypress中对比JSON文件:忽略属性顺序,仅检测缺失属性与值差异
在用Cypress编写测试用例对比两个JSON文件时,会遇到三类问题:部分属性缺失、属性顺序不一致、属性值存在差异。直接使用cy.readFile()配合deep.equal断言会因为属性顺序不同直接报错,无法获取完整的缺失/差异信息。需要实现自定义对比逻辑,忽略属性顺序,仅检测并打印缺失属性和值差异到控制台。
示例文件
file1.json(预期文件)
{ "isActive": true, "isLocked": false, "phone": null, "details": [ { "firstName":"test1", "lastName": "last1", "userId": "testuser1", "lastLoggedIn": "2024-01-01" } ] }
file2.json(实际文件)
{ "isActive": true, "phone": "123-456-7890", "details": [ { "firstName":"test1", "userId": "testuser1", "lastLoggedIn": "2024-01-02" } ], "isLocked": false }
期望控制台输出
+ expected - actual - "phone": "123-456-7890", "details": [ { - lastLoggedIn: "2024-01-02" } ] -- + "phone": null, "details": [ { + lastName: "last1", + lastLoggedIn: "2024-01-01" } ]
解决方案
1. 编写自定义JSON对比函数
该函数递归遍历对象和数组,忽略属性顺序,收集三类差异:实际文件缺失的属性、实际文件多余的属性、属性值不一致的情况。
function compareJSON(expected, actual) { const diff = { missing: [], // actual中缺失的属性(expected有,actual无) extra: [], // actual中多出来的属性(expected无,actual有) mismatched: [] // 属性值不一致的情况 }; // 对比对象 if (typeof expected === 'object' && expected !== null && typeof actual === 'object' && actual !== null) { const expectedKeys = Object.keys(expected).sort(); const actualKeys = Object.keys(actual).sort(); // 查找缺失属性 expectedKeys.forEach(key => { if (!actualKeys.includes(key)) { diff.missing.push(`+ ${key}: ${JSON.stringify(expected[key])}`); } else { // 递归对比嵌套属性 const nestedDiff = compareJSON(expected[key], actual[key]); if (nestedDiff.missing.length || nestedDiff.extra.length || nestedDiff.mismatched.length) { diff.mismatched.push(`- ${key}: ${JSON.stringify(actual[key])}`); diff.mismatched.push(`+ ${key}: ${JSON.stringify(expected[key])}`); } } }); // 查找多余属性 actualKeys.forEach(key => { if (!expectedKeys.includes(key)) { diff.extra.push(`- ${key}: ${JSON.stringify(actual[key])}`); } }); } // 对比数组(默认匹配对应位置元素,若需忽略顺序可额外修改排序逻辑) else if (Array.isArray(expected) && Array.isArray(actual)) { const maxLength = Math.max(expected.length, actual.length); for (let i = 0; i < maxLength; i++) { if (i >= actual.length) { diff.missing.push(`+ [${i}]: ${JSON.stringify(expected[i])}`); } else if (i >= expected.length) { diff.extra.push(`- [${i}]: ${JSON.stringify(actual[i])}`); } else { const nestedDiff = compareJSON(expected[i], actual[i]); if (nestedDiff.missing.length || nestedDiff.extra.length || nestedDiff.mismatched.length) { diff.mismatched.push(`- [${i}]: ${JSON.stringify(actual[i])}`); diff.mismatched.push(`+ [${i}]: ${JSON.stringify(expected[i])}`); } } } } // 对比基本类型值 else { if (expected !== actual) { diff.mismatched.push(`- ${JSON.stringify(actual)}`); diff.mismatched.push(`+ ${JSON.stringify(expected)}`); } } return diff; }
2. 在Cypress测试用例中调用函数
读取两个JSON文件,执行对比逻辑,格式化输出差异到控制台:
cy.readFile('../src/cypress/fixtures/file1.json').then(expected => { cy.readFile('../src/cypress/fixtures/file2.json').then(actual => { const diff = compareJSON(expected, actual); // 格式化输出差异 console.log('+ expected - actual\n'); console.log('- actual differences:\n'); if (diff.extra.length) console.log(diff.extra.join('\n')); const actualMismatches = diff.mismatched.filter(line => line.startsWith('-')); if (actualMismatches.length) console.log(actualMismatches.join('\n')); console.log('\n--\n'); console.log('+ expected differences:\n'); if (diff.missing.length) console.log(diff.missing.join('\n')); const expectedMismatches = diff.mismatched.filter(line => line.startsWith('+')); if (expectedMismatches.length) console.log(expectedMismatches.join('\n')); // 可选:若需测试失败,可根据差异是否存在断言 if (diff.missing.length || diff.extra.length || diff.mismatched.length) { throw new Error('JSON文件存在差异'); } }); });
内容的提问来源于stack exchange,提问作者S K
相关产品推荐
相关产品推荐

