import { describe, it, expect, beforeEach, vi } from 'vitest'; import { todoManager } from '../../../../src/tools/todo/todo-manager.js'; import type { SessionManager } from '../../../../src/session/index.js'; import type { Todo } from '../../../../src/session/types.js'; describe('TodoManager', () => { let mockSessionManager: SessionManager; let mockTodos: Todo[]; beforeEach(() => { mockTodos = []; mockSessionManager = { getTodos: vi.fn(() => mockTodos), setTodos: vi.fn(async (todos: Todo[]) => { mockTodos = todos; }), } as unknown as SessionManager; // 重置 todoManager 状态 todoManager.setSessionManager(mockSessionManager); }); describe('setSessionManager', () => { it('设置会话管理器后 isInitialized 返回 true', () => { const freshManager = { getTodos: vi.fn(() => []), setTodos: vi.fn(), } as unknown as SessionManager; todoManager.setSessionManager(freshManager); expect(todoManager.isInitialized()).toBe(true); }); }); describe('getTodos', () => { it('返回空数组当没有 todo', () => { const todos = todoManager.getTodos(); expect(todos).toEqual([]); }); it('返回现有的 todo 列表', () => { mockTodos = [ { id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' }, { id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' }, ]; const todos = todoManager.getTodos(); expect(todos).toHaveLength(2); expect(todos[0].content).toBe('Task 1'); expect(todos[1].content).toBe('Task 2'); }); it('正确调用 sessionManager.getTodos', () => { todoManager.getTodos(); expect(mockSessionManager.getTodos).toHaveBeenCalled(); }); }); describe('setTodos', () => { it('更新 todo 列表', async () => { const newTodos: Todo[] = [ { id: '1', content: 'New Task', status: 'pending', createdAt: '', updatedAt: '' }, ]; await todoManager.setTodos(newTodos); expect(mockSessionManager.setTodos).toHaveBeenCalledWith(newTodos); expect(mockTodos).toHaveLength(1); }); it('可以设置空列表', async () => { mockTodos = [ { id: '1', content: 'Task', status: 'pending', createdAt: '', updatedAt: '' }, ]; await todoManager.setTodos([]); expect(mockTodos).toHaveLength(0); }); }); describe('addTodo', () => { it('添加新的 todo(默认状态 pending)', async () => { const todo = await todoManager.addTodo('新任务'); expect(todo.content).toBe('新任务'); expect(todo.status).toBe('pending'); expect(todo.id).toBeDefined(); expect(todo.createdAt).toBeDefined(); expect(todo.updatedAt).toBeDefined(); expect(mockTodos).toHaveLength(1); }); it('添加指定状态的 todo', async () => { const todo = await todoManager.addTodo('进行中的任务', 'in_progress'); expect(todo.content).toBe('进行中的任务'); expect(todo.status).toBe('in_progress'); }); it('添加已完成状态的 todo', async () => { const todo = await todoManager.addTodo('已完成任务', 'completed'); expect(todo.status).toBe('completed'); }); it('生成唯一 ID', async () => { const todo1 = await todoManager.addTodo('Task 1'); const todo2 = await todoManager.addTodo('Task 2'); expect(todo1.id).not.toBe(todo2.id); }); it('追加到现有列表', async () => { mockTodos = [ { id: 'existing', content: 'Existing', status: 'pending', createdAt: '', updatedAt: '' }, ]; await todoManager.addTodo('New Task'); expect(mockTodos).toHaveLength(2); expect(mockTodos[0].content).toBe('Existing'); expect(mockTodos[1].content).toBe('New Task'); }); }); describe('updateTodoStatus', () => { beforeEach(() => { mockTodos = [ { id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' }, { id: 'todo-2', content: 'Task 2', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' }, ]; }); it('更新存在的 todo 状态', async () => { const result = await todoManager.updateTodoStatus('todo-1', 'completed'); expect(result).toBe(true); expect(mockTodos[0].status).toBe('completed'); }); it('更新 updatedAt 时间戳', async () => { const originalUpdatedAt = mockTodos[0].updatedAt; await todoManager.updateTodoStatus('todo-1', 'in_progress'); expect(mockTodos[0].updatedAt).not.toBe(originalUpdatedAt); }); it('不存在的 todo 返回 false', async () => { const result = await todoManager.updateTodoStatus('non-existent', 'completed'); expect(result).toBe(false); }); it('可以更新为任意状态', async () => { await todoManager.updateTodoStatus('todo-1', 'in_progress'); expect(mockTodos[0].status).toBe('in_progress'); await todoManager.updateTodoStatus('todo-1', 'completed'); expect(mockTodos[0].status).toBe('completed'); await todoManager.updateTodoStatus('todo-1', 'pending'); expect(mockTodos[0].status).toBe('pending'); }); }); describe('deleteTodo', () => { beforeEach(() => { mockTodos = [ { id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' }, { id: 'todo-2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' }, { id: 'todo-3', content: 'Task 3', status: 'in_progress', createdAt: '', updatedAt: '' }, ]; }); it('删除存在的 todo', async () => { const result = await todoManager.deleteTodo('todo-2'); expect(result).toBe(true); expect(mockTodos).toHaveLength(2); expect(mockTodos.find(t => t.id === 'todo-2')).toBeUndefined(); }); it('删除第一个 todo', async () => { const result = await todoManager.deleteTodo('todo-1'); expect(result).toBe(true); expect(mockTodos[0].id).toBe('todo-2'); }); it('删除最后一个 todo', async () => { const result = await todoManager.deleteTodo('todo-3'); expect(result).toBe(true); expect(mockTodos).toHaveLength(2); }); it('不存在的 todo 返回 false', async () => { const result = await todoManager.deleteTodo('non-existent'); expect(result).toBe(false); expect(mockTodos).toHaveLength(3); }); it('删除后其他 todo 保持不变', async () => { await todoManager.deleteTodo('todo-2'); expect(mockTodos[0].content).toBe('Task 1'); expect(mockTodos[1].content).toBe('Task 3'); }); }); describe('clearTodos', () => { it('清空所有 todo', async () => { mockTodos = [ { id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' }, { id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' }, ]; await todoManager.clearTodos(); expect(mockTodos).toHaveLength(0); expect(mockSessionManager.setTodos).toHaveBeenCalledWith([]); }); it('空列表时调用也不报错', async () => { mockTodos = []; await expect(todoManager.clearTodos()).resolves.not.toThrow(); expect(mockTodos).toHaveLength(0); }); }); describe('isInitialized', () => { it('初始化后返回 true', () => { expect(todoManager.isInitialized()).toBe(true); }); }); describe('边界情况', () => { it('处理包含特殊字符的 content', async () => { const specialContent = '任务: "测试" & '; const todo = await todoManager.addTodo(specialContent); expect(todo.content).toBe(specialContent); }); it('处理非常长的 content', async () => { const longContent = 'A'.repeat(10000); const todo = await todoManager.addTodo(longContent); expect(todo.content).toBe(longContent); }); it('处理空字符串 content', async () => { const todo = await todoManager.addTodo(''); expect(todo.content).toBe(''); }); it('连续操作保持数据一致性', async () => { await todoManager.addTodo('Task 1'); await todoManager.addTodo('Task 2'); await todoManager.updateTodoStatus(mockTodos[0].id, 'completed'); await todoManager.deleteTodo(mockTodos[1].id); await todoManager.addTodo('Task 3'); expect(mockTodos).toHaveLength(2); expect(mockTodos[0].status).toBe('completed'); expect(mockTodos[1].content).toBe('Task 3'); }); }); });