import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication, ValidationPipe } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from '../src/app.module'; import { ReportPeriod } from '../src/domain/value-objects'; describe('Reporting Service (e2e)', () => { let app: INestApplication; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); app.setGlobalPrefix('api/v1'); app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, transformOptions: { enableImplicitConversion: true, }, }), ); // TransformInterceptor and GlobalExceptionFilter are already registered in AppModule // Don't add them again to avoid double-wrapping responses await app.init(); }); afterAll(async () => { await app.close(); }); describe('Health Check', () => { it('/api/v1/health (GET) should return ok status', () => { return request(app.getHttpServer()) .get('/api/v1/health') .expect(200) .expect((res) => { // Response is wrapped by TransformInterceptor: { success: true, data: { ... }, timestamp: ... } expect(res.body.success).toBe(true); expect(res.body.data).toBeDefined(); expect(res.body.data.status).toBe('ok'); expect(res.body.data.service).toBe('reporting-service'); }); }); it('/api/v1/health/ready (GET) should return ready status', () => { return request(app.getHttpServer()) .get('/api/v1/health/ready') .expect(200) .expect((res) => { expect(res.body.success).toBe(true); expect(res.body.data).toBeDefined(); expect(res.body.data.status).toBe('ready'); }); }); }); describe('Reports API', () => { describe('GET /api/v1/reports/definitions', () => { it('should return list of report definitions', () => { return request(app.getHttpServer()) .get('/api/v1/reports/definitions') .expect(200) .expect((res) => { expect(res.body.success).toBe(true); expect(res.body.data).toBeDefined(); expect(Array.isArray(res.body.data)).toBe(true); }); }); }); describe('GET /api/v1/reports/definitions/:code', () => { it('should return 404 for non-existent report code', () => { return request(app.getHttpServer()) .get('/api/v1/reports/definitions/NON_EXISTENT_CODE') .expect(404) .expect((res) => { expect(res.body.statusCode).toBe(404); }); }); }); describe('POST /api/v1/reports/generate', () => { it('should validate request body', () => { return request(app.getHttpServer()) .post('/api/v1/reports/generate') .send({}) .expect(400); }); it('should reject invalid report period', () => { return request(app.getHttpServer()) .post('/api/v1/reports/generate') .send({ reportCode: 'RPT_LEADERBOARD', reportPeriod: 'INVALID_PERIOD', startDate: '2024-01-01', endDate: '2024-01-31', }) .expect(400); }); it('should return 404 for non-existent report code', () => { return request(app.getHttpServer()) .post('/api/v1/reports/generate') .send({ reportCode: 'NON_EXISTENT', reportPeriod: ReportPeriod.DAILY, startDate: '2024-01-01', endDate: '2024-01-01', }) .expect(404); }); }); describe('GET /api/v1/reports/snapshots', () => { it('should return empty array when no report code provided', () => { return request(app.getHttpServer()) .get('/api/v1/reports/snapshots') .expect(200) .expect((res) => { expect(res.body.success).toBe(true); expect(res.body.data).toBeDefined(); expect(Array.isArray(res.body.data)).toBe(true); }); }); it('should filter snapshots by report code', () => { return request(app.getHttpServer()) .get('/api/v1/reports/snapshots') .query({ reportCode: 'RPT_LEADERBOARD' }) .expect(200) .expect((res) => { expect(res.body.success).toBe(true); expect(res.body.data).toBeDefined(); expect(Array.isArray(res.body.data)).toBe(true); }); }); }); describe('GET /api/v1/reports/snapshots/:code/latest', () => { it('should return 404 when no snapshots exist', () => { return request(app.getHttpServer()) .get('/api/v1/reports/snapshots/RPT_LEADERBOARD/latest') .expect(404); }); }); }); describe('Export API', () => { describe('POST /api/v1/export', () => { it('should validate request body', () => { return request(app.getHttpServer()) .post('/api/v1/export') .send({}) .expect(400); }); it('should reject invalid format', () => { return request(app.getHttpServer()) .post('/api/v1/export') .send({ snapshotId: '1', format: 'INVALID_FORMAT', }) .expect(400); }); }); }); });