CommunityRedacción y edicióngithub.com

sametcelikbicak/coverage-guard

An AI agent skill that enforces 100% test coverage for any JavaScript/TypeScript project. Works with Vitest, Jest, react-scripts, and other test runners. Compatible with opencode, Claude Code, Cursor, Windsurf, and GitHub Copilot.

¿Qué es coverage-guard?

coverage-guard is a Claude Code agent skill that an AI agent skill that enforces 100% test coverage for any JavaScript/TypeScript project. Works with Vitest, Jest, react-scripts, and other test runners. Compatible with opencode, Claude Code, Cursor, Windsurf, and GitHub Copilot.

Compatible conClaude Code~Codex CLICursorOpenCodeWindsurf
npx skills add sametcelikbicak/coverage-guard

Installed? Explore more Redacción y edición skills: steipete/notion, affaan-m/seo, affaan-m/brand-voice · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Coverage Guard

Ensure 100% test coverage for any JavaScript/TypeScript project. Automatically detects the test runner, sets up test infrastructure if missing, writes tests for uncovered components, and loops until every file reaches 100% coverage.

Overview

This skill follows a complete pipeline:

  1. Detect runner & infrastructure → 2. Scan source files & tests → 3. Setup if missing → 4. Generate new tests → 5. Run coverage → 6. Fill gaps → 7. Verify → repeat until 100%

Step-by-step Workflow

Phase 1: Detect environment

Check package.json in the project root to determine:

cat package.json

Identify the test runner and coverage tool:

IndicatorRunnerCoverage command
"vitest" in devDependenciesVitestnpx vitest --coverage
"jest" in devDependenciesJestnpx jest --coverage
"react-scripts" in devDependenciesreact-scripts (Jest)npx react-scripts test --coverage
"next" in devDependenciesNext.js (Jest)npx next test --coverage or check jest.config
"@angular/core" in dependenciesAngular (Karma/Jasmine)ng test --code-coverage
"@playwright/test" in devDependenciesPlaywrightnpx playwright test (no built-in coverage; use @playwright/test with istanbul)
"mocha" in devDependenciesMochanpx mocha (coverage via c8/nyc)
"cypress" in devDependenciesCypressnpx cypress run (coverage via @cypress/code-coverage)
"ava" in devDependenciesAVAnpx ava (coverage via c8)
None foundNone → proceed to Phase 2 → Phase 3 setup

Phase 2: Scan source files and existing tests

Find all source files (components, modules, utilities) that need tests:

# Common source directories
find src -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) ! -name "*.test.*" ! -name "*.spec.*" ! -name "*.d.ts" ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/build/*" ! -path "*/.next/*"

Find all existing test files:

find src -type f \( -name "*.test.*" -o -name "*.spec.*" \) ! -path "*/node_modules/*"

Map each source file to a test file:

  • src/components/Button.tsxsrc/components/Button.test.tsx or src/components/__tests__/Button.test.tsx
  • src/utils/format.tssrc/utils/format.test.ts or src/utils/__tests__/format.test.ts
  • Follow the existing project convention for test file placement

Classify each source file:

  • Has test → add to coverage analysis list
  • No test → mark for test generation

Phase 3: Setup test infrastructure (if missing)

If no test runner was detected in Phase 1, ask the user interactively:

? No test framework detected. Which one would you like to set up?
  1) Vitest (Recommended — fast, modern, native ESM)
  2) Jest (Most widely used)
  3) react-scripts (Create React App)
  4) None — skip, I'll set it up manually

Once the user selects, install dependencies and create config:

Vitest setup:

npm install -D vitest @vitest/coverage-v8

Create vitest.config.ts:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: [
        '**/node_modules/**',
        '**/dist/**',
        '**/*.config.*',
        '**/*.d.ts',
      ],
    },
  },
})

Add to package.json scripts:

{
  "scripts": {
    "test": "vitest",
    "test:coverage": "vitest --coverage"
  }
}

Jest setup:

npm install -D jest @types/jest ts-jest
npx ts-jest config:init
npm install -D jest @testing-library/react @testing-library/jest-dom jest-environment-jsdom

Create jest.config.ts:

export default {
  testEnvironment: 'jsdom',
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
  },
  coverageReporters: ['text', 'json', 'html'],
  collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts'],
}

Add to package.json scripts:

{
  "scripts": {
    "test": "jest",
    "test:coverage": "jest --coverage"
  }
}

react-scripts setup:

npm install -D @testing-library/react @testing-library/jest-dom @testing-library/user-event

Coverage comes built-in:

{
  "scripts": {
    "test": "react-scripts test",
    "test:coverage": "react-scripts test --coverage"
  }
}

After setup, run a quick test to confirm everything works:

npm test

If it fails, fix configuration issues before proceeding.

Phase 4: Write tests for untested source files

For each source file that has no test file, analyze the source code:

  1. Read the source file
  2. Identify:
    • All exported functions, classes, components
    • Return types and possible return paths
    • Parameters and their types (required, optional, default values)
    • Props interface (for React components)
    • Async behavior (Promises, async/await)
    • Side effects (API calls, localStorage, etc.)
    • Error states and edge cases
  3. Generate the test file following the project's conventions:
    • Use the detected test runner's API (describe/it/expect for Jest/Vitest, etc.)
    • For React: use @testing-library/react (render, screen, fireEvent)
    • Mock external dependencies
    • Cover all branches, edge cases, and error paths

React component example (src/components/Button.tsxsrc/components/Button.test.tsx):

import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'

describe('Button', () => {
  it('renders with label', () => {
    render(<Button label="Click me" />)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('calls onClick when clicked', () => {
    const onClick = vi.fn() // jest.fn() for Jest
    render(<Button label="Click" onClick={onClick} />)
    fireEvent.click(screen.getByText('Click'))
    expect(onClick).toHaveBeenCalledTimes(1)
  })

  it('is disabled when disabled prop is true', () => {
    render(<Button label="Click" disabled />)
    expect(screen.getByText('Click')).toBeDisabled()
  })
})

Utility function example (src/utils/format.tssrc/utils/format.test.ts):

import { formatCurrency, truncate } from './format'

describe('formatCurrency', () => {
  it('formats integer amount', () => {
    expect(formatCurrency(1000)).toBe('$1,000.00')
  })

  it('formats decimal amount', () => {
    expect(formatCurrency(99.95)).toBe('$99.95')
  })

  it('handles zero', () => {
    expect(formatCurrency(0)).toBe('$0.00')
  })

  it('handles negative values', () => {
    expect(formatCurrency(-50)).toBe('-$50.00')
  })
})

Phase 5: Run coverage report

Run the appropriate coverage command based on detected runner:

RunnerCommand
Vitestnpx vitest --coverage --reporter=verbose
Jestnpx jest --coverage --verbose
react-scriptsnpx react-scripts test --coverage --watchAll=false
OthersUse the project's configured coverage command

Parse the output to identify:

  • Files below 100% coverage
  • Uncovered lines, branches, functions, and statements
  • Specific line numbers that need tests
  • Files with 0% coverage (no tests exist)

Phase 6: Analyze and fill coverage gaps

For each file below 100% (including files from Phase 4 that now have tests but are not at 100%):

  1. Read the source file and its test file side-by-side
  2. Understand what the uncovered lines/functions/branches do
  3. Identify which edge cases are missing from tests
  4. Write targeted tests to cover the gaps:
  • Uncovered branches: Test both if and else paths, ternary conditions
  • Uncovered functions: Test all possible return paths
  • Uncovered lines: Trace the logic and write a case that reaches them
  • Uncovered async paths: Test both resolved and rejected Promise branches
  • Uncovered error handling: Test error callbacks, catch blocks, error boundaries

Use the detected test runner's patterns:

  • Vitest: vi.mock(), vi.spyOn(), vi.fn()
  • Jest: jest.mock(), jest.spyOn(), jest.fn()
  • react-scripts: Same as Jest

Phase 7: Verify

Re-run coverage after adding/updating tests:

# Use the detected command
npx vitest --coverage   # for Vitest
npx jest --coverage      # for Jest

Confirm all files show 100% for statements, branches, functions, and lines.

Phase 8: Repeat

If coverage is still below 100%, loop back to Phase 6.


Configuration by runner

Vitest coverage config

Ensure vitest.config.ts:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: [
        '**/node_modules/**',
        '**/dist/**',
        '**/*.config.*',
        '**/*.d.ts',
      ],
    },
  },
})

Jest coverage config

Ensure jest.config.ts contains:

export default {
  collectCoverage: true,
  coverageReporters: ['text', 'json', 'html'],
  collectCoverageFrom: [
    'src/**/*.{ts,tsx,js,jsx}',
    '!src/**/*.d.ts',
    '!src/**/*.test.*',
    '!src/**/*.spec.*',
  ],
}

Tips

  • Start with files that have existing tests but low coverage — quickest wins
  • Then tackle untested files with the simplest logic first
  • For React components: test rendering, user interactions, conditional rendering, error states, and empty/loading states
  • For utility functions: test edge cases (empty strings, null/undefined, boundary values, special characters)
  • For API services: test success response, error response, loading state, timeout, and network failure
  • If dead code is found (impossible to cover), suggest removing it or adding a coverage ignore comment:
    • Vitest/V8: /* c8 ignore next */ or /* c8 ignore next 3 */
    • Jest/Istanbul: /* istanbul ignore next */ or /* istanbul ignore if */
  • Do NOT modify source code logic — only add or update tests
  • Follow the project's existing test patterns (file naming, folder structure, mocking style)
  • For files with 0 tests, create a comprehensive test file that hits all the major paths first, then iterate

Detection priority

When scanning for source files, check in this order of common directory structures:

  1. src/
  2. app/ (Next.js app directory)
  3. components/
  4. lib/
  5. utils/
  6. server/ (Next.js/Node.js)
  7. pages/ (Next.js pages directory)
  8. Root-level *.ts / *.tsx files

Example

User: "coverage report shows login.ts at 72%, fix it"

Agent actions:

  1. Run npx vitest --coverage --reporter=verbose, see login.ts has uncovered lines 45-52 (error branch of validateEmail)
  2. Read source, understand validateEmail throws on invalid emails
  3. Add test cases for invalid email inputs in login.test.ts
  4. Re-run coverage — login.ts now at 100%

User: "we use jest, check coverage"

  1. Run npx jest --coverage --verbose, identify uncovered files
  2. Find src/components/Header.tsx at 0% — no test exists
  3. Read Header.tsx source, create src/components/Header.test.tsx
  4. Run coverage again — Header.tsx now at 100%

User: "there's no test setup in this project, add coverage"

  1. Detect no test runner in package.json
  2. Ask user: "No test framework detected. Install Vitest? (Recommended)"
  3. User confirms → install vitest + @vitest/coverage-v8, create vitest.config.ts
  4. Scan src/, find 8 source files, 0 test files
  5. Write tests for all 8 files
  6. Run coverage — all at 100%

Skills relacionados

steipete/notion

Notion CLI/API for pages, Markdown content, data sources, files, comments, search, Workers, and raw API calls.

community

affaan-m/seo

Audit, plan, and implement SEO improvements across technical SEO, on-page optimization, structured data, Core Web Vitals, and content strategy. Use when the user wants better search visibility, SEO remediation, schema markup, sitemap/robots work, or keyword mapping.

community

affaan-m/brand-voice

Build a source-derived writing style profile from real posts, essays, launch notes, docs, or site copy, then reuse that profile across content, outreach, and social workflows. Use when the user wants voice consistency without generic AI writing tropes.

community

affaan-m/crosspost

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

community

affaan-m/x-api

X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.

community

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

community