Hone logo
Hone
Problems

Jest Custom Reporter: Enhanced Test Output

This challenge focuses on extending Jest's reporting capabilities. You will learn how to create a custom reporter to process and present test results in a format that suits your specific needs, moving beyond Jest's default console output. This is incredibly useful for integrating test results into CI/CD pipelines, generating detailed reports for stakeholders, or even visualizing test outcomes.

Problem Description

Your task is to implement a custom Jest reporter that intercepts test results and formats them into a structured JSON output. This reporter should capture key information about each test suite and test case, including:

  • Suite Name: The name of the test suite.
  • Test Name: The name of the individual test case.
  • Status: Whether the test passed, failed, or was skipped.
  • Duration: The time taken to execute the test in milliseconds.
  • Error Message (if failed): The error message and stack trace if a test fails.

The reporter should aggregate this information and output it as a single JSON object at the end of the test run.

Key Requirements:

  1. Reporter Class: Create a TypeScript class that implements Jest's Reporter interface.
  2. Event Handlers: Implement the necessary event handlers (e.g., onRunComplete, onTestResult) to capture test results.
  3. Data Aggregation: Store the relevant test data as tests are executed.
  4. JSON Output: At the end of the test run, serialize the aggregated data into a JSON string and print it to the console.
  5. Configuration: Ensure the reporter can be configured in jest.config.js.

Expected Behavior:

When Jest runs with your custom reporter, it should execute all tests as usual, but instead of its default console output, it will print a JSON object to stdout containing the summarized test results.

Edge Cases to Consider:

  • Tests that are skipped.
  • Tests that have no assertions and pass by default.
  • Multiple test suites and test files.
  • Long-running tests.

Examples

Let's assume you have a simple test file math.test.ts:

// math.test.ts
describe('Math Operations', () => {
  test('should add two numbers', () => {
    expect(2 + 2).toBe(4);
  });

  test('should subtract two numbers', () => {
    expect(5 - 3).toBe(2);
  });

  test.skip('should multiply two numbers', () => {
    expect(2 * 3).toBe(6);
  });

  test('should fail a test', () => {
    expect(1).toBe(2);
  });
});

Example 1: Successful Run (All tests passing except skipped)

Input: Running jest --reporters=./path/to/your/CustomReporter.ts with the above math.test.ts.

Output:

{
  "testResults": [
    {
      "suiteName": "Math Operations",
      "tests": [
        {
          "testName": "should add two numbers",
          "status": "passed",
          "duration": 15,
          "errorMessage": null
        },
        {
          "testName": "should subtract two numbers",
          "status": "passed",
          "duration": 10,
          "errorMessage": null
        },
        {
          "testName": "should multiply two numbers",
          "status": "skipped",
          "duration": 0,
          "errorMessage": null
        },
        {
          "testName": "should fail a test",
          "status": "failed",
          "duration": 5,
          "errorMessage": "expect(1).toBe(2) // Expected: 2\n    received: 1"
        }
      ]
    }
  ],
  "runDetails": {
    "numTotalTestSuites": 1,
    "numPassedTests": 2,
    "numFailedTests": 1,
    "numSkippedTests": 1,
    "startTime": "2023-10-27T10:00:00.000Z",
    "endTime": "2023-10-27T10:00:00.025Z",
    "totalDuration": 25
  }
}

Explanation: The JSON output contains an array of testResults, where each object represents a test suite. Within each suite, there's an array of tests, detailing the name, status, duration, and error message (if any) for each test case. runDetails provides a summary of the overall test run. Durations and timestamps are illustrative.

Example 2: Handling Multiple Files and Suites

Imagine you have math.test.ts and string.test.ts with similar structures.

Input: Running jest --reporters=./path/to/your/CustomReporter.ts with both files.

Output: The JSON output would include entries for both Math Operations (from math.test.ts) and a new suite like String Operations (from string.test.ts) in the testResults array. runDetails would aggregate counts and durations across all files.

Example 3: No Tests Found

Input: Running Jest in a directory with no test files.

Output:

{
  "testResults": [],
  "runDetails": {
    "numTotalTestSuites": 0,
    "numPassedTests": 0,
    "numFailedTests": 0,
    "numSkippedTests": 0,
    "startTime": "2023-10-27T10:05:00.000Z",
    "endTime": "2023-10-27T10:05:00.000Z",
    "totalDuration": 0
  }
}

Explanation: If no tests are found, the testResults array will be empty, and runDetails will reflect zero counts and durations.

Constraints

  • The reporter must be written in TypeScript.
  • The output must be valid JSON.
  • The reporter should not interfere with Jest's standard test execution or reporting, other than providing its custom output.
  • The reporter should be able to handle a large number of test suites and test cases without significant performance degradation.

Notes

  • Refer to the Jest documentation for the Reporter interface and its available methods.
  • You'll need to configure Jest to use your custom reporter in jest.config.js using the reporters option.
  • Consider how you will handle the onRunComplete event to ensure your JSON output is printed only once at the very end of the test run.
  • The structure of the JSON output provided in the examples is a suggestion; feel free to adapt it to be more informative, as long as it's well-structured and parsable.
  • You might find it helpful to create mock test files to easily test your reporter without a large project.
Loading editor...
typescript