import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import request from 'supertest'; import { AppModule } from '../src/app.module'; import { ValidationPipe } from '../src/common/pipes/validation.pipe'; import { AllExceptionsFilter } from '../src/common/filters/all-exceptions.filter'; import { RequestIdInterceptor } from '../src/common/interceptors/request-id.interceptor'; import { ResponseInterceptor } from '../src/common/interceptors/response.interceptor'; describe('Gateway public endpoints (e2e)', () => { let app: INestApplication; beforeAll(async () => { const moduleRef = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleRef.createNestApplication(); app.setGlobalPrefix('api'); app.useGlobalFilters(new AllExceptionsFilter()); app.useGlobalInterceptors( new RequestIdInterceptor(), new ResponseInterceptor(), ); app.useGlobalPipes(new ValidationPipe()); await app.init(); }); afterAll(async () => { if (app) await app.close(); }); it('reports health without authentication', async () => { const response = await request(app.getHttpServer()) .get('/api/admin/health') .expect(200); expect(response.body.data.status).toBe('ok'); }); it('protects admin metrics', async () => { await request(app.getHttpServer()) .get('/api/admin/metrics') .expect(401); }); it('validates registration input through the real HTTP pipeline', async () => { await request(app.getHttpServer()) .post('/api/auth/register') .send({ email: 'not-an-email', password: 'x' }) .expect(400); }); it('completes tenant signup, registration, login, and isolation checks', async () => { const suffix = Date.now().toString(36); const tenantResponse = await request(app.getHttpServer()) .post('/api/tenants') .send({ name: `e2e-${suffix}`, maxAccounts: 2 }) .expect(201); const tenantId = tenantResponse.body.data.id; const credentials = { email: `owner-${suffix}@example.com`, password: 'StrongPass123!', tenantId, }; const registerResponse = await request(app.getHttpServer()) .post('/api/auth/register') .send(credentials) .expect(201); expect(registerResponse.body.data.token).toBeTruthy(); expect(registerResponse.body.data.user.passwordHash).toBeUndefined(); const loginResponse = await request(app.getHttpServer()) .post('/api/auth/login') .send(credentials) .expect(201); const token = loginResponse.body.data.token; expect(loginResponse.body.data.user.passwordHash).toBeUndefined(); const tenantList = await request(app.getHttpServer()) .get('/api/tenants') .set('Authorization', `Bearer ${token}`) .set('x-tenant-id', tenantId) .expect(200); expect(tenantList.body.data).toHaveLength(1); expect(tenantList.body.data[0].id).toBe(tenantId); await request(app.getHttpServer()) .put(`/api/tenants/${tenantId}`) .set('Authorization', `Bearer ${token}`) .set('x-tenant-id', tenantId) .send({ maxAccounts: 3 }) .expect(200); const auditResponse = await request(app.getHttpServer()) .get('/api/admin/audit-logs?action=put') .set('Authorization', `Bearer ${token}`) .expect(200); expect(auditResponse.body.data.total).toBeGreaterThanOrEqual(1); expect(auditResponse.body.data.logs[0].tenantId).toBe(tenantId); await request(app.getHttpServer()) .get('/api/tenants') .set('Authorization', `Bearer ${token}`) .set('x-tenant-id', 'another-tenant') .expect(403); }); it('reports database readiness when Redis is disabled for tests', async () => { const response = await request(app.getHttpServer()) .get('/api/admin/ready') .expect(200); expect(response.body.data).toEqual({ status: 'ready', checks: { database: 'up', redis: 'disabled' }, }); }); });