or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

coverage-provider-browser.mdcoverage-provider-node.mdindex.mdv8-coverage-provider.md
tile.json

coverage-provider-browser.mddocs/

Coverage Provider Module (Browser)

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.

Core Import

import coverageModule from '@vitest/coverage-v8/browser';

Capabilities

Module Interface

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>;
}

Start Coverage

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:

  • Checks if coverage is already enabled; if so, returns immediately
  • Uses CDP session obtained from vitest/browser via cdp() function
  • Sends Profiler.enable command via CDP
  • Sends Profiler.startPreciseCoverage command with options:
    • callCount: true - Collect execution counts
    • detailed: true - Collect detailed coverage information
  • Marks coverage as enabled to prevent duplicate initialization

CDP Commands Used:

  • Profiler.enable - Enables the profiler in the browser
  • Profiler.startPreciseCoverage - Starts detailed coverage collection

Take Coverage

Captures 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:

  • Sends Profiler.takePreciseCoverage command via CDP to get coverage snapshot
  • Filters results to include only:
    • URLs from the same origin as window.location.origin
    • URLs not in node_modules/
    • URLs not containing __vitest_browser__ (vitest internal files)
    • URLs not containing __vitest__/assets (vitest internal assets)
    • URLs not matching the main page URL (window.location.href)
  • Transforms URLs by:
    • Removing the origin (window.location.origin)
    • Decoding URI components for readability

Returns: Object with shape:

{
  result: Array<{
    scriptId: string;
    url: string; // Relative URL, decoded
    functions: FunctionCoverage[];
  }>
}

Filtering Logic:

  1. URL must start with window.location.origin (same-origin only)
  2. URL must not contain /node_modules/ (excludes dependencies)
  3. URL must not contain __vitest_browser__ (excludes vitest runner code)
  4. URL must not contain __vitest__/assets (excludes vitest assets)
  5. URL must not equal window.location.href (excludes main test page)

URL Transformation:

// Original: "http://localhost:5173/src/components/Button.tsx"
// Transformed: "/src/components/Button.tsx"

Stop Coverage

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:

  • Does nothing (no-op)
  • Coverage collection continues until the browser tab/window is closed
  • This is necessary because browser tests share the same JavaScript runtime

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.

Get Provider

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:

  • Dynamically imports ./provider.js to avoid bundling the provider
  • Creates and returns a new instance of V8CoverageProvider
  • The provider can then be initialized with Vitest context

Types

ScriptCoverage

Browser 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;
}

Usage Example

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();

Implementation Details

CDP Session Management

The module uses a CDP session provided by vitest/browser:

  • Session is obtained via cdp() function from vitest/browser
  • Session is maintained throughout the browser test run
  • Session is not closed (shared across all tests)

Persistent Coverage State

Unlike Node.js mode, browser coverage state is persistent:

  • enabled flag prevents duplicate initialization
  • Coverage is never stopped during test execution
  • All tests accumulate coverage in the same session

URL Processing

The module performs two transformations on URLs:

  1. Origin Removal: Converts absolute URLs to relative paths

    // Before: "http://localhost:5173/src/App.tsx"
    // After: "/src/App.tsx"
  2. URI Decoding: Makes URLs readable

    // Before: "/src%20files/my%20file.tsx"
    // After: "/src files/my file.tsx"

Filtering Strategy

The filtering is more restrictive than Node.js mode because browser environments have more noise:

Excluded:

  • Cross-origin scripts (CDN scripts, external resources)
  • Dependencies (node_modules/)
  • Vitest runner code (__vitest_browser__)
  • Vitest assets (__vitest__/assets)
  • Main test page HTML (window.location.href)

Included:

  • Same-origin application code
  • Application assets (JS, TS files served by Vite)

Browser Requirements

  • Chrome/Chromium: Required for CDP support
  • CDP Access: Browser must allow CDP connections (Vitest handles this)
  • Same-Origin: Only same-origin scripts are tracked

Data Transfer Optimization

The filtering is performed in the browser to reduce data transfer:

  • Filtering happens before sending data over CDP
  • Only relevant coverage is transmitted
  • Improves performance for large applications

Platform Requirements

  • Browser: Chrome, Chromium, Edge, or any Chromium-based browser
  • CDP Support: Browser must support Chrome DevTools Protocol
  • Vitest Browser Mode: Requires @vitest/browser peer dependency
  • Not Supported: Firefox, Safari, or non-Chromium browsers

Differences from Node.js Mode

FeatureNode.js ModeBrowser Mode
APINode.js InspectorChrome DevTools Protocol
Session ManagementExplicit start/stopPersistent (no stop)
URL Formatfile:// protocolHTTP URLs (transformed to relative)
Isolate SupportYesNo
Module OffsetTracked via moduleExecutionInfoNot applicable
Coverage ScopePer-processPer-browser-tab
Filter LogicFile URLs, no node_modulesSame-origin, no vitest internals