Files
wmq 06112602ec feat(gateway): include production Telegram user gateway
Version the NestJS TDLib gateway with Docker deployment, migrations, automated tests and platform integration documentation while excluding all account sessions, credentials, runtime databases and backups.
2026-08-01 18:38:20 +08:00

120 lines
3.9 KiB
TypeScript

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' },
});
});
});