Skip to content

V8 Coverage Data

Collecting V8 Coverage Data

Collecting V8 Coverage Data with Playwright

js
await Promise.all([
    page.coverage.startJSCoverage({
        // reportAnonymousScripts: true,
        resetOnNavigation: false
    }),
    page.coverage.startCSSCoverage({
        // Note, anonymous styles (without sourceURLs) are not supported, alternatively, you can use CDPClient
        resetOnNavigation: false
    })
]);

await page.goto("your page url");

const [jsCoverage, cssCoverage] = await Promise.all([
    page.coverage.stopJSCoverage(),
    page.coverage.stopCSSCoverage()
]);

const coverageData = [... jsCoverage, ... cssCoverage];

Collect coverage with @playwright/test Automatic fixtures, see example: fixtures.ts For more examples, see ./test/test-v8.js, css

Collecting Raw V8 Coverage Data with Puppeteer

js
await Promise.all([
    page.coverage.startJSCoverage({
        // reportAnonymousScripts: true,
        resetOnNavigation: false,
        // provide raw v8 coverage data
        includeRawScriptCoverage: true
    }),
    page.coverage.startCSSCoverage({
        resetOnNavigation: false
    })
]);

await page.goto("your page url");

const [jsCoverage, cssCoverage] = await Promise.all([
    page.coverage.stopJSCoverage(),
    page.coverage.stopCSSCoverage()
]);

// to raw V8 script coverage
const coverageData = [... jsCoverage.map((it) => {
    return {
        source: it.text,
        ... it.rawScriptCoverage
    };
}), ... cssCoverage];

Example: ./test/test-puppeteer.js

Collecting V8 Coverage Data from Node.js

Possible solutions:

  • NODE_V8_COVERAGE=dir

    • Sets Node.js env NODE_V8_COVERAGE=dir before the program running, the coverage data will be saved to the dir after the program exits gracefully.
    • Read the JSON file(s) from the dir and generate coverage report.
    • Example:

    cross-env NODE_V8_COVERAGE=.temp/v8-coverage-env node ./test/test-node-env.js && node ./test/generate-report.js

  • V8 API + NODE_V8_COVERAGE

    • Writing the coverage started by NODE_V8_COVERAGE to disk on demand with v8.takeCoverage(), it does not require waiting until the program exits gracefully.
    • Example:

    cross-env NODE_V8_COVERAGE=.temp/v8-coverage-api node ./test/test-node-api.js

  • Inspector API

    • Connecting to the V8 inspector and enable V8 coverage.
    • Taking coverage data and adding it to the report.
    • Example:

    node ./test/test-node-ins.js

    • vm Example (scriptOffset):

    node ./test/test-node-vm.js

  • CDP API

    • Enabling Node Debugging.
    • Collecting coverage data with CDP API.
    • Example:

    node --inspect=9229 ./test/test-node-cdp.js

  • Node Debugging + CDP + NODE_V8_COVERAGE + V8 API

    • When the program starts a server, it will not exit on its own, thus requiring a manual invocation of the v8.takeCoverage() interface to manually collect coverage data. Remote invocation of the v8.takeCoverage() interface can be accomplished through the Runtime.evaluate of the CDP.
    • Example for koa web server:

    node ./test/test-node-koa.js

  • Child Process + NODE_V8_COVERAGE

V8 Coverage Data API

js
// Coverage data for a source range.
export interface CoverageRange {
    // JavaScript script source offset for the range start.
    startOffset: integer;
    // JavaScript script source offset for the range end.
    endOffset: integer;
    // Collected execution count of the source range.
    count: integer;
}
// Coverage data for a JavaScript function.
/**
 * @functionName can be an empty string.
 * @ranges is always non-empty. The first range is called the "root range".
 * @isBlockCoverage indicates if the function has block coverage information.
    If this is false, it usually means that the functions was never called.
    It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
*/
export interface FunctionCoverage {
    // JavaScript function name.
    functionName: string;
    // Source ranges inside the function with coverage data.
    ranges: CoverageRange[];
    // Whether coverage data for this function has block granularity.
    isBlockCoverage: boolean;
}
// Coverage data for a JavaScript script.
export interface ScriptCoverage {
    // JavaScript script id.
    scriptId: Runtime.ScriptId;
    // JavaScript script name or url.
    url: string;
    // Functions contained in the script that has coverage data.
    functions: FunctionCoverage[];
}
export type V8CoverageData = ScriptCoverage[];

Runtime Support

JavaScript RuntimeV8 Coverage
Chrome (65%)Chromium-based
Safari (18%)
Edge (5%)Chromium-based
Firefox (2%)
Node.js
Denoissue
Bun

Released under the MIT License.