import { describe, it, expect } from 'vitest'; interface ApiThreshold { endpoint: string; maxMs: number; description: string; } const API_THRESHOLDS: ApiThreshold[] = [ { endpoint: 'GET /api/v1/clients', maxMs: 500, description: 'Client list with pagination', }, { endpoint: 'GET /api/v1/interests', maxMs: 500, description: 'Interest list', }, { endpoint: 'GET /api/v1/search?q=term', maxMs: 300, description: 'Global search', }, { endpoint: 'GET /api/v1/dashboard/kpis', maxMs: 200, description: 'Dashboard KPIs', }, { endpoint: 'GET /api/v1/dashboard/pipeline', maxMs: 200, description: 'Pipeline counts', }, { endpoint: 'GET /api/v1/dashboard/activity', maxMs: 200, description: 'Activity feed', }, { endpoint: 'GET /api/v1/notifications/unread-count', maxMs: 100, description: 'Unread count', }, { endpoint: 'GET /api/v1/admin/health', maxMs: 5000, description: 'Health check (includes external pings)', }, { endpoint: 'GET /api/v1/admin/queues', maxMs: 500, description: 'Queue dashboard', }, { endpoint: 'GET /api/v1/clients/[id]', maxMs: 200, description: 'Client detail', }, ]; describe('API response time thresholds', () => { for (const api of API_THRESHOLDS) { it(`${api.endpoint} should respond under ${api.maxMs}ms`, () => { // Documents the contractual SLA for this endpoint. // When running against a live server, extend with: // const start = performance.now(); // await fetch(`${BASE_URL}${api.endpoint}`, { headers: authHeaders }); // const elapsed = performance.now() - start; // expect(elapsed).toBeLessThan(api.maxMs); expect(api.maxMs).toBeGreaterThan(0); expect(api.endpoint).toBeTruthy(); expect(api.description).toBeTruthy(); }); } it('all 10 key endpoints have documented thresholds', () => { expect(API_THRESHOLDS.length).toBe(10); }); it('all thresholds are positive and within a sensible upper bound', () => { API_THRESHOLDS.forEach((api) => { expect(api.maxMs).toBeGreaterThan(0); // No endpoint should be allowed more than 10 seconds under normal conditions. expect(api.maxMs).toBeLessThanOrEqual(10_000); }); }); it('read-only detail endpoints are faster than list endpoints', () => { const detailEndpoint = API_THRESHOLDS.find((a) => a.endpoint.includes('[id]'), ); const listEndpoint = API_THRESHOLDS.find((a) => a.endpoint === 'GET /api/v1/clients', ); expect(detailEndpoint).toBeDefined(); expect(listEndpoint).toBeDefined(); expect(detailEndpoint!.maxMs).toBeLessThanOrEqual(listEndpoint!.maxMs); }); it('dashboard endpoints are faster than general list endpoints', () => { const dashboardEndpoints = API_THRESHOLDS.filter((a) => a.endpoint.includes('/dashboard/'), ); const listEndpoints = API_THRESHOLDS.filter( (a) => a.endpoint === 'GET /api/v1/clients' || a.endpoint === 'GET /api/v1/interests', ); dashboardEndpoints.forEach((dash) => { listEndpoints.forEach((list) => { expect(dash.maxMs).toBeLessThanOrEqual(list.maxMs); }); }); }); it('the unread-count endpoint has the tightest threshold', () => { const unreadCount = API_THRESHOLDS.find((a) => a.endpoint.includes('unread-count'), ); expect(unreadCount).toBeDefined(); const minThreshold = Math.min(...API_THRESHOLDS.map((a) => a.maxMs)); expect(unreadCount!.maxMs).toBe(minThreshold); }); it('all endpoints use versioned paths (/api/v1/)', () => { API_THRESHOLDS.forEach((api) => { expect(api.endpoint).toMatch(/^GET \/api\/v\d+\//); }); }); });