V8 Coverage Data
Collecting V8 Coverage Data
Before coverage collection: Enabling
sourcemapfor source code- webpack:
devtool: source-mapandmode: development, example webpack.config-v8.js - rollup:
sourcemap: trueandtreeshake: false - esbuild:
sourcemap: true,treeShaking: falseandminify: false - vite:
sourcemap: trueandminify: false
- webpack:
Browser (Chromium-based Only)
Node.js
CDP
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=dirbefore the program running, the coverage data will be saved to thedirafter the program exits gracefully. - Read the JSON file(s) from the
dirand generate coverage report. - Example:
cross-env NODE_V8_COVERAGE=
.temp/v8-coverage-envnode ./test/test-node-env.js && node ./test/generate-report.js- Sets Node.js env
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-apinode ./test/test-node-api.js- Writing the coverage started by NODE_V8_COVERAGE to disk on demand with
Inspector API
- Connecting to the V8 inspector and enable V8 coverage.
- Taking coverage data and adding it to the report.
- Example:
- vm Example (scriptOffset):
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 thev8.takeCoverage()interface can be accomplished through theRuntime.evaluateof the CDP. - Example for koa web server:
- When the program starts a server, it will not exit on its own, thus requiring a manual invocation of the
Child Process + NODE_V8_COVERAGE
- see Command Line
V8 Coverage Data API
- JavaScript code coverage in V8
- Playwright Coverage Class
- Puppeteer Coverage Class
- DevTools Protocol for Coverage see ScriptCoverage and v8-coverage
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 Runtime | V8 Coverage | |
|---|---|---|
| Chrome (65%) | ✅ | Chromium-based |
| Safari (18%) | ❌ | |
| Edge (5%) | ✅ | Chromium-based |
| Firefox (2%) | ❌ | |
| Node.js | ✅ | |
| Deno | ❌ | issue |
| Bun | ❌ |