diff --git a/tests/helpers/db.ts b/tests/helpers/db.ts index 82db006..e146ff9 100644 --- a/tests/helpers/db.ts +++ b/tests/helpers/db.ts @@ -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; diff --git a/tests/unit/server.test.ts b/tests/unit/server.test.ts index 3f44a44..b8ff24e 100644 --- a/tests/unit/server.test.ts +++ b/tests/unit/server.test.ts @@ -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); diff --git a/tests/unit/server/discovery-label.test.ts b/tests/unit/server/discovery-label.test.ts index 43d4425..ecc293d9 100644 --- a/tests/unit/server/discovery-label.test.ts +++ b/tests/unit/server/discovery-label.test.ts @@ -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'); diff --git a/tests/unit/server/enforce-gating.test.ts b/tests/unit/server/enforce-gating.test.ts index 28f2a76..de92211 100644 --- a/tests/unit/server/enforce-gating.test.ts +++ b/tests/unit/server/enforce-gating.test.ts @@ -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'); diff --git a/tests/unit/server/unknown-group-discovery.test.ts b/tests/unit/server/unknown-group-discovery.test.ts index f4c6f1e..9e5e153 100644 --- a/tests/unit/server/unknown-group-discovery.test.ts +++ b/tests/unit/server/unknown-group-discovery.test.ts @@ -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'); diff --git a/tests/unit/server/webhook.reactions.e2e.test.ts b/tests/unit/server/webhook.reactions.e2e.test.ts index dc83a9e..9636083 100644 --- a/tests/unit/server/webhook.reactions.e2e.test.ts +++ b/tests/unit/server/webhook.reactions.e2e.test.ts @@ -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(() => { diff --git a/tests/unit/services/admin.test.ts b/tests/unit/services/admin.test.ts index 248780e..b138403 100644 --- a/tests/unit/services/admin.test.ts +++ b/tests/unit/services/admin.test.ts @@ -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; diff --git a/tests/unit/services/allowed-groups.test.ts b/tests/unit/services/allowed-groups.test.ts index 3cf1a0b..cd653f2 100644 --- a/tests/unit/services/allowed-groups.test.ts +++ b/tests/unit/services/allowed-groups.test.ts @@ -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(); }); diff --git a/tests/unit/services/command.assignment-defaults.test.ts b/tests/unit/services/command.assignment-defaults.test.ts index 55a330c..5cf0a93 100644 --- a/tests/unit/services/command.assignment-defaults.test.ts +++ b/tests/unit/services/command.assignment-defaults.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.claim-unassign.test.ts b/tests/unit/services/command.claim-unassign.test.ts index 165aca2..b782b2e 100644 --- a/tests/unit/services/command.claim-unassign.test.ts +++ b/tests/unit/services/command.claim-unassign.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.formatting-ddmm.test.ts b/tests/unit/services/command.formatting-ddmm.test.ts index 293d2c4..ca5e19e 100644 --- a/tests/unit/services/command.formatting-ddmm.test.ts +++ b/tests/unit/services/command.formatting-ddmm.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.gating.test.ts b/tests/unit/services/command.gating.test.ts index bd5fea3..261ebc0 100644 --- a/tests/unit/services/command.gating.test.ts +++ b/tests/unit/services/command.gating.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.listing-ddmm.test.ts b/tests/unit/services/command.listing-ddmm.test.ts index a2726b2..85e7b40 100644 --- a/tests/unit/services/command.listing-ddmm.test.ts +++ b/tests/unit/services/command.listing-ddmm.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.nueva-assignees.test.ts b/tests/unit/services/command.nueva-assignees.test.ts index 293d423..1c835fc 100644 --- a/tests/unit/services/command.nueva-assignees.test.ts +++ b/tests/unit/services/command.nueva-assignees.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.onboarding-jit-lid.test.ts b/tests/unit/services/command.onboarding-jit-lid.test.ts index e69a729..2acf1bf 100644 --- a/tests/unit/services/command.onboarding-jit-lid.test.ts +++ b/tests/unit/services/command.onboarding-jit-lid.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.onboarding-jit.test.ts b/tests/unit/services/command.onboarding-jit.test.ts index 2f47cd6..a07939f 100644 --- a/tests/unit/services/command.onboarding-jit.test.ts +++ b/tests/unit/services/command.onboarding-jit.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.reminders-config.test.ts b/tests/unit/services/command.reminders-config.test.ts index 0584a85..9ad5c34 100644 --- a/tests/unit/services/command.reminders-config.test.ts +++ b/tests/unit/services/command.reminders-config.test.ts @@ -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;`); diff --git a/tests/unit/services/command.self-assign.test.ts b/tests/unit/services/command.self-assign.test.ts index 9dd2b10..1f06e9d 100644 --- a/tests/unit/services/command.self-assign.test.ts +++ b/tests/unit/services/command.self-assign.test.ts @@ -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(() => { diff --git a/tests/unit/services/command.task-origins.test.ts b/tests/unit/services/command.task-origins.test.ts index 67eae9f..640fd27 100644 --- a/tests/unit/services/command.task-origins.test.ts +++ b/tests/unit/services/command.task-origins.test.ts @@ -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(` diff --git a/tests/unit/services/command.test.ts b/tests/unit/services/command.test.ts index 67e6a36..52d452b 100644 --- a/tests/unit/services/command.test.ts +++ b/tests/unit/services/command.test.ts @@ -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', () => { diff --git a/tests/unit/services/command.web-login.test.ts b/tests/unit/services/command.web-login.test.ts index 3b03f0d..9c0b490 100644 --- a/tests/unit/services/command.web-login.test.ts +++ b/tests/unit/services/command.web-login.test.ts @@ -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(() => { diff --git a/tests/unit/services/group-sync.coverage.test.ts b/tests/unit/services/group-sync.coverage.test.ts index 2629676..59e9b10 100644 --- a/tests/unit/services/group-sync.coverage.test.ts +++ b/tests/unit/services/group-sync.coverage.test.ts @@ -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)`) diff --git a/tests/unit/services/group-sync.gating.test.ts b/tests/unit/services/group-sync.gating.test.ts index 156e9a0..7a3db7f 100644 --- a/tests/unit/services/group-sync.gating.test.ts +++ b/tests/unit/services/group-sync.gating.test.ts @@ -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) => { diff --git a/tests/unit/services/group-sync.label-update.test.ts b/tests/unit/services/group-sync.label-update.test.ts index 308be45..c6e4d75 100644 --- a/tests/unit/services/group-sync.label-update.test.ts +++ b/tests/unit/services/group-sync.label-update.test.ts @@ -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; }); diff --git a/tests/unit/services/group-sync.members.test.ts b/tests/unit/services/group-sync.members.test.ts index aee35db..edfc75b 100644 --- a/tests/unit/services/group-sync.members.test.ts +++ b/tests/unit/services/group-sync.members.test.ts @@ -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(); }); diff --git a/tests/unit/services/group-sync.onboarding.test.ts b/tests/unit/services/group-sync.onboarding.test.ts index 4b38a5b..ec1f741 100644 --- a/tests/unit/services/group-sync.onboarding.test.ts +++ b/tests/unit/services/group-sync.onboarding.test.ts @@ -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; }); diff --git a/tests/unit/services/group-sync.scheduler.test.ts b/tests/unit/services/group-sync.scheduler.test.ts index 76619ae..bd28410 100644 --- a/tests/unit/services/group-sync.scheduler.test.ts +++ b/tests/unit/services/group-sync.scheduler.test.ts @@ -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 {} }); }); diff --git a/tests/unit/services/group-sync.sync-members.test.ts b/tests/unit/services/group-sync.sync-members.test.ts index d2b6797..e597eaf 100644 --- a/tests/unit/services/group-sync.sync-members.test.ts +++ b/tests/unit/services/group-sync.sync-members.test.ts @@ -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(); }); diff --git a/tests/unit/services/group-sync.test.ts b/tests/unit/services/group-sync.test.ts index 1e7f7e6..82ad62c 100644 --- a/tests/unit/services/group-sync.test.ts +++ b/tests/unit/services/group-sync.test.ts @@ -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'); diff --git a/tests/unit/services/identity-alias.e2e.test.ts b/tests/unit/services/identity-alias.e2e.test.ts index 60d3432..be063c9 100644 --- a/tests/unit/services/identity-alias.e2e.test.ts +++ b/tests/unit/services/identity-alias.e2e.test.ts @@ -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(); }); diff --git a/tests/unit/services/metrics-health.test.ts b/tests/unit/services/metrics-health.test.ts index 97425b7..440d181 100644 --- a/tests/unit/services/metrics-health.test.ts +++ b/tests/unit/services/metrics-health.test.ts @@ -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 () => { diff --git a/tests/unit/services/reminders.gating.test.ts b/tests/unit/services/reminders.gating.test.ts index dbe2c04..f1fccb8 100644 --- a/tests/unit/services/reminders.gating.test.ts +++ b/tests/unit/services/reminders.gating.test.ts @@ -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; diff --git a/tests/unit/services/reminders.test.ts b/tests/unit/services/reminders.test.ts index 0ee028d..8a6a06b 100644 --- a/tests/unit/services/reminders.test.ts +++ b/tests/unit/services/reminders.test.ts @@ -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;`); diff --git a/tests/unit/services/response-queue.cleanup.test.ts b/tests/unit/services/response-queue.cleanup.test.ts index faa088f..800c52c 100644 --- a/tests/unit/services/response-queue.cleanup.test.ts +++ b/tests/unit/services/response-queue.cleanup.test.ts @@ -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(); }); diff --git a/tests/unit/services/response-queue.reactions.test.ts b/tests/unit/services/response-queue.reactions.test.ts index 1729344..e4b23c8 100644 --- a/tests/unit/services/response-queue.reactions.test.ts +++ b/tests/unit/services/response-queue.reactions.test.ts @@ -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 () => { diff --git a/tests/unit/services/response-queue.test.ts b/tests/unit/services/response-queue.test.ts index 69f2787..7641494 100644 --- a/tests/unit/services/response-queue.test.ts +++ b/tests/unit/services/response-queue.test.ts @@ -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(); }); diff --git a/tests/unit/tasks/claim-unassign.test.ts b/tests/unit/tasks/claim-unassign.test.ts index 7ba67a4..8c1eb94 100644 --- a/tests/unit/tasks/claim-unassign.test.ts +++ b/tests/unit/tasks/claim-unassign.test.ts @@ -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(() => { diff --git a/tests/unit/tasks/service.test.ts b/tests/unit/tasks/service.test.ts index 71706b5..8237a88 100644 --- a/tests/unit/tasks/service.test.ts +++ b/tests/unit/tasks/service.test.ts @@ -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 {} });