import { describe, it, beforeEach, afterEach, expect } from 'bun:test'; import { Database } from 'bun:sqlite'; import { initializeDatabase } from '../../../src/db'; import { IdentityService } from '../../../src/services/identity'; import { WebhookServer } from '../../../src/server'; import { GroupSyncService } from '../../../src/services/group-sync'; const ORIGINAL_FETCH = globalThis.fetch; const envBackup = { ...process.env }; describe('Alias @lid ↔ número: aprendizaje y uso en sync de miembros', () => { let memdb: Database; beforeEach(() => { process.env = { ...envBackup }; memdb = new Database(':memory:'); memdb.exec('PRAGMA foreign_keys = ON;'); initializeDatabase(memdb); // Inyectar DB en servicios implicados (IdentityService as any).dbInstance = memdb; (WebhookServer as any).dbInstance = memdb; (GroupSyncService as any).dbInstance = memdb; // Limpiar caché de grupos para evitar interferencias GroupSyncService.activeGroupsCache.clear(); }); afterEach(() => { globalThis.fetch = ORIGINAL_FETCH; process.env = envBackup; memdb.close(); }); it('aprende alias desde participantAlt y luego resuelve miembros con solo @lid', async () => { // 1) Simular mensaje de grupo que trae participant (alias @lid) y participantAlt (número real) process.env.NODE_ENV = 'test'; // evita efectos de red/timers const payload = { key: { remoteJid: '12345-678@g.us', participant: 'userXYZ@lid', participantAlt: '666777888@s.whatsapp.net', fromMe: false }, message: { conversation: 'hola' } }; await WebhookServer.handleMessageUpsert(payload); // Verificar que el alias fue aprendido const resolved = IdentityService.resolveAliasOrNull('userXYZ@lid'); expect(resolved).toBe('666777888'); // Añadir un segundo alias manualmente para cubrir varios miembros IdentityService.upsertAlias('abc@lid', '999000111@s.whatsapp.net', 'test-seed'); expect(IdentityService.resolveAliasOrNull('abc@lid')).toBe('999000111'); // 2) Ahora simular la Evolution API devolviendo solo IDs con @lid en /group/participants process.env.NODE_ENV = 'development'; // evitar early-return en fetchGroupMembersFromAPI process.env.EVOLUTION_API_URL = 'http://evolution.test'; process.env.EVOLUTION_API_INSTANCE = 'instance-1'; process.env.EVOLUTION_API_KEY = 'apikey'; globalThis.fetch = async (url: RequestInfo | URL) => { if (String(url).includes('/group/participants/')) { const body = { participants: [ { id: 'userXYZ@lid', admin: 'admin' }, // debe resolverse a 666777888 (admin) { id: 'abc@lid', admin: null } // debe resolverse a 999000111 (no admin) ] }; return new Response(JSON.stringify(body), { status: 200, headers: { 'Content-Type': 'application/json' } }); } return new Response('not found', { status: 404 }); }; const out = await (GroupSyncService as any).fetchGroupMembersFromAPI('12345-678@g.us'); const map = new Map(out.map((x: any) => [x.userId, x.isAdmin])); expect(map.has('666777888')).toBe(true); expect(map.has('999000111')).toBe(true); expect(map.get('666777888')).toBe(true); // admin resuelto expect(map.get('999000111')).toBe(false); // no admin }); });