> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testdino.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Playwright Code Coverage

> Collect and track Playwright code coverage in TestDino.

<Callout icon="book-open" color="#3B82F6">
  **What you'll learn**

  * How to set up Istanbul instrumentation for coverage collection
  * How to configure the streaming reporter with coverage enabled
  * How coverage data merges across sharded runs
</Callout>

Code coverage shows how much of your application code runs during tests. TestDino collects coverage from your Playwright tests, merges data across shards, and displays a per-file breakdown on the dashboard.

<Warning>
  **Warning**

  Code coverage requires the `@testdino/playwright` streaming reporter, which is currently in **Experimental**. The standard `tdpw upload` CLI does not support coverage collection. See [Real-Time Streaming](/guides/playwright-real-time-test-streaming) for setup.
</Warning>

## Quick Reference

| Topic                                               | Link                                             |
| :-------------------------------------------------- | :----------------------------------------------- |
| [Coverage metrics](#coverage-metrics)               | Statements, branches, functions, lines           |
| [Instrument your app](#instrument-your-application) | babel-plugin-istanbul, nyc, vite-plugin-istanbul |
| [Enable coverage](#enable-coverage)                 | CLI flags and reporter config                    |
| [Coverage fixture](#use-the-coverage-fixture)       | Auto-fixture and manual fixture                  |
| [Sharded runs](#sharded-runs)                       | Merge coverage across CI shards                  |
| [Data handling](#data-handling)                     | What gets uploaded and stored                    |
| [Troubleshooting](#troubleshooting)                 | Common issues and fixes                          |

## Coverage Metrics

TestDino tracks four standard coverage metrics:

| Metric         | What it measures                                                     |
| :------------- | :------------------------------------------------------------------- |
| **Statements** | How many individual code statements ran                              |
| **Branches**   | How many `if`/`else` paths were taken (both the true and false side) |
| **Functions**  | How many functions were called at least once                         |
| **Lines**      | How many source lines ran                                            |

## Prerequisites

* `@testdino/playwright` installed ([CLI reference](/cli/testdino-playwright-nodejs))
* TestDino API token ([generate one](/guides/generate-api-keys))
* Your application instrumented with [Istanbul](https://istanbul.js.org/) so `window.__coverage__` is available in the browser

## Instrument Your Application

Instrumentation adds small tracking counters around every statement, branch, and function in your code. When your app runs, these counters record what was executed. The result is stored in a global `window.__coverage__` object that TestDino reads after each test.

<Warning>
  **Warning**

  Instrumented builds are for testing only. Never deploy them to production. Instrumentation slows performance by 10-30%, increases bundle size by 2-3x, and exposes your source code file structure.
</Warning>

Pick the method that matches your build tool:

<Tabs>
  <Tab title="babel-plugin-istanbul">
    Best for React apps using Babel (Create React App, Next.js with Babel, etc.).

    Install the plugin:

    ```bash theme={null}
    npm install -D babel-plugin-istanbul
    ```

    Add it to your Babel config so it only runs during test builds:

    ```json babel.config.json theme={null}
    {
      "env": {
        "test": {
          "plugins": ["istanbul"]
        }
      }
    }
    ```

    Build with instrumentation enabled:

    ```bash theme={null}
    NODE_ENV=test npm run build
    ```
  </Tab>

  <Tab title="vite-plugin-istanbul">
    Best for Vite-based apps (Vite + React, Vite + Vue, etc.).

    Install the plugin:

    ```bash theme={null}
    npm install -D vite-plugin-istanbul
    ```

    Add it to your Vite config. The `requireEnv: true` option ensures instrumentation only activates when you set `VITE_COVERAGE=true`:

    ```typescript vite.config.ts theme={null}
    import istanbul from 'vite-plugin-istanbul';

    export default defineConfig({
      plugins: [
        istanbul({
          include: 'src/*',
          exclude: ['node_modules", "test/"],
          extension: ['.js", ".ts", ".tsx"],
          requireEnv: true,
        }),
      ],
    });
    ```

    Build with instrumentation enabled:

    ```bash theme={null}
    VITE_COVERAGE=true npm run build
    ```
  </Tab>

  <Tab title="nyc instrument">
    Best when you need a standalone tool without modifying your build config.

    Install nyc:

    ```bash theme={null}
    npm install -D nyc
    ```

    Instrument your source into a separate directory:

    ```bash theme={null}
    npx nyc instrument src instrumented-src
    ```

    Serve the `instrumented-src` directory for your test runs.
  </Tab>
</Tabs>

### Recommended Build Strategy

Only use instrumented builds for test environments. All other environments should use regular builds.

| Environment  | Build Type   | `NODE_ENV`    | Purpose                   |
| :----------- | :----------- | :------------ | :------------------------ |
| Development  | Regular      | `development` | Local development         |
| Testing / QA | Instrumented | `test`        | E2E tests with coverage   |
| Staging      | Regular      | `production`  | Pre-production validation |
| Production   | Regular      | `production`  | Live users                |

## Enable Coverage

There are two ways to enable coverage: CLI flags or reporter config. Both produce the same result.

### CLI Flags

Pass coverage flags directly to `tdpw test`:

```bash theme={null}
npx tdpw test --coverage
```

Generate a local HTML report alongside the dashboard upload:

```bash theme={null}
npx tdpw test --coverage --coverage-report --coverage-report-dir=./coverage-report
```

| Flag                    | Description                                                   |
| :---------------------- | :------------------------------------------------------------ |
| `--coverage`            | Enable coverage collection                                    |
| `--coverage-report`     | Generate a local Istanbul HTML report                         |
| `--coverage-report-dir` | Output directory for the local report (default: `./coverage`) |

CLI flags override reporter config options. See the [Node.js CLI reference](/cli/testdino-playwright-nodejs) for all available flags.

### Reporter Config

Add the `coverage` option to the `@testdino/playwright` reporter in your Playwright config:

```typescript playwright.config.ts theme={null}
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['list"],
    ['@testdino/playwright', {
      token: process.env.TESTDINO_TOKEN,
      coverage: {
        enabled: true,
        localReport: true,
        localReportDir: './coverage-report',
      },
    }],
  ],
  projects: [
    { name: 'chromium', use: { browserName: 'chromium' } },
    { name: 'firefox', use: { browserName: 'firefox' } },
    { name: 'webkit', use: { browserName: 'webkit' } },
  ],
  use: {
    baseURL: 'http://localhost:3000',
  },
});
```

### Coverage Options

| Option           | Type      | Default      | Description                           |
| :--------------- | :-------- | :----------- | :------------------------------------ |
| `enabled`        | `boolean` | `false`      | Turn on coverage collection           |
| `localReport`    | `boolean` | `false`      | Generate a local Istanbul HTML report |
| `localReportDir` | `string`  | `./coverage` | Output directory for the local report |

## Use the Coverage Fixture

The fixture is the piece that reads `window.__coverage__` from the browser after each test finishes. The reporter then merges all the collected data and sends it to TestDino.

<Tabs>
  <Tab title="Auto-fixture (Recommended)">
    Change your import from `@playwright/test` to `@testdino/playwright`. Everything else stays the same:

    ```typescript tests/example.spec.ts theme={null}
    import { test, expect } from '@testdino/playwright';

    test('homepage loads', async ({ page }) => {
      await page.goto('/');
      await expect(page.locator('h1')).toBeVisible();
    });
    ```

    Coverage collection runs automatically after each test. No other code changes needed.
  </Tab>

  <Tab title="Manual fixture">
    If you already have a custom test fixture setup, extend it with coverage:

    ```typescript tests/fixtures.ts theme={null}
    import { test as base } from '@playwright/test';
    import { coverageFixtures } from '@testdino/playwright';

    export const test = base.extend(coverageFixtures);
    export { expect } from '@playwright/test';
    ```

    Then use your extended test in spec files:

    ```typescript tests/example.spec.ts theme={null}
    import { test, expect } from './fixtures';

    test('homepage loads', async ({ page }) => {
      await page.goto('/');
      await expect(page.locator('h1')).toBeVisible();
    });
    ```
  </Tab>
</Tabs>

## Run Tests

<Steps>
  <Step title="Start the instrumented application">
    Run your app using the instrumented test build:

    ```bash theme={null}
    NODE_ENV=test npm start
    ```
  </Step>

  <Step title="Set your API token">
    ```bash theme={null}
    export TESTDINO_TOKEN="your-api-token"
    ```
  </Step>

  <Step title="Run Playwright tests">
    ```bash theme={null}
    npx playwright test
    ```
  </Step>

  <Step title="Review results">
    After tests complete, the console prints a coverage summary table.

    If `localReport` is enabled, open `./coverage-report/index.html` for the full Istanbul HTML report.

    Open the test run in [TestDino](https://app.testdino.com) and select the **Coverage** tab to see overall metrics and a per-file breakdown.
  </Step>
</Steps>

## Sharded Runs

When you split tests across multiple CI shards, each shard collects coverage only for the tests it runs. TestDino merges all shard data into one combined report.

**Step 1:** Set a CI run ID so all shards group into one test run:

```bash theme={null}
export TESTDINO_CI_RUN_ID=$CI_PIPELINE_ID
```

**Step 2:** Run each shard:

```bash theme={null}
npx playwright test --shard=1/3
npx playwright test --shard=2/3
npx playwright test --shard=3/3
```

**How merging works:** The server takes the union of covered lines from every shard. If shard 1 covers lines 1-50 of `auth.ts` and shard 2 covers lines 30-80, the merged report shows lines 1-80 as covered.

### Example CI Workflow

```yaml .github/workflows/coverage.yml theme={null}
name: Playwright Coverage
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shard: [1/3, 2/3, 3/3]
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Build for coverage
        run: NODE_ENV=test npm run build

      - name: Run tests
        env:
          TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
        run: npx playwright test --shard=${{ matrix.shard }}
```

## Data Handling

TestDino uploads only coverage metrics (percentages and hit counts per file). No source code, raw coverage maps, or `window.__coverage__` payloads are stored on the server.

| Data                                                     | Stored on server | Purpose                           |
| :------------------------------------------------------- | :--------------- | :-------------------------------- |
| Per-run summary (statements, branches, functions, lines) | Yes              | Dashboard summary tiles           |
| Per-file metrics (path, percentages, hit counts)         | Yes              | File-by-file breakdown and trends |
| Source code                                              | No               | Never leaves your machine         |
| Raw Istanbul coverage maps                               | No               | Processed locally, then discarded |

<Note>
  **Note**

  When `window.__coverage__` is not present in the browser, the reporter skips coverage collection and proceeds normally. Tests run without any performance impact.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="No coverage data collected">
    Open your app in the browser and type `window.__coverage__` in the DevTools console. If it returns `undefined`, your app is not instrumented.

    Check that:

    * Your build command uses `NODE_ENV=test` or `VITE_COVERAGE=true`
    * `coverage.enabled` is set to `true` in the reporter config
    * Your test files import `test` from `@testdino/playwright` (not `@playwright/test`)
  </Accordion>

  <Accordion title="Coverage only from one browser">
    This is expected when `coverage.projects` is set to a single browser (for example, `['chromium"]`). To collect coverage from all browsers, remove the `projects` option.
  </Accordion>

  <Accordion title="Missing files in coverage report">
    Only files that run during tests appear in the report. If a file shows 0% or is missing, no test triggered the code path that imports it.

    To include all source files (even untouched ones), configure your Istanbul tool's `include`/`exclude` settings to cover the full source directory.
  </Accordion>

  <Accordion title="Branch coverage is lower than line coverage">
    This is normal. Branch coverage counts both sides of every `if`/`else`. If your tests only exercise one side (for example, the success path but not the error path), branch coverage drops while line coverage stays higher.
  </Accordion>

  <Accordion title="Debug coverage collection">
    Enable debug logging to see what the reporter collects:

    ```typescript theme={null}
    ['@testdino/playwright', {
      token: process.env.TESTDINO_TOKEN,
      debug: true,
      coverage: { enabled: true },
    }]
    ```

    Check the console for messages prefixed with `[TestDino]`.
  </Accordion>
</AccordionGroup>

## Related

Set up coverage, view per-run reports, and configure CI.

<CardGroup cols={2}>
  <Card title="Test Run Coverage" icon="chart-bar" href="/platform/playwright-test-runs/coverage">
    Per-run coverage breakdown by file
  </Card>

  <Card title="Coverage Analytics" icon="chart-line" href="/platform/analytics/playwright-code-coverage">
    Coverage trends across runs and environments
  </Card>

  <Card title="Node.js CLI" icon="node-js" href="/cli/testdino-playwright-nodejs">
    Reporter configuration and CLI options
  </Card>

  <Card title="CI Integration" icon="microchip" href="/guides/playwright-github-actions">
    Set up Playwright in GitHub Actions
  </Card>
</CardGroup>
