The browser coverage provider module implements the CoverageProviderModule interface for browser environments. It manages the V8 profiler lifecycle using Chrome DevTools Protocol (CDP) to collect coverage data in browser-based testing scenarios.
import coverageModule from '@vitest/coverage-v8/browser';The default export implements the CoverageProviderModule interface with lifecycle methods for coverage collection in browsers:
interface CoverageProviderModule {
/**
* Initialize V8 coverage collection using Chrome DevTools Protocol
*/
startCoverage(): Promise<void>;
/**
* Take a snapshot of current V8 coverage data from the browser
* @returns Object containing array of script coverage results
*/
takeCoverage(): Promise<{ result: any[] }>;
/**
* Stop coverage collection (no-op in browser mode)
*/
stopCoverage(): void;
/**
* Factory method to get the V8CoverageProvider instance
* @returns Promise resolving to V8CoverageProvider instance
*/
getProvider(): Promise<V8CoverageProvider>;
}Initializes V8 coverage collection in the browser using Chrome DevTools Protocol.
/**
* Initialize V8 coverage collection in browser using Chrome DevTools Protocol.
* Creates a CDP session via vitest/browser, enables the Profiler, and starts
* precise coverage collection.
*
* @returns Promise that resolves when coverage collection is started
*
* @example
* import coverageModule from '@vitest/coverage-v8/browser';
*
* // Start coverage collection in browser
* await coverageModule.startCoverage();
*/
function startCoverage(): Promise<void>;Behavior:
vitest/browser via cdp() functionProfiler.enable command via CDPProfiler.startPreciseCoverage command with options:
callCount: true - Collect execution countsdetailed: true - Collect detailed coverage informationCDP Commands Used:
Profiler.enable - Enables the profiler in the browserProfiler.startPreciseCoverage - Starts detailed coverage collectionCaptures a snapshot of the current coverage data from the browser's V8 engine.
/**
* Take a snapshot of current V8 coverage data from the browser.
* Retrieves coverage via CDP and filters out irrelevant files (external origins,
* node_modules, vitest internals). Transforms URLs to be relative to the application.
*
* @returns Promise resolving to object containing array of filtered script coverage results
*
* @example
* import coverageModule from '@vitest/coverage-v8/browser';
*
* const { result } = await coverageModule.takeCoverage();
* console.log(`Collected coverage for ${result.length} files`);
*
* // Each result has:
* // - scriptId: unique identifier
* // - url: relative URL (decoded, with origin removed)
* // - functions: array of function coverage data
*/
function takeCoverage(): Promise<{ result: any[] }>;Behavior:
Profiler.takePreciseCoverage command via CDP to get coverage snapshotwindow.location.originnode_modules/__vitest_browser__ (vitest internal files)__vitest__/assets (vitest internal assets)window.location.href)window.location.origin)Returns: Object with shape:
{
result: Array<{
scriptId: string;
url: string; // Relative URL, decoded
functions: FunctionCoverage[];
}>
}Filtering Logic:
window.location.origin (same-origin only)/node_modules/ (excludes dependencies)__vitest_browser__ (excludes vitest runner code)__vitest__/assets (excludes vitest assets)window.location.href (excludes main test page)URL Transformation:
// Original: "http://localhost:5173/src/components/Button.tsx"
// Transformed: "/src/components/Button.tsx"In browser mode, this is a no-op because the V8 instance is shared across all tests.
/**
* Stop coverage collection.
* This is a no-op in browser mode because the same V8 instance is shared
* between all tests. Stopping coverage would affect subsequent tests.
*
* @example
* import coverageModule from '@vitest/coverage-v8/browser';
*
* // This does nothing in browser mode
* coverageModule.stopCoverage();
*/
function stopCoverage(): void;Behavior:
Rationale: In browser testing, all test files run in the same JavaScript context (same browser tab). Stopping coverage after one test file would prevent coverage collection for subsequent tests. The browser's V8 instance must keep collecting coverage until all tests complete.
Factory method that returns an instance of the V8CoverageProvider class.
/**
* Factory method to get the V8CoverageProvider instance.
* The provider is dynamically imported to prevent bundling.
*
* @returns Promise resolving to new V8CoverageProvider instance
*
* @example
* import coverageModule from '@vitest/coverage-v8/browser';
*
* const provider = await coverageModule.getProvider();
* provider.initialize(vitestContext);
* const coverageMap = await provider.generateCoverage({ allTestsRun: true });
*/
function getProvider(): Promise<V8CoverageProvider>;Behavior:
./provider.js to avoid bundling the providerV8CoverageProviderBrowser coverage data structure from Chrome DevTools Protocol:
interface ScriptCoverage {
/** Unique script identifier assigned by V8 */
scriptId: string;
/**
* URL of the script.
* In browser mode, this is transformed to be relative to the application origin
* and URI decoded for readability.
*/
url: string;
/** Coverage entries for functions in the script */
functions: FunctionCoverage[];
}
interface FunctionCoverage {
/** Name of the function (empty string for anonymous functions) */
functionName: string;
/** Coverage ranges within the function showing which parts were executed */
ranges: Range[];
/**
* Indicates whether this is block-level coverage (true) or function-level only (false).
* When true, ranges contain detailed execution counts for code blocks.
*/
isBlockCoverage: boolean;
}
interface Range {
/** Start offset in the script source code (in characters) */
startOffset: number;
/** End offset in the script source code (in characters) */
endOffset: number;
/** Number of times this range was executed */
count: number;
}Complete usage example for browser testing:
import coverageModule from '@vitest/coverage-v8/browser';
// 1. Start coverage collection in browser
await coverageModule.startCoverage();
// 2. Run your browser tests
// ... test execution happens here ...
// 3. Take coverage snapshot after tests
const { result } = await coverageModule.takeCoverage();
console.log(`Collected coverage for ${result.length} files`);
result.forEach(({ url, functions }) => {
console.log(`File: ${url}, Functions: ${functions.length}`);
});
// 4. Stop is a no-op in browser mode
coverageModule.stopCoverage(); // Does nothing
// 5. Get provider for processing coverage data
const provider = await coverageModule.getProvider();The module uses a CDP session provided by vitest/browser:
cdp() function from vitest/browserUnlike Node.js mode, browser coverage state is persistent:
enabled flag prevents duplicate initializationThe module performs two transformations on URLs:
Origin Removal: Converts absolute URLs to relative paths
// Before: "http://localhost:5173/src/App.tsx"
// After: "/src/App.tsx"URI Decoding: Makes URLs readable
// Before: "/src%20files/my%20file.tsx"
// After: "/src files/my file.tsx"The filtering is more restrictive than Node.js mode because browser environments have more noise:
Excluded:
node_modules/)__vitest_browser__)__vitest__/assets)window.location.href)Included:
The filtering is performed in the browser to reduce data transfer:
@vitest/browser peer dependency| Feature | Node.js Mode | Browser Mode |
|---|---|---|
| API | Node.js Inspector | Chrome DevTools Protocol |
| Session Management | Explicit start/stop | Persistent (no stop) |
| URL Format | file:// protocol | HTTP URLs (transformed to relative) |
| Isolate Support | Yes | No |
| Module Offset | Tracked via moduleExecutionInfo | Not applicable |
| Coverage Scope | Per-process | Per-browser-tab |
| Filter Logic | File URLs, no node_modules | Same-origin, no vitest internals |