istanbul-reporter-html-monorepo

A monorepo-focused HTML reporter for istanbul/nyc

Usage no npm install needed!

<script type="module">
  import istanbulReporterHtmlMonorepo from 'https://cdn.skypack.dev/istanbul-reporter-html-monorepo';
</script>

README

istanbul-reporter-html-monorepo

An alternate HTML reporter for Istanbul/nyc, intended for multi-project monorepos.

Istanbul (and its command-line runner nyc) is the code coverage analyzer used by the JavaScript unit test framework Jest, and is also commonly added to projects using other unit test frameworks like Mocha.

The default HTML reporter provided by Istanbul is not ideal when reporting on many projects in a large monorepo. The istanbul-reporter-html-monorepo plugin solves this problem by creating an HTML report with a single top-level summary, and then separate summary reports for each project inside the monorepo.

example screenshot

Installation

npm install --save-dev istanbul-reporter-html-monorepo

Usage

In order to produce a satisfactory report, you need to pass information about your project configuration to the reporter. You can do this either by writing this configuration to a JSON file that the reporter can read, or by creating the Reporter from code using the istanbul internals.

Using a configuration file

To use the reporter with a configuration file, create the file istanbul-reporter-options.json in your project folder, like so:

{
    "reportTitle": "Acme Corp",
    "projects": [
        { "name": "@acme/rocket-sled", "path": "vehicles/rocket-sled" },
        { "name": "@acme/jet-engine-core", "path": "libraries/jet-engine-core" }
    ],
    "defaultProjectName": "Other Files"
}

Next you'll need to gather the coverage data for your projects. One way to do that would be to loop through your projects and run nyc merge for each one.

nyc merge vehicles/rocket-sled/.nyc_output .nyc_output/rocket-sled.json
nyc merge libraries/jet-engine-core/.nyc_output .nyc_output/jet-engine-core.json

Finally, you can report using the monorepo reporter, which will use the configuration file you've created.

nyc report -r istanbul-reporter-html-monorepo

In larger monorepos, you wouldn't want to create this file by hand -- it's more likely you'll want to generate it on the fly each time from some other source of project data (a list of projects, or a glob pattern, etc.). You can override the path used to find this config file by setting the ISTANBUL_REPORTER_CONFIG environment variable.

ISTANBUL_REPORTER_CONFIG=temp/options.json nyc report -r istanbul-reporter-html-monorepo

Using from code

Let's say you have a custom monorepo for Acme Corp, containing several subfolders with different projects. You've already run your builds and unit tests and generated JSON file coverage for each project. Here's an example of how you would generate HTML monorepo from these coverage files, using a custom script.

const fs = require('fs);
const { CoverageMap, CoverageMapData, createCoverageMap } = require('istanbul-lib-coverage');
const { Context, ReportBase, createContext } = require('istanbul-lib-report');
const createReport = require('istanbul-reports').create;

async function generateMonorepoReport() {
    const reportTitle = 'Acme Corp';
    const projects = [
        {
            name: '@acme/rocket-sled',
            path: 'vehicles/rocket-sled'
        },
        {
            name: '@acme/jet-engine-core',
            path: 'libraries/jet-engine-core'
        },
        // ... etc.
    ];

    // Build a coverage map containing coverage from all projects
    const coverageMap = createCoverageMap({});
    for (let project of projects) {
        const coverageData = JSON.parse(fs.readFileSync(`${project.path}/coverage/coverage-final.json`));
        coverageMap.merge(coverageData);
    }

    // Specify the output folder for the HTML report (in this case, we'll write to the 'coverage' folder
    // in the root of the monorepo).
    const context = createContext({
      dir: 'coverage',
      coverageMap: coverageMap
    });

    // Create and execute the report, passing in the expected options
    const htmlReport = createReport('istanbul-reporter-html-monorepo', {
        reportTitle: reportTitle,
        projects: projects,
        defaultProjectName: false
    });
    htmlReport.execute(context);
}

This example also shows how you can use the istanbul internals directly to combine coverage data, instead of repeatedly calling nyc merge, which can offer a speed improvement for larger repos.

Options

In addition to the list below, the html-monorepo reporter accepts all the options that the standard HTML reporter does.

reportTitle

The reportTitle option allows you to specify a custom title for the report, displayed in the upper-left hand corner. If missing or undefined, the default All files title is used.

projects

The projects option should contain an array of project definitions. Each project definition consists of a name and path key. Covered source files within the path specified will be considered part of that project, and will be displayed in the summary underneath the corresponding name.

Consider this project definition:

{ name: 'docs-site', path: 'src/sites/docs' }

In the summary listing and breadcrumb links, files under this folder path will be displayed under docs-site (the project name), instead of src/sites/docs (the project path).

In some cases you may prefer to use the project paths instead of the names, or your users would like to see both the file path and the project name. You can customize the name property to achieve your desired result.

// Organize by project, but display only the path
{ name: 'src/sites/docs', path: 'src/sites/docs' }

// Display as name and path
{ name: 'docs-site (src/sites/docs)', path: 'src/sites/docs' }

// Display as path and name
{ name: 'src/sites/docs [docs-site]', path: 'src/sites/docs' }

defaultProjectName

In general, your project list should cover all files that have coverage in your monorepo. If additional files are discovered that don't fall into any of your defined projects, they will be organized under the summary line Other Files. You can customize this default name by providing an alternate string value for defaultProjectName.

If you'd rather show these additional source files as "loose" source files in the root of the coverage report, you can disable the default project by specifying defaultProjectName: false.

If you want to exclude these files from the report completely, you can use nyc's built-in --exclude option in the appropriate project to ensure the files won't get covered. Alternately, you can doctor the combined coverageMap in your script and remove any files you wish to exclude before passing the coverageMap to the reporter.

Examples

See the links below for more detailed examples on how to configure html-monorepo.

Contributing

Additional improvements and bug fixes are welcome!

This project includes files that were forked from the istanbul-lib-report and istanbul-reports packages. The original copyrights and license are preserved. New functionality for the monorepo reporter is implemented in index.js, and supporting files and reporting logic can be found in the ./lib folder.

Disclaimer

This is a community project that provides additional functionality for istanbul/nyc tooling. It is not published by or affiliated with the creators of istanbul/nyc.