import { describe, it, expect, beforeEach, afterEach } from 'bun:test'; import { Database } from 'bun:sqlite'; import { initializeDatabase } from '../../../src/db'; import { ResponseQueue } from '../../../src/services/response-queue'; const ORIGINAL_FETCH = globalThis.fetch; const envBackup = { ...process.env }; describe('ResponseQueue - jobs de reacción (enqueue + sendOne)', () => { let memdb: Database; let captured: { url?: string; payload?: any } = {}; beforeEach(() => { process.env = { ...envBackup, NODE_ENV: 'test', EVOLUTION_API_URL: 'http://evolution.test', EVOLUTION_API_INSTANCE: 'instance-1', EVOLUTION_API_KEY: 'apikey', RQ_REACTIONS_MAX_ATTEMPTS: '3', }; memdb = new Database(':memory:'); memdb.exec('PRAGMA foreign_keys = ON;'); initializeDatabase(memdb); (ResponseQueue as any).dbInstance = memdb; globalThis.fetch = async (url: RequestInfo | URL, init?: RequestInit) => { captured.url = String(url); try { captured.payload = init?.body ? JSON.parse(String(init.body)) : null; } catch { captured.payload = null; } return new Response(JSON.stringify({ ok: true }), { status: 200, headers: { 'Content-Type': 'application/json' } }); }; memdb.exec('DELETE FROM response_queue'); captured = {}; }); afterEach(() => { globalThis.fetch = ORIGINAL_FETCH; process.env = envBackup; try { memdb.close(); } catch {} }); it('enqueueReaction aplica idempotencia por (chatId, messageId, emoji) en ventana 24h', async () => { await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '🤖'); await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '🤖'); // duplicado → ignorar const cnt = memdb.prepare(`SELECT COUNT(*) AS c FROM response_queue`).get() as any; expect(Number(cnt.c)).toBe(1); // Mismo chat y mensaje, emoji distinto → debe insertar await ResponseQueue.enqueueReaction('123@g.us', 'MSG-1', '⚠️'); const cnt2 = memdb.prepare(`SELECT COUNT(*) AS c FROM response_queue`).get() as any; expect(Number(cnt2.c)).toBe(2); }); it('sendOne con metadata.kind === "reaction" usa /message/sendReaction y payload esperado', async () => { const item = { id: 42, recipient: '123@g.us', message: '', // no se usa para reaction attempts: 0, metadata: JSON.stringify({ kind: 'reaction', emoji: '🤖', chatId: '123@g.us', messageId: 'MSG-99' }), }; const res = await ResponseQueue.sendOne(item as any); expect(res.ok).toBe(true); expect(captured.url?.includes('/message/sendReaction/instance-1')).toBe(true); expect(captured.payload).toBeDefined(); expect(captured.payload.reaction).toBe('🤖'); expect(captured.payload.key).toEqual({ remoteJid: '123@g.us', fromMe: false, id: 'MSG-99' }); }); });