plugins/dev/skills/test-coverage/SKILL.md
On-demand test coverage analysis. Use when identifying untested code, finding test gaps, measuring coverage metrics, or improving test quality. Trigger keywords - "test coverage", "coverage report", "untested code", "test gaps", "missing tests", "coverage metrics".
npx skillsauth add madappgang/claude-code test-coverageInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The test-coverage skill provides comprehensive on-demand test coverage analysis for your codebase. It identifies untested code paths, measures coverage metrics, finds test gaps, evaluates test quality, and provides actionable recommendations for improving test coverage across all supported technology stacks.
When to Use:
Technology Coverage:
Definition: Percentage of executable lines that are executed by tests.
Example:
function divide(a: number, b: number): number {
if (b === 0) { // Line 1: COVERED
throw new Error('Div 0'); // Line 2: NOT COVERED
}
return a / b; // Line 3: COVERED
}
// Test only covers normal case
test('divides numbers', () => {
expect(divide(10, 2)).toBe(5);
});
// Line Coverage: 66% (2/3 lines)
Interpretation:
Definition: Percentage of decision branches (if/else, switch, ternary) that are tested.
Example:
function getUserStatus(user: User): string {
if (user.isActive) { // Branch 1: true (COVERED)
if (user.isPremium) { // Branch 2: true (NOT COVERED)
return 'premium'; // NOT COVERED
}
return 'active'; // COVERED
}
return 'inactive'; // Branch 1: false (NOT COVERED)
}
// Test only covers active non-premium
test('returns status', () => {
expect(getUserStatus({ isActive: true, isPremium: false })).toBe('active');
});
// Branch Coverage: 33% (1/3 branches)
// Line Coverage: 60% (3/5 lines)
Why Important: Higher than line coverage, catches edge cases.
Definition: Percentage of functions that are called at least once in tests.
Example:
// auth.ts
export function login(user: string, pass: string) { ... } // COVERED
export function logout() { ... } // COVERED
export function resetPassword(email: string) { ... } // NOT COVERED
export function changePassword(old: string, new: string) { ... } // NOT COVERED
// Function Coverage: 50% (2/4 functions)
Red Flag: Exported functions with 0% coverage.
Definition: Percentage of statements executed (similar to line coverage but more granular).
Difference from Line Coverage:
// Single line, multiple statements
const x = 1, y = 2, z = 3;
// Line coverage: 1 line
// Statement coverage: 3 statements
Use Case: More precise for minified or compact code.
Priority Levels:
CRITICAL (Must Test):
HIGH (Should Test):
MEDIUM (Nice to Test):
LOW (Optional):
# Test Coverage Gap Analysis
**Generated**: 2026-01-28 14:32:00
**Coverage**: 68% (Target: 80%)
**Files Analyzed**: 247
**Critical Gaps**: 12 files
## Executive Summary
**Overall Coverage**:
- Line Coverage: 68% (Target: 80%) - 12% below
- Branch Coverage: 54% (Target: 75%) - 21% below
- Function Coverage: 71% (Target: 85%) - 14% below
**Risk Assessment**: MEDIUM-HIGH
- 12 critical files under 50% coverage
- 23 high-priority functions untested
- 47 error handling branches untested
## Critical Gaps (Priority 1)
### [GAP-001] Authentication Module
**File**: src/auth/AuthService.ts
**Line Coverage**: 34% (Target: 95%+)
**Branch Coverage**: 22%
**Risk**: CRITICAL
**Untested Code Paths**:
```typescript
// CRITICAL: No tests for password reset flow
async resetPassword(email: string): Promise<void> {
const user = await this.userRepo.findByEmail(email);
if (!user) {
throw new NotFoundError('User not found'); // UNTESTED
}
const token = generateResetToken(); // UNTESTED
await this.emailService.sendResetEmail( // UNTESTED
user.email,
token
);
}
// CRITICAL: No tests for token expiry
validateResetToken(token: string): boolean {
const decoded = jwt.verify(token, SECRET);
if (Date.now() > decoded.exp) { // UNTESTED
return false;
}
return true;
}
Impact: Security vulnerability, potential for unauthorized access.
Recommendation: Add comprehensive tests for all auth flows.
Required Tests:
Estimated Coverage After: 88%
File: src/payments/PaymentService.ts Line Coverage: 41% (Target: 99%+) Branch Coverage: 29% Risk: CRITICAL
Untested Code Paths:
async processPayment(order: Order): Promise<PaymentResult> {
try {
const charge = await stripe.charges.create({ // TESTED
amount: order.total,
currency: 'usd',
source: order.paymentToken
});
if (charge.status === 'failed') { // UNTESTED
await this.handleFailedPayment(order); // UNTESTED
throw new PaymentError('Payment failed');
}
await this.fulfillOrder(order); // TESTED
return { success: true, chargeId: charge.id };
} catch (error) {
if (error.code === 'card_declined') { // UNTESTED
await this.notifyCardDeclined(order); // UNTESTED
}
throw error; // UNTESTED
}
}
Impact: Financial loss, failed orders without proper handling.
Recommendation: Mock Stripe, test all payment scenarios.
Required Tests:
Estimated Coverage After: 94%
File: src/users/UserService.ts Line Coverage: 62% Branch Coverage: 48% Risk: HIGH
Untested Validation Logic:
validateUserData(data: UserInput): ValidationResult {
const errors: string[] = [];
if (!data.email || !data.email.includes('@')) { // Partially tested
errors.push('Invalid email');
}
if (data.password.length < 8) { // UNTESTED
errors.push('Password too short');
}
if (!/[A-Z]/.test(data.password)) { // UNTESTED
errors.push('Password needs uppercase');
}
if (!/[0-9]/.test(data.password)) { // UNTESTED
errors.push('Password needs number');
}
return { valid: errors.length === 0, errors };
}
Recommendation: Test all validation branches.
File: src/api/handlers/UserHandler.ts Line Coverage: 59% Branch Coverage: 41% Risk: HIGH
Untested Error Paths:
async getUser(req: Request, res: Response) {
try {
const user = await this.userService.getById(req.params.id);
res.json(user); // TESTED
} catch (error) {
if (error instanceof NotFoundError) { // UNTESTED
res.status(404).json({ error: 'Not found' });
} else if (error instanceof ValidationError) { // UNTESTED
res.status(400).json({ error: error.message });
} else {
res.status(500).json({ error: 'Server error' }); // UNTESTED
}
}
}
Recommendation: Test all error types and status codes.
| File | Coverage | Untested Lines | Priority | |------|----------|----------------|----------| | src/utils/DateFormatter.ts | 67% | 12 | MEDIUM | | src/services/EmailService.ts | 65% | 23 | MEDIUM | | src/middleware/RateLimiter.ts | 63% | 18 | MEDIUM | | src/database/Migrations.ts | 58% | 34 | LOW |
Module Coverage Breakdown:
├── src/auth/ 34% (CRITICAL - needs work)
├── src/payments/ 41% (CRITICAL - needs work)
├── src/users/ 62% (below target)
├── src/api/handlers/ 59% (below target)
├── src/services/ 72% (above target ✓)
├── src/utils/ 84% (good ✓)
├── src/database/ 91% (excellent ✓)
└── src/components/ 77% (good ✓)
Overall: 68%
Target: 80%
Gap: -12%
Authentication:
Payments:
Data Validation:
Error Handling:
Add auth module tests - Priority: CRITICAL
Add payment processing tests - Priority: CRITICAL
Test all error handling paths - Priority: HIGH
Expected Coverage After: 68% → 76%
Expected Coverage After: 76% → 82%
Target Coverage: 85%
Coverage is not the only metric. Test quality matters:
1. Tests Without Assertions (4 tests)
// BAD: No assertion
test('creates user', async () => {
await createUser({ name: 'John' });
});
// GOOD: Verify behavior
test('creates user', async () => {
const user = await createUser({ name: 'John' });
expect(user.id).toBeDefined();
expect(user.name).toBe('John');
});
2. Tests That Don't Test Anything (7 tests)
// BAD: Always passes
test('validates email', () => {
const result = validateEmail('[email protected]');
expect(result).toBeTruthy(); // Any truthy value passes
});
// GOOD: Specific assertion
test('validates email', () => {
expect(validateEmail('[email protected]')).toBe(true);
expect(validateEmail('invalid')).toBe(false);
});
3. Overly Broad Mocks (12 tests)
// BAD: Mocks everything, tests nothing
jest.mock('../UserService');
// GOOD: Mock only external dependencies
jest.mock('../EmailService');
// UserService tested with real implementation
4. Flaky Tests (3 tests)
// BAD: Depends on timing
test('debounces input', async () => {
fireEvent.change(input, { target: { value: 'test' } });
await new Promise(resolve => setTimeout(resolve, 100)); // Flaky!
expect(mockFn).toHaveBeenCalledTimes(1);
});
// GOOD: Use fake timers
test('debounces input', () => {
jest.useFakeTimers();
fireEvent.change(input, { target: { value: 'test' } });
jest.advanceTimersByTime(300);
expect(mockFn).toHaveBeenCalledTimes(1);
});
## Coverage Report Format
### Standard Coverage Output
**Jest/Vitest**:
----------------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------------|---------|----------|---------|---------|------------------- All files | 68.23 | 54.12 | 71.45 | 68.23 | auth/ | 34.56 | 22.31 | 41.23 | 34.56 | AuthService | 34.56 | 22.31 | 41.23 | 34.56 | 42-67,89-102 payments/ | 41.23 | 29.45 | 50.00 | 41.23 | PaymentSvc | 41.23 | 29.45 | 50.00 | 41.23 | 23-34,56-78 users/ | 62.34 | 48.12 | 65.23 | 62.34 | UserService | 62.34 | 48.12 | 65.23 | 62.34 | 112-123,145 ----------------|---------|----------|---------|---------|-------------------
**Go**:
coverage: 68.2% of statements
ok github.com/user/project/auth 0.234s coverage: 34.5% of statements ok github.com/user/project/payments 0.156s coverage: 41.2% of statements ok github.com/user/project/users 0.189s coverage: 62.3% of statements
**Rust (tarpaulin)**:
|| Tested/Total Lines: || src/auth.rs: 23/67 (34.3%) || src/payments.rs: 34/82 (41.5%) || src/users.rs: 89/143 (62.2%) || 68.23% coverage, 146/214 lines covered
## Integration with Dev Plugin
### With Test Architect Agent
Request comprehensive test creation:
Analyze test coverage and generate tests for all critical gaps
The test-architect agent will:
1. Identify gaps using this skill
2. Generate test files
3. Run tests and verify coverage improvement
### With Audit Skill
Combine coverage with security:
Identify untested security-critical code paths
### With Optimize Skill
Balance coverage with performance:
Check test coverage impact on build time
## Best Practices
### 1. Set Coverage Targets by Risk
**Critical Code** (95%+ coverage):
- Authentication and authorization
- Payment processing
- Data validation
- Security checks
**Business Logic** (80%+ coverage):
- Core features
- API endpoints
- State management
**Utilities** (70%+ coverage):
- Helper functions
- Formatters
- Parsers
**Infrastructure** (50%+ coverage):
- Configuration
- Build scripts
- Tooling
### 2. Focus on Untested Branches
Branch coverage > line coverage for finding bugs.
**Example**:
```typescript
// 100% line coverage, 50% branch coverage
function process(data: Data | null) {
const result = data ? data.value : 0; // Both branches needed
return result * 2;
}
// Test only null case - 100% lines, 50% branches
test('handles null', () => {
expect(process(null)).toBe(0);
});
// Need both cases
test('handles data', () => {
expect(process({ value: 5 })).toBe(10);
});
Bad (tests implementation):
test('calls getUserById', () => {
const spy = jest.spyOn(service, 'getUserById');
component.loadUser(123);
expect(spy).toHaveBeenCalledWith(123);
});
Good (tests behavior):
test('displays user name after loading', async () => {
render(<UserProfile userId={123} />);
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
});
});
Coverage is a tool, not a target.
Anti-pattern: Writing useless tests to hit 100% Better: Writing meaningful tests, accepting 85-90%
CI/CD Integration:
# .github/workflows/test.yml
- name: Run tests with coverage
run: npm test -- --coverage
- name: Check coverage threshold
run: |
COVERAGE=$(jq '.total.lines.pct' coverage/coverage-summary.json)
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% below 80%"
exit 1
fi
Pre-commit Hook:
#!/bin/bash
# Run tests on changed files
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.ts$')
if [ -n "$CHANGED_FILES" ]; then
npm test -- --findRelatedTests $CHANGED_FILES --coverage
fi
Request:
I just added user profile editing. Check test coverage for this feature.
Analysis Process:
Report:
User Profile Feature Coverage: 58%
Files:
- UserProfile.tsx: 72% (needs: error handling tests)
- useUserProfile.ts: 45% (needs: loading state, error state)
- updateUser.ts: 67% (needs: validation error cases)
Critical Gaps:
- No test for update failure
- No test for network error
- No test for validation errors
Recommended Tests: 8
Estimated Coverage After: 89%
Request:
Check if we meet 80% coverage threshold for deployment
Analysis:
Current Coverage: 76% (Target: 80%)
Status: BLOCKED
Modules Below Target:
- auth/: 34% (need +46%)
- payments/: 41% (need +39%)
- api/handlers/: 59% (need +21%)
Quickest Path to 80%:
1. Add auth error handling tests (+8%)
2. Add payment failure tests (+6%)
3. Add API validation tests (+4%)
Estimated Effort: 2 days
Request:
We're refactoring the auth module. What's our test coverage there?
Analysis:
Auth Module Coverage: 34%
Risk Assessment: HIGH
- 66% of code is untested
- No tests for password reset
- No tests for session expiry
- Limited tests for error cases
Recommendation: STOP
Before refactoring:
1. Increase coverage to 80%+ (add 23 tests)
2. Add integration tests for auth flow
3. Document expected behavior
Refactoring without tests = high regression risk
Coverage Command:
npm test -- --coverage --collectCoverageFrom='src/**/*.{ts,tsx}'
Common Gaps:
Coverage Command:
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
Common Gaps:
Coverage Command:
cargo tarpaulin --out Html --output-dir coverage
Common Gaps:
Test coverage analysis identifies gaps, prioritizes testing efforts, and ensures code quality. Use this skill regularly to maintain high coverage, catch regressions early, and ship with confidence.
Key Takeaways:
For security analysis, see the audit skill. For performance optimization, see the optimize skill.
testing
A test skill for validation testing. Use when testing skill parsing and validation logic.
tools
--- name: bad-skill description: This skill has invalid YAML in frontmatter allowed-tools: [invalid, array, syntax prerequisites: not-an-array --- # Bad Skill This skill has malformed frontmatter that should fail parsing. The YAML has: - Unclosed array bracket - Wrong type for prerequisites (should be array, not string)
tools
Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.
testing
Fetch trending programming models from OpenRouter rankings. Use when selecting models for multi-model review, updating model recommendations, or researching current AI coding trends. Provides model IDs, context windows, pricing, and usage statistics from the most recent week.