/** * Regression tests: DM (direct message) gating. * * Ensures that user DMs are NEVER treated as groups for gating purposes. * A user JID (e.g. 1234567890@s.whatsapp.net) must not trigger group * discovery (notify admins of a "new group") or group enforcement * (silently block the message). */ import { describe, test, expect } from 'bun:test'; import { WebhookServer } from '../../src/server'; import { SimulatedResponseQueue } from '../helpers/queue'; import { createTestRequest, registerServerTestLifecycle } from '../helpers/server-test-harness'; const testDb = registerServerTestLifecycle(); // ── Helpers ──────────────────────────────────────────────────────────── function makeDmPayload(text: string) { return { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: '1234567890@s.whatsapp.net', // user JID, NOT a group fromMe: false, }, message: { conversation: text }, }, }; } function countAllowedGroups(): number { try { const row = testDb.prepare('SELECT COUNT(*) AS c FROM allowed_groups').get() as { c: number }; return row.c; } catch { return 0; } } // ── Tests ────────────────────────────────────────────────────────────── describe('DM gating — user DMs must not be treated as groups', () => { test('discover mode: DM does NOT register user JID in allowed_groups', async () => { process.env.GROUP_GATING_MODE = 'discover'; const request = createTestRequest(makeDmPayload('t ver mis')); const response = await WebhookServer.handleRequest(request); expect(response.status).toBe(200); // No allowed_groups entry should exist for the user JID const count = countAllowedGroups(); expect(count).toBe(0); // Admin should NOT be notified about a "new group" const out = SimulatedResponseQueue.get(); const adminNotices = out.filter(r => r.message && (r.message as string).includes('Nuevo grupo detectado')); expect(adminNotices.length).toBe(0); }); test('enforce mode: DM is NOT blocked (user can still use commands)', async () => { process.env.GROUP_GATING_MODE = 'enforce'; const request = createTestRequest(makeDmPayload('t ver mis')); const response = await WebhookServer.handleRequest(request); expect(response.status).toBe(200); // Command should have processed and produced a response const out = SimulatedResponseQueue.get(); // "ver mis" in DM should produce at least one response expect(out.length).toBeGreaterThan(0); }); test('discover mode: unknown GROUP still gets discovered (regression check)', async () => { process.env.GROUP_GATING_MODE = 'discover'; process.env.NOTIFY_ADMINS_ON_DISCOVERY = 'false'; // don't spam admins in test // Ensure the group is NOT already in allowed_groups or active groups testDb.exec('DELETE FROM allowed_groups WHERE group_id = \'unknown-group@g.us\''); testDb.exec('DELETE FROM groups WHERE id = \'unknown-group@g.us\''); const payload = { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: 'unknown-group@g.us', // group JID participant: '1234567890@s.whatsapp.net', }, message: { conversation: 'hola' }, }, }; const request = createTestRequest(payload); await WebhookServer.handleRequest(request); // Should have registered the group as pending const row = testDb.prepare('SELECT * FROM allowed_groups WHERE group_id = ?').get('unknown-group@g.us') as any; expect(row).toBeDefined(); expect(row.status).toBe('pending'); }); test('enforce mode: non-allowed GROUP is still blocked (regression check)', async () => { process.env.GROUP_GATING_MODE = 'enforce'; // Ensure the group is NOT allowed testDb.exec('DELETE FROM allowed_groups WHERE group_id = \'blocked-group@g.us\''); testDb.exec('DELETE FROM groups WHERE id = \'blocked-group@g.us\''); // Add it as active so it passes ensureGroupActive testDb.exec(` INSERT OR IGNORE INTO groups (id, community_id, name, active) VALUES ('blocked-group@g.us', 'test-community', 'Blocked Group', 1) `); const payload = { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: 'blocked-group@g.us', participant: '1234567890@s.whatsapp.net', }, message: { conversation: 't ver mis' }, }, }; const request = createTestRequest(payload); await WebhookServer.handleRequest(request); // Message should be silently blocked (no response) const out = SimulatedResponseQueue.get(); expect(out.length).toBe(0); }); test('enforce mode: allowed GROUP can still use commands (regression check)', async () => { process.env.GROUP_GATING_MODE = 'enforce'; testDb.exec(` INSERT OR REPLACE INTO allowed_groups (group_id, label, status) VALUES ('group-id@g.us', 'Test Group', 'allowed') `); const payload = { event: 'messages.upsert', instance: 'test-instance', data: { key: { remoteJid: 'group-id@g.us', participant: '1234567890@s.whatsapp.net', }, message: { conversation: 't n Test tarea mañana' }, }, }; const request = createTestRequest(payload); await WebhookServer.handleRequest(request); const out = SimulatedResponseQueue.get(); expect(out.length).toBeGreaterThan(0); }); });