You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			93 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			93 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
| 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';
 | |
| 
 | |
| describe('TaskService - claim/unassign', () => {
 | |
|   let memdb: Database;
 | |
| 
 | |
|   beforeAll(() => {
 | |
|     memdb = new Database(':memory:');
 | |
|     initializeDatabase(memdb);
 | |
|     TaskService.dbInstance = memdb;
 | |
|   });
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     memdb.exec(`
 | |
|       DELETE FROM task_assignments;
 | |
|       DELETE FROM tasks;
 | |
|       DELETE FROM users;
 | |
|     `);
 | |
|   });
 | |
| 
 | |
|   function createTask(description: string, createdBy: string, due?: string | null, assignees: string[] = []): number {
 | |
|     const creator = ensureUserExists(createdBy, memdb)!;
 | |
|     const taskId = TaskService.createTask(
 | |
|       {
 | |
|         description,
 | |
|         due_date: due ?? null,
 | |
|         group_id: null,
 | |
|         created_by: creator,
 | |
|       },
 | |
|       assignees.map(uid => ({ user_id: ensureUserExists(uid, memdb)!, assigned_by: creator }))
 | |
|     );
 | |
|     return taskId;
 | |
|   }
 | |
| 
 | |
|   it('claim: happy path then idempotent', () => {
 | |
|     const taskId = createTask('Probar claim', '111', '2025-09-12');
 | |
|     const res1 = TaskService.claimTask(taskId, '222');
 | |
|     expect(res1.status).toBe('claimed');
 | |
|     expect(res1.task?.id).toBe(taskId);
 | |
| 
 | |
|     const res2 = TaskService.claimTask(taskId, '222');
 | |
|     expect(res2.status).toBe('already');
 | |
|     expect(res2.task?.id).toBe(taskId);
 | |
|   });
 | |
| 
 | |
|   it('claim: not_found', () => {
 | |
|     const res = TaskService.claimTask(999999, '111');
 | |
|     expect(res.status).toBe('not_found');
 | |
|   });
 | |
| 
 | |
|   it('claim: completed', () => {
 | |
|     const taskId = createTask('Tarea ya completada', '111', '2025-10-10');
 | |
|     // marcar como completada
 | |
|     const comp = TaskService.completeTask(taskId, '111');
 | |
|     expect(comp.status).toBe('updated');
 | |
| 
 | |
|     const res = TaskService.claimTask(taskId, '222');
 | |
|     expect(res.status).toBe('completed');
 | |
|     expect(res.task?.id).toBe(taskId);
 | |
|   });
 | |
| 
 | |
|   it('unassign: happy path; luego not_assigned; now_unassigned=true', () => {
 | |
|     const taskId = createTask('Soltar luego de asignar', '111', '2025-09-20', ['222']);
 | |
|     // soltar por el mismo usuario
 | |
|     const res1 = TaskService.unassignTask(taskId, '222');
 | |
|     expect(res1.status).toBe('unassigned');
 | |
|     expect(res1.task?.id).toBe(taskId);
 | |
|     expect(res1.now_unassigned).toBe(true);
 | |
| 
 | |
|     // idempotente si no estaba asignado
 | |
|     const res2 = TaskService.unassignTask(taskId, '222');
 | |
|     expect(res2.status).toBe('not_assigned');
 | |
|     expect(res2.now_unassigned).toBe(true);
 | |
|   });
 | |
| 
 | |
|   it('unassign: not_found', () => {
 | |
|     const res = TaskService.unassignTask(424242, '111');
 | |
|     expect(res.status).toBe('not_found');
 | |
|   });
 | |
| 
 | |
|   it('unassign: completed', () => {
 | |
|     const taskId = createTask('Unassign bloqueada por completada', '111', null, ['222']);
 | |
|     const comp = TaskService.completeTask(taskId, '111');
 | |
|     expect(comp.status).toBe('updated');
 | |
| 
 | |
|     const res = TaskService.unassignTask(taskId, '222');
 | |
|     expect(res.status).toBe('completed');
 | |
|     expect(res.task?.id).toBe(taskId);
 | |
|   });
 | |
| });
 |