diff --git a/tests/helpers/db.ts b/tests/helpers/db.ts new file mode 100644 index 0000000..a10b2ee --- /dev/null +++ b/tests/helpers/db.ts @@ -0,0 +1,49 @@ +import Database, { type Database as SqliteDatabase } from 'bun:sqlite'; +import { initializeDatabase } from '../../src/db'; + +// Servicios opcionales para inyección de DB en tests. +// Importamos con nombres existentes en la base de código para respetar convenciones. +import { TaskService } from '../../src/tasks/service'; +import { CommandService } from '../../src/services/command'; +import { ResponseQueue } from '../../src/services/response-queue'; +import { IdentityService } from '../../src/services/identity'; +import { GroupSyncService } from '../../src/services/group-sync'; +import { RemindersService } from '../../src/services/reminders'; + +/** + * Crea una DB en memoria y aplica initializeDatabase() con todas las migraciones. + */ +export function makeMemDb(): SqliteDatabase { + const memdb = new Database(':memory:'); + initializeDatabase(memdb); + return memdb; +} + +/** + * Inyecta la instancia de DB en los servicios que la exponen como propiedad estática. + * 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 {} +} + +/** + * Restablece estado global/cachés en servicios entre tests. + * Best-effort: solo llama si existen los métodos. + */ +export function resetServices(): void { + try { (IdentityService as any).clearCache?.(); } catch {} + try { (GroupSyncService as any).clearCaches?.(); } catch {} + try { (CommandService as any).resetForTests?.(); } catch {} + try { (ResponseQueue as any).resetForTests?.(); } catch {} + try { (RemindersService as any).resetForTests?.(); } catch {} +} + +/** + * Nota: en Etapa 1 añadiremos seedAllowed() aquí cuando exista AllowedGroups. + */ diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..8571b57 --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,7 @@ +/** + * Setup opcional para tests. Si el runner lo soporta (p. ej., bun test con --preload), + * fija el modo de gating por defecto a 'off' para no afectar suites existentes. + */ +if (!process.env.GROUP_GATING_MODE) { + process.env.GROUP_GATING_MODE = 'off'; +} diff --git a/tests/unit/db/migrations.smoke.test.ts b/tests/unit/db/migrations.smoke.test.ts new file mode 100644 index 0000000..28096fa --- /dev/null +++ b/tests/unit/db/migrations.smoke.test.ts @@ -0,0 +1,18 @@ +import { describe, it, expect } from 'bun:test'; +import Database from 'bun:sqlite'; +import { initializeDatabase } from '../../../src/db'; + +describe('DB migrations smoke', () => { + it('initializeDatabase en :memory: no lanza y crea tablas base', () => { + const memdb = new Database(':memory:'); + expect(() => initializeDatabase(memdb)).not.toThrow(); + + // Comprobar que al menos una tabla base existe (users, tasks o response_queue). + const rows = memdb + .query(`SELECT name FROM sqlite_master WHERE type='table' AND name IN ('users','tasks','response_queue')`) + .all() as Array<{ name: string }>; + + expect(Array.isArray(rows)).toBe(true); + expect(rows.length).toBeGreaterThan(0); + }); +});