const request = require('supertest') const app = require('../server') // Mock axios to avoid actual HTTP requests during tests jest.mock('axios') const axios = require('axios') describe('API Docs Service', () => { let server beforeAll(() => { // Start the server for testing server = app.listen(0) // Use random available port }) afterAll((done) => { // Close the server after tests server.close(done) }) describe('GET /health', () => { it('should return health status', async () => { const response = await request(app) .get('/health') .expect(200) expect(response.body).toHaveProperty('status', 'healthy') expect(response.body).toHaveProperty('timestamp') expect(new Date(response.body.timestamp)).toBeInstanceOf(Date) }) }) describe('GET /services', () => { beforeEach(() => { // Reset axios mocks jest.clearAllMocks() }) it('should return service status for all services', async () => { // Mock successful health checks for active services axios.get.mockImplementation((url) => { if (url.includes('/health')) { return Promise.resolve({ headers: { 'x-response-time': '50ms' } }) } return Promise.reject(new Error('Not found')) }) const response = await request(app) .get('/services') .expect(200) expect(response.body).toHaveProperty('api-gateway') expect(response.body).toHaveProperty('service-adapters') expect(response.body).toHaveProperty('metrics-collector') expect(response.body).toHaveProperty('notification-service') // Check structure of service status Object.values(response.body).forEach(service => { expect(service).toHaveProperty('name') expect(service).toHaveProperty('url') expect(service).toHaveProperty('status') }) }) it('should handle service health check failures', async () => { // Mock all health checks to fail axios.get.mockRejectedValue(new Error('Connection refused')) const response = await request(app) .get('/services') .expect(200) // All services should show as unhealthy or planned Object.values(response.body).forEach(service => { expect(['unhealthy', 'planned']).toContain(service.status) if (service.status === 'unhealthy') { expect(service).toHaveProperty('error') } }) }) }) describe('GET /openapi.json', () => { beforeEach(() => { jest.clearAllMocks() }) it('should return unified OpenAPI specification', async () => { // Mock service spec responses axios.get.mockImplementation((url) => { if (url.includes('/v3/api-docs')) { return Promise.resolve({ data: { openapi: '3.0.0', info: { title: 'API Gateway', version: '1.0.0' }, paths: { '/test': { get: { summary: 'Test endpoint' } } }, components: { schemas: {} } } }) } if (url.includes('/openapi.json')) { return Promise.resolve({ data: { openapi: '3.0.0', info: { title: 'Service Adapters', version: '1.0.0' }, paths: { '/health': { get: { summary: 'Health check' } } }, components: { schemas: {} } } }) } return Promise.reject(new Error('Not found')) }) const response = await request(app) .get('/openapi.json') .expect(200) expect(response.body).toHaveProperty('openapi', '3.0.0') expect(response.body).toHaveProperty('info') expect(response.body).toHaveProperty('paths') expect(response.body).toHaveProperty('components') expect(response.body).toHaveProperty('tags') // Check that paths are prefixed with service names expect(response.body.paths).toHaveProperty('/api-gateway/test') expect(response.body.paths).toHaveProperty('/service-adapters/health') }) it('should handle service spec fetch failures gracefully', async () => { // Mock all service spec requests to fail axios.get.mockRejectedValue(new Error('Service unavailable')) const response = await request(app) .get('/openapi.json') .expect(200) expect(response.body).toHaveProperty('openapi', '3.0.0') expect(response.body).toHaveProperty('info') expect(response.body).toHaveProperty('paths') expect(response.body).toHaveProperty('components') expect(response.body).toHaveProperty('tags') // Should still have tags for all services expect(response.body.tags).toHaveLength(4) }) }) describe('GET /api-docs.json', () => { it('should return API docs service specification', async () => { const response = await request(app) .get('/api-docs.json') .expect(200) expect(response.body).toHaveProperty('openapi', '3.0.0') expect(response.body).toHaveProperty('info') expect(response.body.info).toHaveProperty('title', 'LabFusion API Docs Service') }) }) describe('GET /', () => { it('should serve Swagger UI', async () => { const response = await request(app) .get('/') .expect(200) expect(response.text).toContain('swagger-ui') expect(response.text).toContain('LabFusion API Documentation') }) }) })