import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from 'bun:test'; import { Database } from 'bun:sqlite'; import { WebhookServer } from '../../../src/server'; import { initializeDatabase } from '../../../src/db'; import { ResponseQueue } from '../../../src/services/response-queue'; import { AllowedGroups } from '../../../src/services/allowed-groups'; import { GroupSyncService } from '../../../src/services/group-sync'; let testDb: Database; let originalAdd: any; let simulatedQueue: any[] = []; const SimulatedResponseQueue = { async add(responses: any[]) { simulatedQueue.push(...responses); }, clear() { simulatedQueue = []; }, get() { return simulatedQueue; } }; const createTestRequest = (payload: any) => new Request('http://localhost:3007', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); describe('WebhookServer - enforce gating (modo=enforce)', () => { const envBackup = process.env; beforeAll(() => { testDb = new Database(':memory:'); initializeDatabase(testDb); originalAdd = (ResponseQueue as any).add; }); afterAll(() => { (ResponseQueue as any).add = originalAdd; testDb.close(); }); beforeEach(() => { process.env = { ...envBackup, NODE_ENV: 'test', GROUP_GATING_MODE: 'enforce' }; SimulatedResponseQueue.clear(); (ResponseQueue as any).add = SimulatedResponseQueue.add; WebhookServer.dbInstance = testDb; (AllowedGroups as any).dbInstance = testDb; // Limpiar tablas relevantes testDb.exec('DELETE FROM response_queue'); testDb.exec('DELETE FROM allowed_groups'); testDb.exec('DELETE FROM users'); }); afterEach(() => { process.env = envBackup; }); test('bloquea mensaje de grupo no permitido (no se encolan respuestas)', async () => { const payload = { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: 'blocked-group@g.us', participant: '1234567890@s.whatsapp.net' }, message: { conversation: '/t ayuda' } } }; const res = await WebhookServer.handleRequest(createTestRequest(payload)); expect(res.status).toBe(200); // No debe haber respuestas encoladas (retorno temprano) expect(SimulatedResponseQueue.get().length).toBe(0); // allowed_groups no contiene allowed para ese grupo (get() devuelve null cuando no hay filas) const row = testDb.query(`SELECT status FROM allowed_groups WHERE group_id = 'blocked-group@g.us'`).get() as any; expect(row == null).toBe(true); }); test('permite mensaje en grupo allowed y procesa comando', async () => { // Sembrar grupo como allowed testDb.exec(` INSERT INTO allowed_groups (group_id, status, discovered_at, updated_at) VALUES ('allowed-group@g.us', 'allowed', strftime('%Y-%m-%d %H:%M:%f','now'), strftime('%Y-%m-%d %H:%M:%f','now')) `); // Marcar el grupo como activo en la caché para evitar retorno temprano por "grupo inactivo" en tests GroupSyncService.activeGroupsCache.set('allowed-group@g.us', 'Allowed Group'); const payload = { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: 'allowed-group@g.us', participant: '1234567890@s.whatsapp.net' }, message: { conversation: '/t ayuda' } } }; const res = await WebhookServer.handleRequest(createTestRequest(payload)); expect(res.status).toBe(200); // Debe haberse encolado al menos una respuesta (ayuda) expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0); }); });