import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'bun:test'; import { Database } from 'bun:sqlite'; import { initializeDatabase } from '../../../src/db'; import { WebhookServer } from '../../../src/server'; import { ResponseQueue } from '../../../src/services/response-queue'; import { AllowedGroups } from '../../../src/services/allowed-groups'; import { GroupSyncService } from '../../../src/services/group-sync'; function makePayload(event: string, data: any) { return { event, instance: 'test-instance', data }; } async function postWebhook(payload: any) { const req = new Request('http://localhost/webhook', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); return await WebhookServer.handleRequest(req); } describe('WebhookServer E2E - reacciones por comando', () => { let memdb: Database; const envBackup = { ...process.env }; beforeAll(() => { memdb = new Database(':memory:'); initializeDatabase(memdb); (WebhookServer as any).dbInstance = memdb; (ResponseQueue as any).dbInstance = memdb; (AllowedGroups as any).dbInstance = memdb; (GroupSyncService as any).dbInstance = memdb; }); afterAll(() => { process.env = envBackup; try { memdb.close(); } catch {} }); beforeEach(() => { process.env = { ...envBackup, NODE_ENV: 'test', REACTIONS_ENABLED: 'true', REACTIONS_SCOPE: 'groups', GROUP_GATING_MODE: 'enforce', CHATBOT_PHONE_NUMBER: '999' }; memdb.exec(` DELETE FROM response_queue; DELETE FROM task_assignments; DELETE FROM tasks; DELETE FROM users; DELETE FROM groups; DELETE FROM allowed_groups; `); GroupSyncService.activeGroupsCache?.clear?.(); }); it('encola 🤖 en grupo allowed y activo tras /t n', async () => { const groupId = 'g1@g.us'; // Sembrar grupo activo y allowed memdb.exec(` INSERT OR IGNORE INTO groups (id, community_id, name, active, archived, is_community, last_verified) VALUES ('${groupId}', 'comm-1', 'G1', 1, 0, 0, strftime('%Y-%m-%d %H:%M:%f','now')) `); GroupSyncService.activeGroupsCache.set(groupId, 'G1'); AllowedGroups.setStatus(groupId, 'allowed'); const payload = makePayload('MESSAGES_UPSERT', { key: { remoteJid: groupId, id: 'MSG-OK-1', fromMe: false, participant: '600111222@s.whatsapp.net' }, message: { conversation: '/t n prueba e2e' } }); const res = await postWebhook(payload); expect(res.status).toBe(200); const row = memdb.prepare(`SELECT metadata FROM response_queue WHERE metadata LIKE '%"kind":"reaction"%' ORDER BY id DESC LIMIT 1`).get() as any; expect(row).toBeTruthy(); const meta = JSON.parse(String(row.metadata)); expect(meta.kind).toBe('reaction'); expect(meta.emoji).toBe('🤖'); expect(meta.chatId).toBe(groupId); expect(meta.messageId).toBe('MSG-OK-1'); }); it('no encola reacción en DM cuando REACTIONS_SCOPE=groups', async () => { const dmJid = '600111222@s.whatsapp.net'; const payload = makePayload('MESSAGES_UPSERT', { key: { remoteJid: dmJid, id: 'MSG-DM-1', fromMe: false }, message: { conversation: '/t n en DM no reacciona' } }); const res = await postWebhook(payload); expect(res.status).toBe(200); const cnt = memdb.prepare(`SELECT COUNT(*) AS c FROM response_queue WHERE metadata LIKE '%"kind":"reaction"%'`).get() as any; expect(Number(cnt.c)).toBe(0); }); it('encola ⚠️ en grupo allowed y activo para comando inválido (/t x sin IDs)', async () => { const groupId = 'g2@g.us'; memdb.exec(` INSERT OR IGNORE INTO groups (id, community_id, name, active, archived, is_community, last_verified) VALUES ('${groupId}', 'comm-1', 'G2', 1, 0, 0, strftime('%Y-%m-%d %H:%M:%f','now')) `); GroupSyncService.activeGroupsCache.set(groupId, 'G2'); AllowedGroups.setStatus(groupId, 'allowed'); const payload = makePayload('MESSAGES_UPSERT', { key: { remoteJid: groupId, id: 'MSG-ERR-1', fromMe: false, participant: '600111222@s.whatsapp.net' }, message: { conversation: '/t x' } }); const res = await postWebhook(payload); expect(res.status).toBe(200); const row = memdb.prepare(`SELECT metadata FROM response_queue WHERE metadata LIKE '%"kind":"reaction"%' ORDER BY id DESC LIMIT 1`).get() as any; expect(row).toBeTruthy(); const meta = JSON.parse(String(row.metadata)); expect(meta.kind).toBe('reaction'); expect(meta.emoji).toBe('⚠️'); expect(meta.chatId).toBe(groupId); expect(meta.messageId).toBe('MSG-ERR-1'); }); });