feat: precalentar métricas de reacciones y añadir tests E2E
Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>main
parent
f0ab277d38
commit
215f242a0d
@ -0,0 +1,131 @@
|
||||
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');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue