import { describe, it, expect, beforeEach, vi } from 'vitest'; // 使用可变的引用对象来绕过 hoisting 问题 const mockState = { isInitialized: vi.fn().mockReturnValue(true), getTodos: vi.fn().mockReturnValue([]), setTodos: vi.fn().mockResolvedValue(undefined), }; vi.mock('../../../../src/tools/todo/todo-manager.js', () => ({ todoManager: { isInitialized: () => mockState.isInitialized(), getTodos: () => mockState.getTodos(), setTodos: (todos: any) => mockState.setTodos(todos), }, })); import { todoWriteTool } from '../../../../src/tools/todo/todowrite.js'; describe('todoWriteTool - Todo 写入工具', () => { beforeEach(() => { vi.clearAllMocks(); mockState.isInitialized.mockReturnValue(true); mockState.getTodos.mockReturnValue([]); }); describe('工具定义', () => { it('有正确的名称', () => { expect(todoWriteTool.name).toBe('todowrite'); }); it('有正确的元数据', () => { expect(todoWriteTool.metadata.category).toBe('core'); expect(todoWriteTool.metadata.keywords).toContain('todo'); expect(todoWriteTool.metadata.keywords).toContain('task'); expect(todoWriteTool.metadata.keywords).toContain('write'); }); it('定义了必需的 todos 参数', () => { expect(todoWriteTool.parameters.todos.required).toBe(true); }); }); describe('execute - 执行', () => { it('成功创建待办列表', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '任务1', status: 'pending' }, { content: '任务2', status: 'in_progress' }, ], }); expect(result.success).toBe(true); expect(result.output).toContain('待办事项已更新'); expect(mockState.setTodos).toHaveBeenCalled(); }); it('返回正确的统计信息', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '任务1', status: 'pending' }, { content: '任务2', status: 'in_progress' }, { content: '任务3', status: 'completed' }, ], }); expect(result.success).toBe(true); // pendingCount 包含所有非 completed 状态的任务(pending + in_progress) expect(result.metadata?.pendingCount).toBe(2); expect(result.metadata?.inProgressCount).toBe(1); expect(result.metadata?.completedCount).toBe(1); }); it('更新现有任务', async () => { mockState.getTodos.mockReturnValue([ { id: 'existing-1', content: '任务1', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' }, ]); const result = await todoWriteTool.execute({ todos: [ { content: '任务1', status: 'completed' }, ], }); expect(result.success).toBe(true); const savedTodos = mockState.setTodos.mock.calls[0][0]; expect(savedTodos[0].id).toBe('existing-1'); // 保留原有 ID expect(savedTodos[0].status).toBe('completed'); }); it('未初始化时返回错误', async () => { mockState.isInitialized.mockReturnValue(false); const result = await todoWriteTool.execute({ todos: [{ content: '任务', status: 'pending' }], }); expect(result.success).toBe(false); expect(result.error).toContain('会话管理器未初始化'); }); it('todos 非数组返回错误', async () => { const result = await todoWriteTool.execute({ todos: 'not an array', }); expect(result.success).toBe(false); expect(result.error).toContain('todos 参数必须是数组'); }); it('无效的待办项格式返回错误', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '有效任务', status: 'pending' }, { content: '', status: 'pending' }, // 空内容 ], }); expect(result.success).toBe(false); expect(result.error).toContain('第 2 个待办事项格式无效'); }); it('无效的状态值返回错误', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '任务', status: 'invalid_status' }, ], }); expect(result.success).toBe(false); expect(result.error).toContain('格式无效'); }); it('缺少 content 返回错误', async () => { const result = await todoWriteTool.execute({ todos: [ { status: 'pending' }, ], }); expect(result.success).toBe(false); expect(result.error).toContain('格式无效'); }); it('为新任务生成 ID', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '新任务', status: 'pending' }, ], }); expect(result.success).toBe(true); const savedTodos = mockState.setTodos.mock.calls[0][0]; expect(savedTodos[0].id).toBeDefined(); expect(savedTodos[0].id.length).toBeGreaterThan(0); }); it('设置创建和更新时间', async () => { const result = await todoWriteTool.execute({ todos: [ { content: '新任务', status: 'pending' }, ], }); expect(result.success).toBe(true); const savedTodos = mockState.setTodos.mock.calls[0][0]; expect(savedTodos[0].createdAt).toBeDefined(); expect(savedTodos[0].updatedAt).toBeDefined(); }); }); });