learning_ai_notes/backend/src/diagnostics.test.ts
saravanakumardb1 8a1234a460 feat(backend): add GET /api/bootstrap route + test
- Returns productId, displayName, backendPort for client bootstrapping
- Integration test validates response shape and types
2026-03-20 21:15:41 -07:00

105 lines
3.9 KiB
TypeScript

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import Fastify from 'fastify';
import type { FastifyInstance } from 'fastify';
import { getAllFlags } from './lib/feature-flags.js';
import { getBufferedEvents, flushEvents } from './lib/telemetry.js';
import { config } from './lib/config.js';
import { PRODUCT_ID, productConfig } from './lib/product-config.js';
let app: FastifyInstance;
beforeAll(async () => {
app = Fastify({ logger: false });
app.get('/api/diagnostics/flags', async () => getAllFlags());
app.get('/api/diagnostics/telemetry', async () => ({ events: getBufferedEvents() }));
app.post('/api/diagnostics/telemetry/flush', async () => ({ flushed: flushEvents().length }));
app.get('/api/diagnostics/config', async () => ({
productId: PRODUCT_ID,
serviceName: config.SERVICE_NAME,
port: config.PORT,
nodeEnv: config.NODE_ENV,
dbProvider: config.DB_PROVIDER,
telemetryEnabled: config.TELEMETRY_ENABLED,
featureFlagsEnabled: config.FEATURE_FLAGS_ENABLED,
}));
app.get('/health', async (req) => ({
status: 'ok',
service: config.SERVICE_NAME,
version: '0.1.0',
timestamp: new Date().toISOString(),
requestId: req.id,
}));
app.get('/api/bootstrap', async () => ({
productId: productConfig.productId,
displayName: productConfig.displayName,
backendPort: config.PORT,
}));
await app.ready();
});
afterAll(async () => {
await app.close();
});
describe('diagnostics routes', () => {
it('GET /api/diagnostics/flags returns feature flags', async () => {
const res = await app.inject({ method: 'GET', url: '/api/diagnostics/flags' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(typeof body).toBe('object');
expect(body).not.toBeNull();
});
it('GET /api/diagnostics/telemetry returns buffered events', async () => {
const res = await app.inject({ method: 'GET', url: '/api/diagnostics/telemetry' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body).toHaveProperty('events');
expect(Array.isArray(body.events)).toBe(true);
});
it('POST /api/diagnostics/telemetry/flush returns flushed count', async () => {
const res = await app.inject({ method: 'POST', url: '/api/diagnostics/telemetry/flush' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body).toHaveProperty('flushed');
expect(typeof body.flushed).toBe('number');
});
it('GET /api/diagnostics/config returns sanitized config', async () => {
const res = await app.inject({ method: 'GET', url: '/api/diagnostics/config' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body).toHaveProperty('productId');
expect(body).toHaveProperty('serviceName');
expect(body).toHaveProperty('port');
expect(body).toHaveProperty('nodeEnv');
expect(body).toHaveProperty('dbProvider');
expect(typeof body.telemetryEnabled).toBe('boolean');
expect(typeof body.featureFlagsEnabled).toBe('boolean');
});
it('GET /health returns standard health response', async () => {
const res = await app.inject({ method: 'GET', url: '/health' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body.status).toBe('ok');
expect(body).toHaveProperty('service');
expect(body).toHaveProperty('version');
expect(body).toHaveProperty('timestamp');
expect(body.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
});
it('GET /api/bootstrap returns product identity', async () => {
const res = await app.inject({ method: 'GET', url: '/api/bootstrap' });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body).toHaveProperty('productId');
expect(body).toHaveProperty('displayName');
expect(body).toHaveProperty('backendPort');
expect(typeof body.productId).toBe('string');
expect(typeof body.displayName).toBe('string');
expect(typeof body.backendPort).toBe('number');
});
});