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=htmland openbackend/htmlcov/index.html - [ ] Run
cd frontend && npm run test -- --run --coverageand 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:coverageand opencoverage/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