Skip to content

Test Coverage (/test-coverage)

In plain terms

Runs the test suite and shows where test coverage is thin, then helps improve it — for both front-end and back-end.

What this skill does

Run, review, and improve test coverage for both frontend and backend

[!TIP] Use this to check the current test state, run the full suite, and identify gaps.

Trigger Conditions

  • Keywords: "Add tests", "Check coverage", "Write unit tests", "Test this endpoint", "Coverage report"

1. Current Test Stack

Layer Framework Location
Backend — all tests pytest backend/tests/
Frontend — all tests Vitest + React Testing Library frontend/src/tests/

2. Run Tests

# Backend — all tests
cd backend && pytest --tb=short -q

# Backend — with coverage report
cd backend && pytest --cov=app --cov-report=term-missing --tb=short -q

# Frontend — all tests
cd frontend && npm run test -- --run

# Frontend — with coverage report
cd frontend && npm run test -- --run --coverage

# Backend — type check
cd backend && python -m mypy app/

# Frontend — type check
cd frontend && npm run type-check

3. Backend Test Patterns (pytest)

Test files live in backend/tests/. Structure:

import pytest
from httpx import AsyncClient
from app.main import app

@pytest.mark.asyncio
async def test_get_resource_success(client: AsyncClient, auth_headers: dict):
    response = await client.get("/api/[resource]", headers=auth_headers)
    assert response.status_code == 200

@pytest.mark.asyncio
async def test_get_resource_unauthorized(client: AsyncClient):
    response = await client.get("/api/[resource]")
    assert response.status_code == 401

For each new route, test: - Success path (200/201 with valid data + auth) - Auth rejection (401 without token) - Validation error (422 with invalid input) - Not found (404 for unknown ID)

4. Frontend Test Patterns (Vitest)

Test files live in frontend/src/tests/. Structure:

import { renderHook } from '@testing-library/react';
import { useResource } from '../../hooks/useResource';

vi.mock('../../lib/queryClient', () => ({
    apiRequest: vi.fn().mockResolvedValue(mockData),
}));

describe('useResource', () => {
    it('returns data on success', async () => {
        const { result } = renderHook(() => useResource(), { wrapper: QueryClientWrapper });
        await waitFor(() => expect(result.current.isLoading).toBe(false));
        expect(result.current.data).toHaveLength(2);
    });
});

5. Coverage Review

  • [ ] Run cd backend && pytest --cov=app --cov-report=html and open backend/htmlcov/index.html
  • [ ] Run cd frontend && npm run test -- --run --coverage and review output
  • [ ] Identify files/routes with 0% or < 50% coverage
  • [ ] Prioritize:
  • Auth flows (login, token validation, RBAC)
  • Mutation handlers (create, update, delete routes)
  • Pydantic validation (reject invalid input)
  • Critical business logic (calculations, role checks)

6. Latency Review

After running backend tests, review endpoint response times: - Any endpoint averaging > 500ms is a regression risk - Investigate N+1 query patterns in SQLModel queries - Check if caching is working correctly

7. Interpret Results

  • Failing backend test: Read the traceback, identify the root cause, fix the code (not the test unless the test is wrong)
  • Failing frontend test: Check if it's a component regression or a stale mock. Fix the source, not the assertion
  • Low coverage on new code: Add targeted tests for the uncovered branches before shipping

8. Report

Summarize to the user: - Total tests run / passed / failed - Coverage % for backend and frontend (if measured) - Any areas flagged as under-covered

[!TIP] Use this to check the current test state, run the full suite, and identify gaps.

Trigger Conditions

  • Keywords: "Add tests", "Check coverage", "Write unit tests", "Test this endpoint", "Coverage report"

1. Current Test Stack

Layer Framework Location
Backend — all tests Jest + Supertest backend/tests/
Backend — smoke only Jest + Supertest backend/tests/smoke/
Backend — latency Jest + Supertest backend/tests/performance/
Frontend Vitest + React Testing Library tests/

2. Run Tests

# Backend — all tests
cd backend && npm run test

# Backend — smoke only (fast, runs on pre-commit via husky)
cd backend && npm run test:smoke

# Backend — latency (flags endpoints > 500ms)
cd backend && npm run test:latency

# Frontend — all tests
npm run test

# Frontend — with coverage report (opens coverage/ directory)
npm run test:coverage

# Backend — type check
cd backend && npm run type-check

# Frontend — type check
npm run type-check

3. Backend Test Patterns (Jest + Supertest)

Test files live in backend/tests/. Structure:

import request from 'supertest';
import { app } from '../../src/server.js';

describe('GET /api/[resource]', () => {
    it('returns 200 with valid auth', async () => {
        const res = await request(app)
            .get('/api/[resource]')
            .set('Authorization', `Bearer ${testToken}`);
        expect(res.status).toBe(200);
    });

    it('returns 401 without auth', async () => {
        const res = await request(app).get('/api/[resource]');
        expect(res.status).toBe(401);
    });
});

For each new route, test: - ✅ Success path (200/201 with valid data + auth) - ❌ Auth rejection (401 without token) - ❌ Validation error (400 with invalid input) - ❌ Not found (404 for unknown ID)

4. Frontend Test Patterns (Vitest)

Test files live in tests/. Structure:

import { renderHook } from '@testing-library/react';
import { useCompanies } from '../../hooks/useCompanies';

// Mock the API client
vi.mock('../../services/apiClient', () => ({
    default: {
        get: vi.fn().mockResolvedValue({ data: mockCompanies }),
    },
}));

describe('useCompanies', () => {
    it('returns companies on success', async () => {
        const { result } = renderHook(() => useCompanies(), { wrapper: QueryClientWrapper });
        await waitFor(() => expect(result.current.isLoading).toBe(false));
        expect(result.current.companies).toHaveLength(2);
    });
});

5. Coverage Review

  • [ ] Run npm run test:coverage and open coverage/index.html
  • [ ] Identify files/routes with 0% or < 50% coverage
  • [ ] Prioritize:
  • Auth flows (login, token validation)
  • Mutation handlers (create, update, delete routes)
  • Zod validation (reject invalid input)
  • Critical business logic (pricing calculations, role checks)

6. Latency Review

After running cd backend && npm run test:latency: - Any endpoint averaging > 500ms is a regression risk - Investigate N+1 query patterns in Drizzle queries - Check if the authenticate cache (60s TTL) is working correctly