feat: añadir TaskService con dbInstance y tests unitarios
Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>pull/1/head
parent
94f6813cb2
commit
7b9928937b
@ -0,0 +1,170 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
||||
import Database from 'better-sqlite3';
|
||||
import { initializeDatabase, ensureUserExists } from '../../../src/db';
|
||||
import { TaskService } from '../../../src/tasks/service';
|
||||
|
||||
let memDb: Database;
|
||||
|
||||
beforeEach(() => {
|
||||
memDb = new Database(':memory:');
|
||||
initializeDatabase(memDb);
|
||||
TaskService.dbInstance = memDb;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
try {
|
||||
memDb.close();
|
||||
} catch {}
|
||||
});
|
||||
|
||||
describe('TaskService.createTask', () => {
|
||||
it('crea una tarea mínima con created_by y sin due_date ni group_id', () => {
|
||||
const creatorRaw = '555111222@s.whatsapp.net';
|
||||
const createdBy = ensureUserExists(creatorRaw, memDb);
|
||||
expect(createdBy).toBeTruthy();
|
||||
|
||||
const id = TaskService.createTask(
|
||||
{
|
||||
description: 'Comprar agua',
|
||||
created_by: createdBy!,
|
||||
due_date: null,
|
||||
group_id: null,
|
||||
},
|
||||
[] // sin asignaciones
|
||||
);
|
||||
|
||||
expect(typeof id).toBe('number');
|
||||
|
||||
const task = memDb
|
||||
.prepare(
|
||||
`SELECT id, description, due_date, group_id, created_by, completed
|
||||
FROM tasks WHERE id = ?`
|
||||
)
|
||||
.get(id) as any;
|
||||
|
||||
expect(task).toBeTruthy();
|
||||
expect(task.description).toBe('Comprar agua');
|
||||
expect(task.due_date).toBeNull();
|
||||
expect(task.group_id).toBeNull();
|
||||
expect(task.created_by).toBe(createdBy);
|
||||
expect(task.completed).toBe(0); // BOOLEAN en SQLite como 0/1
|
||||
});
|
||||
|
||||
it('guarda due_date como cadena YYYY-MM-DD y group_id como JID completo', () => {
|
||||
const creatorRaw = '555333444@s.whatsapp.net';
|
||||
const createdBy = ensureUserExists(creatorRaw, memDb)!;
|
||||
|
||||
const due = '2025-09-10';
|
||||
const groupId = '12345@g.us';
|
||||
|
||||
const id = TaskService.createTask(
|
||||
{
|
||||
description: 'Pagar servicios',
|
||||
created_by: createdBy,
|
||||
due_date: due,
|
||||
group_id: groupId,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const row = memDb
|
||||
.prepare(
|
||||
`SELECT description, due_date, group_id, created_by
|
||||
FROM tasks WHERE id = ?`
|
||||
)
|
||||
.get(id) as any;
|
||||
|
||||
expect(row.due_date).toBe(due);
|
||||
expect(row.group_id).toBe(groupId);
|
||||
expect(row.created_by).toBe(createdBy);
|
||||
});
|
||||
|
||||
it('inserta asignaciones y evita duplicados por usuario', () => {
|
||||
const creator = ensureUserExists('555000001@s.whatsapp.net', memDb)!;
|
||||
const assigneeA = ensureUserExists('555000002@s.whatsapp.net', memDb)!;
|
||||
const assigneeB = ensureUserExists('555000003@s.whatsapp.net', memDb)!;
|
||||
|
||||
const id = TaskService.createTask(
|
||||
{
|
||||
description: 'Organizar reunión',
|
||||
created_by: creator,
|
||||
due_date: null,
|
||||
group_id: null,
|
||||
},
|
||||
[
|
||||
{ user_id: assigneeA, assigned_by: creator },
|
||||
{ user_id: assigneeA, assigned_by: creator }, // duplicado
|
||||
{ user_id: assigneeB, assigned_by: creator },
|
||||
]
|
||||
);
|
||||
|
||||
const count = memDb
|
||||
.prepare(
|
||||
`SELECT COUNT(*) AS c FROM task_assignments WHERE task_id = ?`
|
||||
)
|
||||
.get(id) as any;
|
||||
|
||||
expect(count.c).toBe(2);
|
||||
|
||||
const users = memDb
|
||||
.prepare(
|
||||
`SELECT user_id FROM task_assignments WHERE task_id = ? ORDER BY user_id`
|
||||
)
|
||||
.all(id) as any[];
|
||||
|
||||
expect(users.map(u => u.user_id)).toEqual([assigneeA, assigneeB].sort());
|
||||
});
|
||||
|
||||
it('hace rollback si una asignación viola FK (usuario inexistente)', () => {
|
||||
const creator = ensureUserExists('555010101@s.whatsapp.net', memDb)!;
|
||||
|
||||
expect(() =>
|
||||
TaskService.createTask(
|
||||
{
|
||||
description: 'Tarea con fallo',
|
||||
created_by: creator,
|
||||
due_date: null,
|
||||
group_id: null,
|
||||
},
|
||||
[
|
||||
// Usuario no existente: no llamamos ensureUserExists
|
||||
{ user_id: '555099999', assigned_by: creator },
|
||||
]
|
||||
)
|
||||
).toThrow();
|
||||
|
||||
const counts = memDb
|
||||
.prepare(
|
||||
`SELECT
|
||||
(SELECT COUNT(*) FROM tasks) AS tasks_count,
|
||||
(SELECT COUNT(*) FROM task_assignments) AS assigns_count`
|
||||
)
|
||||
.get() as any;
|
||||
|
||||
expect(counts.tasks_count).toBe(0);
|
||||
expect(counts.assigns_count).toBe(0);
|
||||
});
|
||||
|
||||
it('lanza error si created_by no existe (FK) y no inserta la tarea', () => {
|
||||
// No llamamos a ensureUserExists para este created_by
|
||||
const nonExisting = '555123123';
|
||||
|
||||
expect(() =>
|
||||
TaskService.createTask(
|
||||
{
|
||||
description: 'No debería insertarse',
|
||||
created_by: nonExisting,
|
||||
due_date: null,
|
||||
group_id: null,
|
||||
},
|
||||
[]
|
||||
)
|
||||
).toThrow();
|
||||
|
||||
const count = memDb
|
||||
.prepare(`SELECT COUNT(*) AS c FROM tasks`)
|
||||
.get() as any;
|
||||
|
||||
expect(count.c).toBe(0);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue