nextcov – Collecting Test Coverage for Next.js Server Components

If you’ve ever tried to get test coverage for React Server Components, you know the frustration. Unit testing frameworks like Jest and Vitest can’t render server components — they require the full Next.js runtime. So you write E2E tests with Playwright, but then you’re left wondering: “What’s actually being covered?”

nextcov solves this problem by collecting V8 coverage from both client and server during Playwright E2E tests, then merging it with your unit and component test coverage for a complete picture.

The Testing Landscape in 2025

Modern Next.js applications have three layers that need testing:

Layer What to Test Best Tool
Utilities & Hooks Pure functions, custom hooks Vitest (unit tests)
Client Components React components with user interaction Vitest Browser Mode (component tests)
Server Components RSC, server actions, full pages Playwright (E2E tests)

Vitest Browser Mode — Great for Client Components

Vitest’s Browser Mode is excellent for component testing. It runs tests in a real browser, giving you accurate DOM behavior and event handling. Combined with @vitest/coverage-v8, you get proper coverage for your client components.

But there’s a limitation: Vitest Browser Mode only works for client components. Server components require the full Next.js runtime — they can’t be rendered in isolation.

The Server Component Gap

React Server Components (RSC) are notoriously difficult to test:

  • They run only on the server — Can’t be rendered in jsdom or even a real browser
  • Async components fetch data directly — Mocking becomes complex and unreliable
  • Tight coupling with Next.js runtime — Server actions, cookies, headers require the full framework

The practical solution? Test server components through E2E tests with Playwright, where they run in their natural environment.

But this creates a coverage gap. You have coverage from unit tests, coverage from component tests… but nothing from E2E tests.

nextcov Fills the Gap

nextcov completes the coverage picture by collecting V8 coverage during Playwright E2E tests:

Test Type Coverage Tool What It Covers
Unit (Vitest) @vitest/coverage-v8 Utilities, hooks, logic
Component (Vitest Browser) @vitest/coverage-v8 Client components
E2E (Playwright) nextcov Server components, pages, user flows

And the best part? nextcov merges all three into a single unified report.

Real Results

In a production Next.js application:

Coverage Type Lines
Unit Tests ~45%
Component Tests ~35%
E2E Tests (nextcov) ~46%
Merged ~88%

Each test type contributes coverage that others can’t reach. The merged report shows exactly what’s tested and what’s not.

The Testing Landscape in 2025

Modern Next.js applications have three layers that need testing:

Layer What to Test Best Tool
Utilities & Hooks Pure functions, custom hooks Vitest (unit tests)
Client Components React components with user interaction Vitest Browser Mode (component tests)
Server Components RSC, server actions, full pages Playwright (E2E tests)

Vitest Browser Mode — Great for Client Components

Vitest’s Browser Mode is excellent for component testing. It runs tests in a real browser, giving you accurate DOM behavior and event handling. Combined with @vitest/coverage-v8, you get proper coverage for your client components.

But there’s a limitation: Vitest Browser Mode only works for client components. Server components require the full Next.js runtime — they can’t be rendered in isolation.

The Server Component Gap

React Server Components (RSC) are notoriously difficult to test:

  • They run only on the server — Can’t be rendered in jsdom or even a real browser
  • Async components fetch data directly — Mocking becomes complex and unreliable
  • Tight coupling with Next.js runtime — Server actions, cookies, headers require the full framework

The practical solution? Test server components through E2E tests with Playwright, where they run in their natural environment.

But this creates a coverage gap. You have coverage from unit tests, coverage from component tests… but nothing from E2E tests.

nextcov Fills the Gap

nextcov completes the coverage picture by collecting V8 coverage during Playwright E2E tests:

Test Type Coverage Tool What It Covers
Unit (Vitest) @vitest/coverage-v8 Utilities, hooks, logic
Component (Vitest Browser) @vitest/coverage-v8 Client components
E2E (Playwright) nextcov Server components, pages, user flows

And the best part? nextcov merges all three into a single unified report.

Real Results

In a production Next.js application:

Coverage Type Lines
Unit Tests ~45%
Component Tests ~35%
E2E Tests (nextcov) ~46%
Merged ~88%

Each test type contributes coverage that others can’t reach. The merged report shows exactly what’s tested and what’s not.

How It Works

Unlike traditional coverage tools that work within a single Node.js process, nextcov coordinates coverage collection across three separate environments:

  1. Test Runner (Playwright) — orchestrates tests
  2. Next.js Server (Node.js) — runs server components
  3. Browser (Chromium) — runs client components

For the browser, nextcov uses Playwright’s CDP integration to collect V8 coverage. For the server, it uses Node.js’s built-in NODE_V8_COVERAGE environment variable, triggered via Chrome DevTools Protocol.

This multi-process approach is what makes nextcov unique compared to tools like c8 or @vitest/coverage-v8, which only work within a single process.

Quick Start

# Install
npm install nextcov --save-dev

# Interactive setup
npx nextcov init

The init command creates all the necessary configuration files:

  • e2e/global-setup.ts — Initialize coverage collection
  • e2e/global-teardown.ts — Finalize and generate reports
  • e2e/fixtures/test-fixtures.ts — Playwright fixture for per-test coverage
  • Updates to playwright.config.ts and next.config.ts

Then run your E2E tests with coverage:

# Build with source maps
E2E_MODE=true npm run build

# Start server with coverage enabled and run tests
NODE_V8_COVERAGE=.v8-coverage NODE_OPTIONS='--inspect=9230' npm start &
npx playwright test

Merging All Coverage

The real power comes from merging E2E coverage with your unit and component test coverage:

# Merge all coverage sources
npx nextcov merge coverage/unit coverage/component coverage/e2e -o coverage/merged

This produces a unified HTML report showing the complete coverage picture — what’s covered by unit tests, component tests, E2E tests, and what’s still missing.

Detecting V8 Coverage Blind Spots

Even with complete test coverage, V8 has limitations. Certain JSX patterns cannot be tracked for branch coverage:

// These patterns are NOT tracked by V8
function MyComponent({ error, user }) {
  return (
    <div>
      {error && <ErrorMessage />}           {/* logical AND */}
      {user ? <LoggedIn /> : <LoggedOut />} {/* ternary */}
    </div>
  )
}

nextcov includes a check command to scan your codebase for these patterns:

npx nextcov check src/

Example output:

V8 Coverage Blind Spots Found:
────────────────────────────────────────────────────────────

src/components/ReviewForm.tsx:69:9
  ⚠ JSX logical AND (V8 cannot track branch coverage)

src/components/ui/Input.tsx:25:26
  ⚠ JSX ternary operator (V8 cannot track branch coverage)

────────────────────────────────────────────────────────────
Found 2 issues in 2 files

The Complete Testing Strategy

Here’s the recommended approach for Next.js applications:

  1. Unit tests (Vitest) — Test utilities, hooks, and pure logic
  2. Component tests (Vitest Browser Mode) — Test client components in isolation
  3. E2E tests (Playwright + nextcov) — Test server components, pages, and user flows
  4. Merge coverage — Get the complete picture with nextcov merge

This gives you fast feedback from unit and component tests during development, comprehensive E2E tests for critical user flows, and a unified coverage report that shows exactly what’s tested.

Features

  • Next.js + Vite support — Works with both frameworks
  • Client + Server coverage — Browser and Node.js in one report
  • Dev mode support — Works with next dev (no production build required)
  • Auto-detection — Automatically detects dev vs production mode
  • Source map support — Maps bundled code back to original TypeScript/JSX
  • Multi-source merge — Combine unit, component, and E2E coverage
  • Blind spot detection — Find V8 coverage limitations with nextcov check
  • Multiple reporters — HTML, LCOV, JSON, text-summary

Try It Out

If you’re building a Next.js application and want complete test coverage visibility across unit, component, and E2E tests, give nextcov a try.

Leave a Reply