Hone logo
Hone
Problems

Jest Coverage Merging Utility

Jest's built-in coverage reporting can be limited when running tests across multiple files or directories. This challenge asks you to implement a utility function that merges multiple Jest coverage reports into a single, consolidated report. This is particularly useful for CI/CD pipelines or projects with a modular structure where you want a holistic view of test coverage.

Problem Description

You need to create a TypeScript function mergeCoverageReports that takes an array of Jest coverage report file paths as input and returns a single, merged coverage report object. The input files are expected to be in the standard Jest coverage JSON format. The function should handle potential errors gracefully, such as invalid file paths or malformed JSON. The merged report should contain all the information from the individual reports, with any overlapping file paths having their coverage data combined appropriately (e.g., lines, functions, statements). If a file exists in multiple reports, the merged report should reflect the maximum coverage value for each line/function/statement.

Key Requirements:

  • Input: An array of strings, where each string is the path to a Jest coverage report file (JSON format).
  • Output: A single object representing the merged Jest coverage report in the same JSON format as the input files.
  • Merging Logic: For files with overlapping paths (same file being tested in different suites), the merged report should take the maximum coverage value for each line, function, and statement.
  • Error Handling: The function should handle cases where a file does not exist or contains invalid JSON. Invalid files should be logged to the console (using console.error) and skipped, without crashing the entire merging process.
  • File Structure: Assume the standard Jest coverage report structure: { paths: [ { path: string, statements: { line: number, pct: number }, functions: { line: number, pct: number }, branches: { line: number, pct: number }, ... } ] }

Expected Behavior:

  • The function should read each file in the input array.
  • It should parse the JSON content of each file.
  • It should merge the coverage data, prioritizing maximum values for overlapping file paths.
  • It should return the merged coverage report object.
  • It should log errors to the console for invalid files and continue processing other files.

Edge Cases to Consider:

  • Empty input array: Should return an empty coverage report object.
  • Files with no overlapping paths: Should simply combine the data from all files.
  • Files with identical paths and coverage data: Should result in the same data in the merged report.
  • Files with identical paths but different coverage data: Should prioritize the maximum coverage values.
  • Invalid JSON in a file: Should log an error and skip the file.
  • Non-existent file: Should log an error and skip the file.

Examples

Example 1:

Input: ["coverage1.json", "coverage2.json"]

coverage1.json:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 80 }
    },
    {
      "path": "src/file2.ts",
      "statements": { "line": 5, "pct": 100 }
    }
  ]
}

coverage2.json:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 90 }
    },
    {
      "path": "src/file3.ts",
      "statements": { "line": 8, "pct": 75 }
    }
  ]
}

Output:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 90 }
    },
    {
      "path": "src/file2.ts",
      "statements": { "line": 5, "pct": 100 }
    },
    {
      "path": "src/file3.ts",
      "statements": { "line": 8, "pct": 75 }
    }
  ]
}
Explanation: src/file1.ts has its coverage updated to 90% (maximum of 80% and 90%).  src/file2.ts and src/file3.ts are added to the merged report.

Example 2:

Input: ["coverage1.json", "invalid.json", "coverage2.json"]

coverage1.json:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 80 }
    }
  ]
}

coverage2.json:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 85 }
    }
  ]
}

Output:
{
  "paths": [
    {
      "path": "src/file1.ts",
      "statements": { "line": 10, "pct": 85 }
    }
  ]
}
Explanation: invalid.json is skipped due to being invalid JSON. src/file1.ts coverage is updated to 85%.

Constraints

  • The function must be written in TypeScript.
  • The input array can contain up to 100 file paths.
  • Each coverage report file is expected to be less than 1MB in size.
  • The function should complete within 5 seconds for a reasonable number of files (e.g., 10).
  • The function should not modify the original coverage report files.

Notes

  • Consider using asynchronous file reading to improve performance.
  • You can use a library like fs/promises for asynchronous file operations.
  • Think about how to efficiently merge the data without unnecessary iterations. A Map might be useful for tracking coverage data by file path.
  • Focus on handling errors gracefully and providing informative error messages.
  • The structure of the Jest coverage report is crucial; ensure your merging logic correctly handles it.
Loading editor...
typescript