175 lines
5.4 KiB
TypeScript
175 lines
5.4 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|
|
});
|