Jest Coverage Merging
Jest is a popular JavaScript testing framework that provides powerful code coverage reporting. Often, you might run tests across multiple environments or configurations, resulting in separate coverage reports. This challenge focuses on implementing a mechanism to merge these individual coverage reports into a single, consolidated report, providing a holistic view of your codebase's test coverage.
Problem Description
Your task is to create a function that takes an array of Jest coverage report objects (typically JSON files generated by Jest's --coverage=true option) and merges them into a single, coherent coverage report object.
Key Requirements:
- File-Level Merging: For each file present in any of the input reports, its coverage data (lines hit, branches covered, etc.) should be aggregated. If a file appears in multiple reports, its metrics should be summed up.
- Global Metrics Aggregation: The global coverage metrics (total lines, hits, branches, etc.) for the merged report should be the sum of the global metrics from all input reports.
- Handling Missing Files: If a file exists in one report but not another, it should still be included in the merged report with its original data.
- Structure Preservation: The output merged report should maintain the same hierarchical structure as the input Jest coverage reports.
Expected Behavior:
The function should accept an array of coverage report objects and return a single coverage report object.
Edge Cases:
- An empty input array of reports.
- Input reports with no files.
- Reports with identical file paths.
Examples
Example 1:
Input:
[
{
"total": {
"lines": { "total": 10, "hit": 5 },
"branches": { "total": 4, "hit": 2 }
},
"data": {
"file1.js": {
"lines": { "total": 10, "hit": 5 },
"branches": { "total": 4, "hit": 2 }
}
}
},
{
"total": {
"lines": { "total": 5, "hit": 3 },
"branches": { "total": 2, "hit": 1 }
},
"data": {
"file1.js": {
"lines": { "total": 5, "hit": 3 },
"branches": { "total": 2, "hit": 1 }
}
}
}
]
Output:
{
"total": {
"lines": { "total": 15, "hit": 8 },
"branches": { "total": 6, "hit": 3 }
},
"data": {
"file1.js": {
"lines": { "total": 15, "hit": 8 },
"branches": { "total": 6, "hit": 3 }
}
}
}
Explanation: The total metrics are summed (10+5=15 lines, 5+3=8 hits; 4+2=6 branches, 2+1=3 hits). The data for file1.js is also summed.
Example 2:
Input:
[
{
"total": {
"lines": { "total": 10, "hit": 5 },
"branches": { "total": 4, "hit": 2 }
},
"data": {
"file1.js": {
"lines": { "total": 10, "hit": 5 },
"branches": { "total": 4, "hit": 2 }
}
}
},
{
"total": {
"lines": { "total": 8, "hit": 6 },
"branches": { "total": 3, "hit": 2 }
},
"data": {
"file2.js": {
"lines": { "total": 8, "hit": 6 },
"branches": { "total": 3, "hit": 2 }
}
}
}
]
Output:
{
"total": {
"lines": { "total": 18, "hit": 11 },
"branches": { "total": 7, "hit": 4 }
},
"data": {
"file1.js": {
"lines": { "total": 10, "hit": 5 },
"branches": { "total": 4, "hit": 2 }
},
"file2.js": {
"lines": { "total": 8, "hit": 6 },
"branches": { "total": 3, "hit": 2 }
}
}
}
Explanation: file1.js is only in the first report. file2.js is only in the second. The total metrics are summed. The files are combined in the data object.
Example 3: Empty Input
Input:
[]
Output:
{
"total": {
"lines": { "total": 0, "hit": 0 },
"branches": { "total": 0, "hit": 0 }
},
"data": {}
}
Explanation: An empty input array results in an empty, zeroed-out coverage report.
Constraints
- The input
reportswill be an array of objects, each conforming to the Jest coverage report JSON structure. - Each coverage report object will have a
totalobject and adataobject. - The
totalobject containslinesandbranches(and potentially others, but focus on these two) withtotalandhitproperties. - The
dataobject is a map where keys are file paths (strings) and values are similar coverage metric objects as intotal. - The number of input reports will not exceed 100.
- The total number of files across all reports will not exceed 10,000.
Notes
- You'll need to define the TypeScript interfaces for the Jest coverage report structure to ensure type safety.
- Consider how to handle different types of coverage metrics if they exist (e.g., functions, statements) – for this challenge, focus on
linesandbranches. - The
totalmetrics for a report are essentially the aggregated metrics of all files within itsdataobject. Your merging logic should reflect this. - Think about how to efficiently aggregate data, especially when dealing with a large number of files and reports.
- A helper function to merge individual metric objects (like
linesorbranches) might be useful.