refactor: usar locator para inyectar DB en tests

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
main
brobert 1 month ago
parent 6cb6c31d8d
commit ecc0cc6fd8

@ -1,5 +1,6 @@
import Database, { type Database as SqliteDatabase } from 'bun:sqlite';
import { initializeDatabase } from '../../src/db';
import { setDb } from '../../src/db/locator';
// Servicios opcionales para inyección de DB en tests.
// Importamos con nombres existentes en la base de código para respetar convenciones.
@ -25,12 +26,7 @@ export function makeMemDb(): SqliteDatabase {
* Pensado para usarse en beforeAll/beforeEach de tests que usan estos servicios.
*/
export function injectAllServices(db: SqliteDatabase): void {
try { (TaskService as any).dbInstance = db; } catch {}
try { (CommandService as any).dbInstance = db; } catch {}
try { (ResponseQueue as any).dbInstance = db; } catch {}
try { (IdentityService as any).dbInstance = db; } catch {}
try { (GroupSyncService as any).dbInstance = db; } catch {}
try { (RemindersService as any).dbInstance = db; } catch {}
setDb(db);
}
/**
@ -49,7 +45,6 @@ export function resetServices(): void {
* Marca como 'allowed' los groupIds indicados en la DB provista.
*/
export function seedAllowed(db: SqliteDatabase, groupIds: string[]): void {
(AllowedGroups as any).dbInstance = db;
for (const gid of groupIds) {
const g = String(gid || '').trim();
if (!g) continue;

@ -5,6 +5,7 @@ import { ResponseQueue } from '../../src/services/response-queue';
import { GroupSyncService } from '../../src/services/group-sync';
import { initializeDatabase, ensureUserExists } from '../../src/db';
import { TaskService } from '../../src/tasks/service';
import { setDb, resetDb } from '../../src/db/locator';
let originalAdd: any;
@ -38,11 +39,8 @@ beforeEach(() => {
// Inject testDb for WebhookServer to use
WebhookServer.dbInstance = testDb;
// Inject testDb for GroupSyncService to use
GroupSyncService.dbInstance = testDb;
// Inject testDb for TaskService to use
(TaskService as any).dbInstance = testDb;
// Usar el locator global para el resto de servicios
setDb(testDb);
// Ensure database is initialized (recreates tables if dropped)
initializeDatabase(testDb);

@ -4,6 +4,7 @@ import { WebhookServer } from '../../../src/server';
import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
let testDb: Database;
let originalAdd: any;
@ -28,6 +29,7 @@ describe('WebhookServer - discovery guarda label del grupo si está en caché',
afterAll(() => {
(ResponseQueue as any).add = originalAdd;
resetDb();
testDb.close();
});
@ -40,6 +42,7 @@ describe('WebhookServer - discovery guarda label del grupo si está en caché',
SimulatedResponseQueue.clear();
(ResponseQueue as any).add = SimulatedResponseQueue.add;
WebhookServer.dbInstance = testDb;
setDb(testDb);
// Limpiar tablas relevantes
testDb.exec('DELETE FROM response_queue');

@ -5,6 +5,7 @@ import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
let testDb: Database;
let originalAdd: any;
@ -29,6 +30,7 @@ describe('WebhookServer - enforce gating (modo=enforce)', () => {
afterAll(() => {
(ResponseQueue as any).add = originalAdd;
resetDb();
testDb.close();
});
@ -41,7 +43,7 @@ describe('WebhookServer - enforce gating (modo=enforce)', () => {
SimulatedResponseQueue.clear();
(ResponseQueue as any).add = SimulatedResponseQueue.add;
WebhookServer.dbInstance = testDb;
(AllowedGroups as any).dbInstance = testDb;
setDb(testDb);
// Limpiar tablas relevantes
testDb.exec('DELETE FROM response_queue');

@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite';
import { WebhookServer } from '../../../src/server';
import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
import { setDb, resetDb } from '../../../src/db/locator';
let testDb: Database;
let originalAdd: any;
@ -27,6 +28,7 @@ describe('WebhookServer - unknown group discovery (mode=discover)', () => {
afterAll(() => {
(ResponseQueue as any).add = originalAdd;
resetDb();
testDb.close();
});
@ -39,6 +41,7 @@ describe('WebhookServer - unknown group discovery (mode=discover)', () => {
SimulatedResponseQueue.clear();
(ResponseQueue as any).add = SimulatedResponseQueue.add;
WebhookServer.dbInstance = testDb;
setDb(testDb);
// Limpiar tablas relevantes
testDb.exec('DELETE FROM response_queue');

@ -5,6 +5,7 @@ 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';
import { setDb } from '../../../src/db/locator';
function makePayload(event: string, data: any) {
return {
@ -31,9 +32,7 @@ describe('WebhookServer E2E - reacciones por comando', () => {
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;
setDb(memdb);
});
afterAll(() => {

@ -2,6 +2,7 @@ import { describe, it, beforeEach, expect } from 'bun:test';
import { makeMemDb } from '../../helpers/db';
import { AdminService } from '../../../src/services/admin';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { setDb } from '../../../src/db/locator';
describe('AdminService - comandos básicos', () => {
const envBackup = process.env;

@ -1,11 +1,12 @@
import { describe, it, beforeEach, expect } from 'bun:test';
import { makeMemDb } from '../../helpers/db';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { setDb } from '../../../src/db/locator';
describe('AllowedGroups service', () => {
beforeEach(() => {
const memdb = makeMemDb();
(AllowedGroups as any).dbInstance = memdb;
setDb(memdb);
AllowedGroups.resetForTests();
});

@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';
describe('CommandService - asignación por defecto (sin dueño vs creador)', () => {
let memdb: Database;
@ -10,8 +11,7 @@ describe('CommandService - asignación por defecto (sin dueño vs creador)', ()
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite';
import { initializeDatabase, ensureUserExists } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';
describe('CommandService - /t tomar y /t soltar', () => {
let memdb: Database;
@ -10,8 +11,7 @@ describe('CommandService - /t tomar y /t soltar', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';
describe('CommandService - formato dd/MM en ACK de creación', () => {
let memdb: Database;
@ -10,8 +11,7 @@ describe('CommandService - formato dd/MM en ACK de creación', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { makeMemDb } from '../../helpers/db';
import { CommandService } from '../../../src/services/command';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { setDb, resetDb } from '../../../src/db/locator';
describe('CommandService - gating en modo enforce', () => {
const envBackup = process.env;
@ -9,8 +10,7 @@ describe('CommandService - gating en modo enforce', () => {
beforeEach(() => {
process.env = { ...envBackup, NODE_ENV: 'test', GROUP_GATING_MODE: 'enforce' };
const memdb = makeMemDb();
(CommandService as any).dbInstance = memdb;
(AllowedGroups as any).dbInstance = memdb;
setDb(memdb);
});
afterEach(() => {

@ -3,6 +3,7 @@ import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';
describe('CommandService - formato dd/MM en listados', () => {
let memdb: Database;
@ -10,8 +11,7 @@ describe('CommandService - formato dd/MM en listados', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { Metrics } from '../../../src/services/metrics';
import { setDb } from '../../../src/db/locator';
describe('CommandService - /t nueva (A2: fallback menciones)', () => {
let memdb: Database;
@ -11,8 +12,7 @@ describe('CommandService - /t nueva (A2: fallback menciones)', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { CommandService } from '../../../src/services/command';
import { ResponseQueue } from '../../../src/services/response-queue';
import { TaskService } from '../../../src/tasks/service';
import { setDb } from '../../../src/db/locator';
describe('CommandService - JIT onboarding para menciones @lid y números demasiado largos', () => {
let memdb: Database;
@ -11,9 +12,7 @@ describe('CommandService - JIT onboarding para menciones @lid y números demasia
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
(CommandService as any).dbInstance = memdb;
(TaskService as any).dbInstance = memdb;
(ResponseQueue as any).dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { Metrics } from '../../../src/services/metrics';
import { setDb } from '../../../src/db/locator';
describe('CommandService - A4 JIT DM al asignador', () => {
let memdb: Database;
@ -11,8 +12,7 @@ describe('CommandService - A4 JIT DM al asignador', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb as any;
CommandService.dbInstance = memdb as any;
setDb(memdb as any);
});
beforeEach(() => {

@ -1,7 +1,8 @@
import { describe, it, beforeEach, expect } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { initializeDatabase } from '../../../src/db'];
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';
describe('CommandService - configurar recordatorios', () => {
let memdb: Database;
@ -15,7 +16,7 @@ describe('CommandService - configurar recordatorios', () => {
initializeDatabase(memdb);
// Inyectar DB
(CommandService as any).dbInstance = memdb;
setDb(memdb);
// Limpiar tablas
memdb.exec(`DELETE FROM response_queue;`);

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { Metrics } from '../../../src/services/metrics';
import { setDb } from '../../../src/db/locator';
describe('CommandService - autoasignación con "yo" / "@yo"', () => {
let memdb: Database;
@ -11,8 +12,7 @@ describe('CommandService - autoasignación con "yo" / "@yo"', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
CommandService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb } from '../../../src/db/locator';
describe('CommandService - inserta task_origins al crear en grupo con messageId', () => {
let memdb: Database;
@ -11,8 +12,7 @@ describe('CommandService - inserta task_origins al crear en grupo con messageId'
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
(TaskService as any).dbInstance = memdb;
(CommandService as any).dbInstance = memdb;
setDb(memdb);
// Sembrar grupo activo y cache
memdb.exec(`

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { CommandService } from '../../../src/services/command';
import { TaskService } from '../../../src/tasks/service';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
let memDb: Database;
const testContextBase = {
@ -15,9 +16,7 @@ const testContextBase = {
beforeEach(() => {
memDb = new Database(':memory:');
initializeDatabase(memDb);
(CommandService as any).dbInstance = memDb;
(TaskService as any).dbInstance = memDb;
(GroupSyncService as any).dbInstance = memDb;
setDb(memDb);
GroupSyncService.activeGroupsCache.clear();
});
@ -282,7 +281,7 @@ test('ver todos por DM: “Tus tareas” + nota instructiva para ver sin dueño
});
afterEach(() => {
try { memDb.close(); } catch { }
try { resetDb(); memDb.close(); } catch { }
});
describe('CommandService', () => {

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { CommandService } from '../../../src/services/command';
import { sha256Hex } from '../../../src/utils/crypto';
import { Metrics } from '../../../src/services/metrics';
import { setDb } from '../../../src/db/locator';
const envBackup = { ...process.env };
let memdb: Database;
@ -20,7 +21,7 @@ describe('CommandService - /t web (emisión de token de login)', () => {
Metrics.reset?.();
memdb = new Database(':memory:');
initializeDatabase(memdb);
(CommandService as any).dbInstance = memdb;
setDb(memdb);
});
afterEach(() => {

@ -14,8 +14,6 @@ describe('GroupSyncService - alias_coverage_ratio', () => {
Metrics.reset();
db = makeMemDb();
injectAllServices(db);
(GroupSyncService as any).dbInstance = db;
(IdentityService as any).dbInstance = db;
// Crear grupo activo requerido por FK
db.prepare(`INSERT INTO groups (id, community_id, name, active) VALUES (?, ?, ?, 1)`)

@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { makeMemDb } from '../../helpers/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { setDb } from '../../../src/db/locator';
describe('GroupSyncService - gating en syncMembersForGroup (enforce)', () => {
const envBackup = process.env;
@ -9,8 +10,7 @@ describe('GroupSyncService - gating en syncMembersForGroup (enforce)', () => {
beforeEach(() => {
process.env = { ...envBackup, NODE_ENV: 'test', GROUP_GATING_MODE: 'enforce' };
const memdb = makeMemDb();
(GroupSyncService as any).dbInstance = memdb;
(AllowedGroups as any).dbInstance = memdb;
setDb(memdb);
// Stub fetchGroupMembersFromAPI para no hacer red
(GroupSyncService as any).fetchGroupMembersFromAPI = async (_groupId: string) => {

@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import Database from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
describe('GroupSyncService - upsertGroups actualiza label en allowed_groups', () => {
const envBackup = process.env;
@ -11,7 +12,7 @@ describe('GroupSyncService - upsertGroups actualiza label en allowed_groups', ()
process.env = { ...envBackup, NODE_ENV: 'test', WHATSAPP_COMMUNITY_ID: 'comm-1' };
memdb = new Database(':memory:');
initializeDatabase(memdb);
(GroupSyncService as any).dbInstance = memdb;
setDb(memdb);
// Limpiar tablas
memdb.exec('DELETE FROM allowed_groups');
@ -19,6 +20,7 @@ describe('GroupSyncService - upsertGroups actualiza label en allowed_groups', ()
});
afterEach(() => {
resetDb();
memdb.close();
process.env = envBackup;
});

@ -2,6 +2,7 @@ import { Database } from 'bun:sqlite';
import { beforeAll, beforeEach, afterAll, describe, expect, test } from 'bun:test';
import { initializeDatabase } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
describe('GroupSyncService - reconcileGroupMembers', () => {
let memdb: Database;
@ -10,11 +11,11 @@ describe('GroupSyncService - reconcileGroupMembers', () => {
memdb = new Database(':memory:');
memdb.exec('PRAGMA foreign_keys = ON;');
initializeDatabase(memdb);
// Inyectar DB en el servicio
GroupSyncService.dbInstance = memdb as any;
setDb(memdb);
});
afterAll(() => {
resetDb();
memdb.close();
});

@ -3,6 +3,7 @@ import Database from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { setDb, resetDb } from '../../../src/db/locator';
const envBackup = { ...process.env } as NodeJS.ProcessEnv;
@ -22,8 +23,7 @@ describe('GroupSyncService - onboarding A3', () => {
};
memdb = new Database(':memory:');
initializeDatabase(memdb);
(GroupSyncService as any).dbInstance = memdb;
(AllowedGroups as any).dbInstance = memdb;
setDb(memdb);
// Sembrar grupo activo
memdb.prepare(`INSERT INTO groups (id, community_id, name, active, last_verified) VALUES (?,?,?,?, strftime('%Y-%m-%d %H:%M:%f','now'))`)
@ -31,6 +31,7 @@ describe('GroupSyncService - onboarding A3', () => {
});
afterEach(() => {
resetDb();
memdb.close();
process.env = envBackup;
});

@ -3,6 +3,7 @@ import Database from 'bun:sqlite';
import { initializeDatabase, ensureUserExists } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { ResponseQueue } from '../../../src/services/response-queue';
import { setDb, resetDb } from '../../../src/db/locator';
const envBackup = { ...process.env };
let originalSyncMembers: any;
@ -90,8 +91,7 @@ describe('GroupSyncService - scheduler de miembros', () => {
const memdb = new Database(':memory:');
initializeDatabase(memdb);
(GroupSyncService as any).dbInstance = memdb;
(ResponseQueue as any).dbInstance = memdb;
setDb(memdb);
// Sembrar grupo activo con miembro y token de calendario
memdb.exec(`INSERT INTO groups (id, community_id, name, active, archived, last_verified) VALUES ('g1@g.us','comm-1','G1',1,0,strftime('%Y-%m-%d %H:%M:%f','now'))`);
@ -121,5 +121,9 @@ describe('GroupSyncService - scheduler de miembros', () => {
// Notificación encolada a admins
const msg = memdb.query(`SELECT message FROM response_queue ORDER BY id DESC LIMIT 1`).get() as any;
expect(msg && String(msg.message)).toContain('/admin archivar-grupo g1@g.us');
// Limpieza de DB/locator local a este test
resetDb();
try { memdb.close(); } catch {}
});
});

@ -2,6 +2,7 @@ import { describe, test, expect, beforeEach, afterEach, beforeAll, afterAll } fr
import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
let memdb: Database;
const envBackup = { ...process.env };
@ -12,10 +13,11 @@ describe('GroupSyncService - syncMembersForActiveGroups (agregado por grupos)',
memdb = new Database(':memory:');
memdb.exec('PRAGMA foreign_keys = ON;');
initializeDatabase(memdb);
GroupSyncService.dbInstance = memdb as any;
setDb(memdb as any);
});
afterAll(() => {
resetDb();
memdb.close();
});

@ -3,6 +3,7 @@ import { GroupSyncService } from '../../../src/services/group-sync';
import { db } from '../../../src/db';
import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { setDb } from '../../../src/db/locator';
// Store original globals
const originalFetch = globalThis.fetch;
@ -17,8 +18,8 @@ describe('GroupSyncService', () => {
testDb = new Database(':memory:');
initializeDatabase(testDb);
// Assign the isolated DB to the service
GroupSyncService.dbInstance = testDb;
// Assign the isolated DB to the service (via locator)
setDb(testDb);
// Clear and reset test data
testDb.exec('DELETE FROM groups');

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { IdentityService } from '../../../src/services/identity';
import { WebhookServer } from '../../../src/server';
import { GroupSyncService } from '../../../src/services/group-sync';
import { setDb, resetDb } from '../../../src/db/locator';
const ORIGINAL_FETCH = globalThis.fetch;
const envBackup = { ...process.env };
@ -18,9 +19,8 @@ describe('Alias @lid ↔ número: aprendizaje y uso en sync de miembros', () =>
initializeDatabase(memdb);
// Inyectar DB en servicios implicados
(IdentityService as any).dbInstance = memdb;
(WebhookServer as any).dbInstance = memdb;
(GroupSyncService as any).dbInstance = memdb;
setDb(memdb);
// Limpiar caché de grupos para evitar interferencias
GroupSyncService.activeGroupsCache.clear();
@ -29,6 +29,7 @@ describe('Alias @lid ↔ número: aprendizaje y uso en sync de miembros', () =>
afterEach(() => {
globalThis.fetch = ORIGINAL_FETCH;
process.env = envBackup;
resetDb();
memdb.close();
});

@ -3,6 +3,7 @@ import { WebhookServer } from '../../../src/server';
import { Metrics } from '../../../src/services/metrics';
import { initializeDatabase } from '../../../src/db';
import { Database } from 'bun:sqlite';
import { setDb, resetDb } from '../../../src/db/locator';
import { toIsoSql as toIso } from '../../helpers/dates';
@ -16,11 +17,12 @@ describe('/metrics y /health (detallado)', () => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
(WebhookServer as any).dbInstance = memdb;
setDb(memdb);
});
afterEach(() => {
process.env = envBackup;
try { memdb.close(); } catch {}
try { resetDb(); memdb.close(); } catch {}
});
test('/metrics devuelve métricas en formato Prometheus', async () => {

@ -6,6 +6,7 @@ import { RemindersService } from '../../../src/services/reminders';
import { AllowedGroups } from '../../../src/services/allowed-groups';
import { ResponseQueue } from '../../../src/services/response-queue';
import { toIsoSql } from '../../helpers/dates';
import { setDb } from '../../../src/db/locator';
function seedGroup(db: Database, groupId: string) {
const cols = db.query(`PRAGMA table_info(groups)`).all() as any[];
@ -49,9 +50,7 @@ describe('RemindersService - gating por grupos en modo enforce', () => {
process.env = { ...envBackup, NODE_ENV: 'test', GROUP_GATING_MODE: 'enforce', TZ: 'Europe/Madrid', REMINDERS_GRACE_MINUTES: '60' };
memdb = new Database(':memory:');
initializeDatabase(memdb);
(TaskService as any).dbInstance = memdb;
(RemindersService as any).dbInstance = memdb;
(AllowedGroups as any).dbInstance = memdb;
setDb(memdb);
// Stub de ResponseQueue
originalAdd = (ResponseQueue as any).add;

@ -4,6 +4,7 @@ import { initializeDatabase } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { RemindersService } from '../../../src/services/reminders';
import { ResponseQueue } from '../../../src/services/response-queue';
import { setDb } from '../../../src/db/locator';
import { toIsoSql as toIso } from '../../helpers/dates';
@ -20,9 +21,7 @@ describe('RemindersService', () => {
initializeDatabase(memdb);
// Inyectar DB en servicios
(TaskService as any).dbInstance = memdb;
(RemindersService as any).dbInstance = memdb;
(ResponseQueue as any).dbInstance = memdb;
setDb(memdb);
// Limpiar tablas entre tests por seguridad
memdb.exec(`DELETE FROM response_queue;`);

@ -4,20 +4,19 @@ import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
let testDb: Database;
let originalDbInstance: Database;
import { toIsoSql as toIso } from '../../helpers/dates';
import { setDb, resetDb } from '../../../src/db/locator';
describe('ResponseQueue cleanup/retention', () => {
beforeAll(() => {
testDb = new Database(':memory:');
initializeDatabase(testDb);
originalDbInstance = (ResponseQueue as any).dbInstance;
(ResponseQueue as any).dbInstance = testDb;
setDb(testDb);
});
afterAll(() => {
(ResponseQueue as any).dbInstance = originalDbInstance;
resetDb();
testDb.close();
});

@ -2,6 +2,7 @@ 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';
import { setDb, resetDb } from '../../../src/db/locator';
const ORIGINAL_FETCH = globalThis.fetch;
const envBackup = { ...process.env };
@ -24,7 +25,7 @@ describe('ResponseQueue - jobs de reacción (enqueue + sendOne)', () => {
memdb.exec('PRAGMA foreign_keys = ON;');
initializeDatabase(memdb);
(ResponseQueue as any).dbInstance = memdb;
setDb(memdb);
globalThis.fetch = async (url: RequestInfo | URL, init?: RequestInit) => {
captured.url = String(url);
@ -46,7 +47,7 @@ describe('ResponseQueue - jobs de reacción (enqueue + sendOne)', () => {
afterEach(() => {
globalThis.fetch = ORIGINAL_FETCH;
process.env = envBackup;
try { memdb.close(); } catch {}
try { resetDb(); memdb.close(); } catch {}
});
it('enqueueReaction aplica idempotencia por (chatId, messageId, emoji) en ventana 24h', async () => {

@ -3,19 +3,18 @@ import { Database } from 'bun:sqlite';
import { initializeDatabase } from '../../../src/db';
import { ResponseQueue } from '../../../src/services/response-queue';
import { toIsoSql } from '../../helpers/dates';
import { setDb, resetDb } from '../../../src/db/locator';
let testDb: Database;
let envBackup: NodeJS.ProcessEnv;
let originalDbInstance: Database;
describe('ResponseQueue (persistent add)', () => {
beforeAll(() => {
envBackup = { ...process.env };
testDb = new Database(':memory:');
initializeDatabase(testDb);
// Guardar e inyectar DB de pruebas
originalDbInstance = (ResponseQueue as any).dbInstance;
(ResponseQueue as any).dbInstance = testDb;
// Inyectar DB de pruebas vía locator
setDb(testDb);
});
afterAll(() => {
@ -111,8 +110,8 @@ describe('ResponseQueue (persistent add)', () => {
describe('ResponseQueue (retries/backoff)', () => {
// Reutiliza la misma DB inyectada en el bloque anterior
afterAll(() => {
// Restaurar DB original y cerrar la de prueba al finalizar todos los tests de reintentos
(ResponseQueue as any).dbInstance = originalDbInstance;
// Restablecer locator y cerrar la DB de prueba
resetDb();
testDb.close();
});

@ -2,6 +2,7 @@ import { describe, it, expect, beforeAll, beforeEach } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase, ensureUserExists } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { setDb } from '../../../src/db/locator';
describe('TaskService - claim/unassign', () => {
let memdb: Database;
@ -9,7 +10,7 @@ describe('TaskService - claim/unassign', () => {
beforeAll(() => {
memdb = new Database(':memory:');
initializeDatabase(memdb);
TaskService.dbInstance = memdb;
setDb(memdb);
});
beforeEach(() => {

@ -2,17 +2,19 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase, ensureUserExists } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { setDb, resetDb } from '../../../src/db/locator';
let memDb: Database;
beforeEach(() => {
memDb = new Database(':memory:');
initializeDatabase(memDb);
TaskService.dbInstance = memDb;
setDb(memDb);
});
afterEach(() => {
try {
resetDb();
memDb.close();
} catch {}
});

Loading…
Cancel
Save