1- import { describe , it , expect } from "vitest" ;
2- import { createTaskTools } from "./task_tools" ;
1+ import { describe , it , expect , vi } from "vitest" ;
2+ import { createTaskTools , type Task } from "./task_tools" ;
33
44describe ( "task_tools" , ( ) => {
5- it ( "should create 5 tools " , ( ) => {
5+ it ( "应创建 3 个工具 " , ( ) => {
66 const { tools } = createTaskTools ( ) ;
7- expect ( tools ) . toHaveLength ( 5 ) ;
7+ expect ( tools ) . toHaveLength ( 3 ) ;
88 const names = tools . map ( ( t ) => t . definition . name ) ;
9- expect ( names ) . toEqual ( [ "create_task" , "get_task" , " update_task", "list_tasks" , "delete_task "] ) ;
9+ expect ( names ) . toEqual ( [ "create_task" , "update_task" , "list_tasks" ] ) ;
1010 } ) ;
1111
12- it ( "create_task should create a task with auto-incremented ID " , async ( ) => {
12+ it ( "create_task 应创建自增 ID 的任务 " , async ( ) => {
1313 const { tools } = createTaskTools ( ) ;
1414 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
1515
@@ -22,19 +22,7 @@ describe("task_tools", () => {
2222 expect ( result2 ) . toEqual ( { id : "2" , subject : "Task 2" , description : "Details" , status : "pending" } ) ;
2323 } ) ;
2424
25- it ( "get_task should return task or throw" , async ( ) => {
26- const { tools } = createTaskTools ( ) ;
27- const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
28- const get = tools . find ( ( t ) => t . definition . name === "get_task" ) ! ;
29-
30- await create . executor . execute ( { subject : "Test" } ) ;
31- const result = JSON . parse ( ( await get . executor . execute ( { task_id : "1" } ) ) as string ) ;
32- expect ( result . subject ) . toBe ( "Test" ) ;
33-
34- await expect ( get . executor . execute ( { task_id : "999" } ) ) . rejects . toThrow ( 'Task "999" not found' ) ;
35- } ) ;
36-
37- it ( "update_task should update fields" , async ( ) => {
25+ it ( "update_task 应更新任务字段" , async ( ) => {
3826 const { tools } = createTaskTools ( ) ;
3927 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
4028 const update = tools . find ( ( t ) => t . definition . name === "update_task" ) ! ;
@@ -48,13 +36,13 @@ describe("task_tools", () => {
4836 expect ( result . subject ) . toBe ( "Updated" ) ;
4937 } ) ;
5038
51- it ( "update_task should throw for non-existent task " , async ( ) => {
39+ it ( "update_task 应对不存在的任务抛错 " , async ( ) => {
5240 const { tools } = createTaskTools ( ) ;
5341 const update = tools . find ( ( t ) => t . definition . name === "update_task" ) ! ;
5442 await expect ( update . executor . execute ( { task_id : "1" } ) ) . rejects . toThrow ( ) ;
5543 } ) ;
5644
57- it ( "list_tasks should return all tasks summary " , async ( ) => {
45+ it ( "list_tasks 应返回所有任务摘要 " , async ( ) => {
5846 const { tools } = createTaskTools ( ) ;
5947 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
6048 const list = tools . find ( ( t ) => t . definition . name === "list_tasks" ) ! ;
@@ -68,65 +56,83 @@ describe("task_tools", () => {
6856 expect ( result [ 1 ] ) . toEqual ( { id : "2" , subject : "B" , status : "pending" } ) ;
6957 } ) ;
7058
71- it ( "list_tasks should return empty array initially " , async ( ) => {
59+ it ( "list_tasks 初始应返回空数组 " , async ( ) => {
7260 const { tools } = createTaskTools ( ) ;
7361 const list = tools . find ( ( t ) => t . definition . name === "list_tasks" ) ! ;
7462 const result = JSON . parse ( ( await list . executor . execute ( { } ) ) as string ) ;
7563 expect ( result ) . toEqual ( [ ] ) ;
7664 } ) ;
7765
78- it ( "update_task should allow clearing description with empty string" , async ( ) => {
79- const { tools } = createTaskTools ( ) ;
66+ it ( "应从 initialTasks 恢复任务并继续递增 ID" , async ( ) => {
67+ const initial : Task [ ] = [
68+ { id : "3" , subject : "Existing" , status : "in_progress" } ,
69+ { id : "5" , subject : "Another" , status : "pending" } ,
70+ ] ;
71+ const { tools } = createTaskTools ( { initialTasks : initial } ) ;
8072 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
81- const update = tools . find ( ( t ) => t . definition . name === "update_task " ) ! ;
73+ const list = tools . find ( ( t ) => t . definition . name === "list_tasks " ) ! ;
8274
83- await create . executor . execute ( { subject : "Test" , description : "Some desc" } ) ;
75+ // 新任务 ID 应从 6 开始(max existing ID 5 + 1)
76+ const result = JSON . parse ( ( await create . executor . execute ( { subject : "New" } ) ) as string ) ;
77+ expect ( result . id ) . toBe ( "6" ) ;
8478
85- const result = JSON . parse ( ( await update . executor . execute ( { task_id : "1" , description : "" } ) ) as string ) ;
86- expect ( result . description ) . toBe ( "" ) ;
79+ const all = JSON . parse ( ( await list . executor . execute ( { } ) ) as string ) ;
80+ expect ( all ) . toHaveLength ( 3 ) ;
8781 } ) ;
8882
89- it ( "update_task with only task_id should not change anything" , async ( ) => {
90- const { tools } = createTaskTools ( ) ;
83+ it ( "create_task 应调用 onSave 和 sendEvent" , async ( ) => {
84+ const onSave = vi . fn ( ) . mockResolvedValue ( undefined ) ;
85+ const sendEvent = vi . fn ( ) ;
86+ const { tools } = createTaskTools ( { onSave, sendEvent } ) ;
9187 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
92- const update = tools . find ( ( t ) => t . definition . name === "update_task" ) ! ;
9388
94- await create . executor . execute ( { subject : "Original" , description : "Desc" } ) ;
95-
96- const result = JSON . parse ( ( await update . executor . execute ( { task_id : "1" } ) ) as string ) ;
97- expect ( result . subject ) . toBe ( "Original" ) ;
98- expect ( result . description ) . toBe ( "Desc" ) ;
99- expect ( result . status ) . toBe ( "pending" ) ;
100- } ) ;
89+ await create . executor . execute ( { subject : "Test" } ) ;
10190
102- it ( "create_task without description should not include it in result" , async ( ) => {
103- const { tools } = createTaskTools ( ) ;
104- const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
91+ expect ( onSave ) . toHaveBeenCalledOnce ( ) ;
92+ expect ( onSave ) . toHaveBeenCalledWith ( [ { id : "1" , subject : "Test" , status : "pending" } ] ) ;
10593
106- const result = JSON . parse ( ( await create . executor . execute ( { subject : "No desc" } ) ) as string ) ;
107- expect ( result . description ) . toBeUndefined ( ) ;
94+ expect ( sendEvent ) . toHaveBeenCalledOnce ( ) ;
95+ expect ( sendEvent ) . toHaveBeenCalledWith ( {
96+ type : "task_update" ,
97+ tasks : [ { id : "1" , subject : "Test" , status : "pending" } ] ,
98+ } ) ;
10899 } ) ;
109100
110- it ( "delete_task should remove a task" , async ( ) => {
111- const { tools, tasks } = createTaskTools ( ) ;
101+ it ( "update_task 应调用 onSave 和 sendEvent" , async ( ) => {
102+ const onSave = vi . fn ( ) . mockResolvedValue ( undefined ) ;
103+ const sendEvent = vi . fn ( ) ;
104+ const { tools } = createTaskTools ( { onSave, sendEvent } ) ;
112105 const create = tools . find ( ( t ) => t . definition . name === "create_task" ) ! ;
113- const del = tools . find ( ( t ) => t . definition . name === "delete_task " ) ! ;
106+ const update = tools . find ( ( t ) => t . definition . name === "update_task " ) ! ;
114107
115- await create . executor . execute ( { subject : "To delete" } ) ;
116- expect ( tasks . size ) . toBe ( 1 ) ;
108+ await create . executor . execute ( { subject : "Task" } ) ;
109+ onSave . mockClear ( ) ;
110+ sendEvent . mockClear ( ) ;
117111
118- const result = JSON . parse ( ( await del . executor . execute ( { task_id : "1" } ) ) as string ) ;
119- expect ( result ) . toEqual ( { deleted : "1" } ) ;
120- expect ( tasks . size ) . toBe ( 0 ) ;
112+ await update . executor . execute ( { task_id : "1" , status : "completed" } ) ;
113+
114+ expect ( onSave ) . toHaveBeenCalledOnce ( ) ;
115+ expect ( sendEvent ) . toHaveBeenCalledOnce ( ) ;
116+ expect ( sendEvent ) . toHaveBeenCalledWith ( {
117+ type : "task_update" ,
118+ tasks : [ { id : "1" , subject : "Task" , status : "completed" } ] ,
119+ } ) ;
121120 } ) ;
122121
123- it ( "delete_task should throw for non-existent task" , async ( ) => {
124- const { tools } = createTaskTools ( ) ;
125- const del = tools . find ( ( t ) => t . definition . name === "delete_task" ) ! ;
126- await expect ( del . executor . execute ( { task_id : "999" } ) ) . rejects . toThrow ( 'Task "999" not found' ) ;
122+ it ( "list_tasks 不应触发 onSave 或 sendEvent" , async ( ) => {
123+ const onSave = vi . fn ( ) . mockResolvedValue ( undefined ) ;
124+ const sendEvent = vi . fn ( ) ;
125+ const initial : Task [ ] = [ { id : "1" , subject : "Existing" , status : "pending" } ] ;
126+ const { tools } = createTaskTools ( { initialTasks : initial , onSave, sendEvent } ) ;
127+ const list = tools . find ( ( t ) => t . definition . name === "list_tasks" ) ! ;
128+
129+ await list . executor . execute ( { } ) ;
130+
131+ expect ( onSave ) . not . toHaveBeenCalled ( ) ;
132+ expect ( sendEvent ) . not . toHaveBeenCalled ( ) ;
127133 } ) ;
128134
129- it ( "tasks map should be independent per createTaskTools call " , async ( ) => {
135+ it ( "多实例应独立 " , async ( ) => {
130136 const instance1 = createTaskTools ( ) ;
131137 const instance2 = createTaskTools ( ) ;
132138
0 commit comments