import type { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import request from 'supertest'; import { afterEach, describe, expect, it } from 'vitest'; import { HealthController } from '../src/health.controller'; import { HealthService, MYSQL_HEALTH_PORT, REDIS_HEALTH_PORT, type DependencyHealthPort, } from '../src/health.service'; describe('GET /api/v1/health', () => { let app: INestApplication | undefined; afterEach(async () => { await app?.close(); app = undefined; }); async function createApp( redis: DependencyHealthPort, mysql: DependencyHealthPort, ): Promise { const moduleRef = await Test.createTestingModule({ controllers: [HealthController], providers: [ HealthService, { provide: REDIS_HEALTH_PORT, useValue: redis }, { provide: MYSQL_HEALTH_PORT, useValue: mysql }, ], }).compile(); const nestApp = moduleRef.createNestApplication(); nestApp.setGlobalPrefix('api/v1'); await nestApp.init(); return nestApp; } it('依赖健康时返回 200 与 RocketMQ disabled', async () => { app = await createApp( { check: async () => ({ status: 'healthy', detail: 'PONG' }) }, { check: async () => ({ status: 'healthy', detail: 'MySQL 5.7' }) }, ); const response = await request(app.getHttpServer()).get('/api/v1/health').expect(200); expect(response.body).toMatchObject({ status: 'healthy', process: 'api', dependencies: { redis: { status: 'healthy' }, mysql: { status: 'healthy' }, rocketMq: { status: 'disabled' }, }, }); }); it('依赖失败时返回 503 且不泄漏错误中的敏感值', async () => { app = await createApp( { check: async () => ({ status: 'unavailable', detail: 'TEST_SENSITIVE_VALUE' }) }, { check: async () => ({ status: 'healthy', detail: 'MySQL 5.7' }) }, ); const response = await request(app.getHttpServer()).get('/api/v1/health').expect(503); const serialized = JSON.stringify(response.body); expect(response.body.status).toBe('unavailable'); expect(serialized).not.toContain('TEST_SENSITIVE_VALUE'); }); it('有意禁用的可选依赖不降低 API 总体状态', async () => { app = await createApp( { check: async () => ({ status: 'healthy', detail: 'PONG' }) }, { check: async () => ({ status: 'disabled', detail: 'MySQL 未启用' }) }, ); const response = await request(app.getHttpServer()).get('/api/v1/health').expect(200); expect(response.body).toMatchObject({ status: 'healthy', dependencies: { mysql: { status: 'disabled' } }, }); }); });