@doist/todoist-ai 2.2.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -14
- package/dist/index.d.ts +619 -250
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -29
- package/dist/main.js +2 -1
- package/dist/mcp-helpers.d.ts +25 -3
- package/dist/mcp-helpers.d.ts.map +1 -1
- package/dist/mcp-helpers.js +37 -19
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +44 -28
- package/dist/tools/__tests__/add-comments.test.d.ts +2 -0
- package/dist/tools/__tests__/add-comments.test.d.ts.map +1 -0
- package/dist/tools/__tests__/add-comments.test.js +241 -0
- package/dist/tools/__tests__/add-projects.test.d.ts +2 -0
- package/dist/tools/__tests__/add-projects.test.d.ts.map +1 -0
- package/dist/tools/__tests__/add-projects.test.js +152 -0
- package/dist/tools/__tests__/add-sections.test.d.ts +2 -0
- package/dist/tools/__tests__/add-sections.test.d.ts.map +1 -0
- package/dist/tools/__tests__/add-sections.test.js +181 -0
- package/dist/tools/__tests__/add-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/add-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-add-multiple.test.js → add-tasks.test.js} +89 -79
- package/dist/tools/__tests__/complete-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/complete-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/complete-tasks.test.js +206 -0
- package/dist/tools/__tests__/delete-object.test.d.ts +2 -0
- package/dist/tools/__tests__/delete-object.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{delete-one.test.js → delete-object.test.js} +42 -22
- package/dist/tools/__tests__/find-comments.test.d.ts +2 -0
- package/dist/tools/__tests__/find-comments.test.d.ts.map +1 -0
- package/dist/tools/__tests__/find-comments.test.js +242 -0
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/find-completed-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-list-completed.test.js → find-completed-tasks.test.js} +13 -36
- package/dist/tools/__tests__/find-projects.test.d.ts +2 -0
- package/dist/tools/__tests__/find-projects.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{projects-list.test.js → find-projects.test.js} +55 -39
- package/dist/tools/__tests__/find-sections.test.d.ts +2 -0
- package/dist/tools/__tests__/find-sections.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{sections-search.test.js → find-sections.test.js} +64 -50
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts +2 -0
- package/dist/tools/__tests__/find-tasks-by-date.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{tasks-list-by-date.test.js → find-tasks-by-date.test.js} +96 -14
- package/dist/tools/__tests__/find-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/find-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/find-tasks.test.js +334 -0
- package/dist/tools/__tests__/get-overview.test.d.ts +2 -0
- package/dist/tools/__tests__/get-overview.test.d.ts.map +1 -0
- package/dist/tools/__tests__/{overview.test.js → get-overview.test.js} +77 -13
- package/dist/tools/__tests__/update-comments.test.d.ts +2 -0
- package/dist/tools/__tests__/update-comments.test.d.ts.map +1 -0
- package/dist/tools/__tests__/update-comments.test.js +296 -0
- package/dist/tools/__tests__/update-projects.test.d.ts +2 -0
- package/dist/tools/__tests__/update-projects.test.d.ts.map +1 -0
- package/dist/tools/__tests__/update-projects.test.js +205 -0
- package/dist/tools/__tests__/update-sections.test.d.ts +2 -0
- package/dist/tools/__tests__/update-sections.test.d.ts.map +1 -0
- package/dist/tools/__tests__/update-sections.test.js +156 -0
- package/dist/tools/__tests__/update-tasks.test.d.ts +2 -0
- package/dist/tools/__tests__/update-tasks.test.d.ts.map +1 -0
- package/dist/tools/__tests__/update-tasks.test.js +645 -0
- package/dist/tools/add-comments.d.ts +51 -0
- package/dist/tools/add-comments.d.ts.map +1 -0
- package/dist/tools/add-comments.js +79 -0
- package/dist/tools/add-projects.d.ts +50 -0
- package/dist/tools/add-projects.d.ts.map +1 -0
- package/dist/tools/add-projects.js +59 -0
- package/dist/tools/add-sections.d.ts +46 -0
- package/dist/tools/add-sections.d.ts.map +1 -0
- package/dist/tools/add-sections.js +61 -0
- package/dist/tools/add-tasks.d.ts +82 -0
- package/dist/tools/add-tasks.d.ts.map +1 -0
- package/dist/tools/add-tasks.js +96 -0
- package/dist/tools/complete-tasks.d.ts +40 -0
- package/dist/tools/complete-tasks.d.ts.map +1 -0
- package/dist/tools/complete-tasks.js +68 -0
- package/dist/tools/delete-object.d.ts +38 -0
- package/dist/tools/delete-object.d.ts.map +1 -0
- package/dist/tools/delete-object.js +79 -0
- package/dist/tools/find-comments.d.ts +46 -0
- package/dist/tools/find-comments.d.ts.map +1 -0
- package/dist/tools/find-comments.js +143 -0
- package/dist/tools/find-completed-tasks.d.ts +74 -0
- package/dist/tools/find-completed-tasks.d.ts.map +1 -0
- package/dist/tools/find-completed-tasks.js +112 -0
- package/dist/tools/find-projects.d.ts +53 -0
- package/dist/tools/find-projects.d.ts.map +1 -0
- package/dist/tools/find-projects.js +101 -0
- package/dist/tools/find-sections.d.ts +42 -0
- package/dist/tools/find-sections.d.ts.map +1 -0
- package/dist/tools/find-sections.js +96 -0
- package/dist/tools/find-tasks-by-date.d.ts +59 -0
- package/dist/tools/find-tasks-by-date.d.ts.map +1 -0
- package/dist/tools/find-tasks-by-date.js +121 -0
- package/dist/tools/find-tasks.d.ts +65 -0
- package/dist/tools/find-tasks.d.ts.map +1 -0
- package/dist/tools/find-tasks.js +182 -0
- package/dist/tools/get-overview.d.ts +67 -0
- package/dist/tools/get-overview.d.ts.map +1 -0
- package/dist/tools/{overview.js → get-overview.js} +66 -19
- package/dist/tools/update-comments.d.ts +50 -0
- package/dist/tools/update-comments.d.ts.map +1 -0
- package/dist/tools/update-comments.js +82 -0
- package/dist/tools/update-projects.d.ts +59 -0
- package/dist/tools/update-projects.d.ts.map +1 -0
- package/dist/tools/update-projects.js +84 -0
- package/dist/tools/update-sections.d.ts +47 -0
- package/dist/tools/update-sections.d.ts.map +1 -0
- package/dist/tools/update-sections.js +70 -0
- package/dist/tools/update-tasks.d.ts +94 -0
- package/dist/tools/update-tasks.d.ts.map +1 -0
- package/dist/tools/update-tasks.js +120 -0
- package/dist/utils/constants.d.ts +39 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +41 -0
- package/dist/utils/response-builders.d.ts +88 -0
- package/dist/utils/response-builders.d.ts.map +1 -0
- package/dist/utils/response-builders.js +202 -0
- package/dist/{tools → utils}/test-helpers.d.ts +16 -0
- package/dist/utils/test-helpers.d.ts.map +1 -0
- package/dist/{tools → utils}/test-helpers.js +51 -0
- package/dist/utils/tool-names.d.ts +28 -0
- package/dist/utils/tool-names.d.ts.map +1 -0
- package/dist/utils/tool-names.js +31 -0
- package/package.json +1 -1
- package/dist/tools/__tests__/delete-one.test.d.ts +0 -2
- package/dist/tools/__tests__/delete-one.test.d.ts.map +0 -1
- package/dist/tools/__tests__/overview.test.d.ts +0 -2
- package/dist/tools/__tests__/overview.test.d.ts.map +0 -1
- package/dist/tools/__tests__/projects-list.test.d.ts +0 -2
- package/dist/tools/__tests__/projects-list.test.d.ts.map +0 -1
- package/dist/tools/__tests__/projects-manage.test.d.ts +0 -2
- package/dist/tools/__tests__/projects-manage.test.d.ts.map +0 -1
- package/dist/tools/__tests__/projects-manage.test.js +0 -106
- package/dist/tools/__tests__/sections-manage.test.d.ts +0 -2
- package/dist/tools/__tests__/sections-manage.test.d.ts.map +0 -1
- package/dist/tools/__tests__/sections-manage.test.js +0 -138
- package/dist/tools/__tests__/sections-search.test.d.ts +0 -2
- package/dist/tools/__tests__/sections-search.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-add-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-add-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-complete-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-complete-multiple.test.js +0 -146
- package/dist/tools/__tests__/tasks-list-by-date.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-by-date.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-completed.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-completed.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-for-container.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-list-for-container.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-list-for-container.test.js +0 -232
- package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-organize-multiple.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-organize-multiple.test.js +0 -245
- package/dist/tools/__tests__/tasks-search.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-search.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-search.test.js +0 -106
- package/dist/tools/__tests__/tasks-update-one.test.d.ts +0 -2
- package/dist/tools/__tests__/tasks-update-one.test.d.ts.map +0 -1
- package/dist/tools/__tests__/tasks-update-one.test.js +0 -251
- package/dist/tools/delete-one.d.ts +0 -17
- package/dist/tools/delete-one.d.ts.map +0 -1
- package/dist/tools/delete-one.js +0 -25
- package/dist/tools/overview.d.ts +0 -14
- package/dist/tools/overview.d.ts.map +0 -1
- package/dist/tools/projects-list.d.ts +0 -29
- package/dist/tools/projects-list.d.ts.map +0 -1
- package/dist/tools/projects-list.js +0 -39
- package/dist/tools/projects-manage.d.ts +0 -24
- package/dist/tools/projects-manage.d.ts.map +0 -1
- package/dist/tools/projects-manage.js +0 -26
- package/dist/tools/sections-manage.d.ts +0 -23
- package/dist/tools/sections-manage.d.ts.map +0 -1
- package/dist/tools/sections-manage.js +0 -37
- package/dist/tools/sections-search.d.ts +0 -18
- package/dist/tools/sections-search.d.ts.map +0 -1
- package/dist/tools/sections-search.js +0 -27
- package/dist/tools/tasks-add-multiple.d.ts +0 -55
- package/dist/tools/tasks-add-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-add-multiple.js +0 -52
- package/dist/tools/tasks-complete-multiple.d.ts +0 -16
- package/dist/tools/tasks-complete-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-complete-multiple.js +0 -23
- package/dist/tools/tasks-list-by-date.d.ts +0 -34
- package/dist/tools/tasks-list-by-date.d.ts.map +0 -1
- package/dist/tools/tasks-list-by-date.js +0 -53
- package/dist/tools/tasks-list-completed.d.ts +0 -44
- package/dist/tools/tasks-list-completed.d.ts.map +0 -1
- package/dist/tools/tasks-list-completed.js +0 -49
- package/dist/tools/tasks-list-for-container.d.ts +0 -34
- package/dist/tools/tasks-list-for-container.d.ts.map +0 -1
- package/dist/tools/tasks-list-for-container.js +0 -48
- package/dist/tools/tasks-organize-multiple.d.ts +0 -37
- package/dist/tools/tasks-organize-multiple.d.ts.map +0 -1
- package/dist/tools/tasks-organize-multiple.js +0 -34
- package/dist/tools/tasks-search.d.ts +0 -32
- package/dist/tools/tasks-search.d.ts.map +0 -1
- package/dist/tools/tasks-search.js +0 -30
- package/dist/tools/tasks-update-one.d.ts +0 -29
- package/dist/tools/tasks-update-one.d.ts.map +0 -1
- package/dist/tools/tasks-update-one.js +0 -63
- package/dist/tools/test-helpers.d.ts.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TEST_ERRORS, TEST_IDS, createMockProject, createMockSection, createMockTask, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { getOverview } from '../get-overview.js';
|
|
4
5
|
// Mock the Todoist API
|
|
5
6
|
const mockTodoistApi = {
|
|
6
7
|
getProjects: jest.fn(),
|
|
@@ -8,7 +9,8 @@ const mockTodoistApi = {
|
|
|
8
9
|
getSections: jest.fn(),
|
|
9
10
|
getTasks: jest.fn(),
|
|
10
11
|
};
|
|
11
|
-
|
|
12
|
+
const { GET_OVERVIEW } = ToolNames;
|
|
13
|
+
describe(`${GET_OVERVIEW} tool`, () => {
|
|
12
14
|
beforeEach(() => {
|
|
13
15
|
jest.clearAllMocks();
|
|
14
16
|
});
|
|
@@ -45,15 +47,42 @@ describe('overview tool', () => {
|
|
|
45
47
|
}
|
|
46
48
|
return Promise.resolve({ results: [], nextCursor: null });
|
|
47
49
|
});
|
|
48
|
-
const result = await
|
|
50
|
+
const result = await getOverview.execute({}, mockTodoistApi);
|
|
49
51
|
expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({});
|
|
50
52
|
expect(mockTodoistApi.getSections).toHaveBeenCalledTimes(2); // Once for each project
|
|
51
|
-
//
|
|
52
|
-
expect(result).toMatchSnapshot();
|
|
53
|
+
// Test text content with snapshot
|
|
54
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
55
|
+
// Test structured content sanity checks
|
|
56
|
+
const structuredContent = extractStructuredContent(result);
|
|
57
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
58
|
+
type: 'account_overview',
|
|
59
|
+
inbox: expect.objectContaining({
|
|
60
|
+
id: TEST_IDS.PROJECT_INBOX,
|
|
61
|
+
name: 'Inbox',
|
|
62
|
+
sections: expect.any(Array),
|
|
63
|
+
}),
|
|
64
|
+
projects: expect.any(Array),
|
|
65
|
+
totalProjects: 2,
|
|
66
|
+
totalSections: 1,
|
|
67
|
+
hasNestedProjects: false,
|
|
68
|
+
}));
|
|
69
|
+
expect(structuredContent.projects).toHaveLength(1); // Only non-inbox projects
|
|
53
70
|
});
|
|
54
71
|
it('should handle empty projects list', async () => {
|
|
55
72
|
mockTodoistApi.getProjects.mockResolvedValue({ results: [], nextCursor: null });
|
|
56
|
-
|
|
73
|
+
const result = await getOverview.execute({}, mockTodoistApi);
|
|
74
|
+
// Test text content with snapshot
|
|
75
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
76
|
+
// Test structured content sanity checks
|
|
77
|
+
const structuredContent = extractStructuredContent(result);
|
|
78
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
79
|
+
type: 'account_overview',
|
|
80
|
+
inbox: null,
|
|
81
|
+
projects: [],
|
|
82
|
+
totalProjects: 0,
|
|
83
|
+
totalSections: 0,
|
|
84
|
+
hasNestedProjects: false,
|
|
85
|
+
}));
|
|
57
86
|
});
|
|
58
87
|
});
|
|
59
88
|
describe('project overview (with projectId)', () => {
|
|
@@ -114,7 +143,7 @@ describe('overview tool', () => {
|
|
|
114
143
|
results: mockTasks,
|
|
115
144
|
nextCursor: null,
|
|
116
145
|
});
|
|
117
|
-
const result = await
|
|
146
|
+
const result = await getOverview.execute({ projectId: TEST_IDS.PROJECT_TEST }, mockTodoistApi);
|
|
118
147
|
expect(mockTodoistApi.getProject).toHaveBeenCalledWith(TEST_IDS.PROJECT_TEST);
|
|
119
148
|
expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
|
|
120
149
|
projectId: TEST_IDS.PROJECT_TEST,
|
|
@@ -124,8 +153,26 @@ describe('overview tool', () => {
|
|
|
124
153
|
limit: 50,
|
|
125
154
|
cursor: undefined,
|
|
126
155
|
});
|
|
127
|
-
//
|
|
128
|
-
expect(result).toMatchSnapshot();
|
|
156
|
+
// Test text content with snapshot
|
|
157
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
158
|
+
// Test structured content sanity checks
|
|
159
|
+
const structuredContent = extractStructuredContent(result);
|
|
160
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
161
|
+
type: 'project_overview',
|
|
162
|
+
project: expect.objectContaining({
|
|
163
|
+
id: TEST_IDS.PROJECT_TEST,
|
|
164
|
+
name: 'test-abc123def456-project',
|
|
165
|
+
}),
|
|
166
|
+
sections: expect.any(Array),
|
|
167
|
+
tasks: expect.any(Array),
|
|
168
|
+
stats: expect.objectContaining({
|
|
169
|
+
totalTasks: 3,
|
|
170
|
+
totalSections: 2,
|
|
171
|
+
tasksWithoutSection: 1,
|
|
172
|
+
}),
|
|
173
|
+
}));
|
|
174
|
+
expect(structuredContent.sections).toHaveLength(2);
|
|
175
|
+
expect(structuredContent.tasks).toHaveLength(3);
|
|
129
176
|
});
|
|
130
177
|
it('should handle project with no tasks', async () => {
|
|
131
178
|
const mockProject = createMockProject({
|
|
@@ -136,8 +183,25 @@ describe('overview tool', () => {
|
|
|
136
183
|
mockTodoistApi.getProject.mockResolvedValue(mockProject);
|
|
137
184
|
mockTodoistApi.getSections.mockResolvedValue({ results: [], nextCursor: null });
|
|
138
185
|
mockTodoistApi.getTasks.mockResolvedValue({ results: [], nextCursor: null });
|
|
139
|
-
const result = await
|
|
140
|
-
|
|
186
|
+
const result = await getOverview.execute({ projectId: 'empty-project-id' }, mockTodoistApi);
|
|
187
|
+
// Test text content with snapshot
|
|
188
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
189
|
+
// Test structured content sanity checks
|
|
190
|
+
const structuredContent = extractStructuredContent(result);
|
|
191
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
192
|
+
type: 'project_overview',
|
|
193
|
+
project: expect.objectContaining({
|
|
194
|
+
id: 'empty-project-id',
|
|
195
|
+
name: 'Empty Project',
|
|
196
|
+
}),
|
|
197
|
+
sections: [],
|
|
198
|
+
tasks: [],
|
|
199
|
+
stats: expect.objectContaining({
|
|
200
|
+
totalTasks: 0,
|
|
201
|
+
totalSections: 0,
|
|
202
|
+
tasksWithoutSection: 0,
|
|
203
|
+
}),
|
|
204
|
+
}));
|
|
141
205
|
});
|
|
142
206
|
});
|
|
143
207
|
describe('error handling', () => {
|
|
@@ -157,7 +221,7 @@ describe('overview tool', () => {
|
|
|
157
221
|
])('should propagate API errors for $scenario', async ({ error, params, mockMethod }) => {
|
|
158
222
|
const apiError = new Error(error);
|
|
159
223
|
mockTodoistApi[mockMethod].mockRejectedValue(apiError);
|
|
160
|
-
await expect(
|
|
224
|
+
await expect(getOverview.execute(params, mockTodoistApi)).rejects.toThrow(error);
|
|
161
225
|
});
|
|
162
226
|
});
|
|
163
227
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-comments.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/update-comments.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { extractStructuredContent, extractTextContent } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { updateComments } from '../update-comments.js';
|
|
5
|
+
// Mock the Todoist API
|
|
6
|
+
const mockTodoistApi = {
|
|
7
|
+
updateComment: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
const { UPDATE_COMMENTS } = ToolNames;
|
|
10
|
+
const createMockComment = (overrides = {}) => ({
|
|
11
|
+
id: '12345',
|
|
12
|
+
content: 'Updated comment content',
|
|
13
|
+
postedAt: '2024-01-01T12:00:00Z',
|
|
14
|
+
postedUid: 'user123',
|
|
15
|
+
taskId: 'task123',
|
|
16
|
+
projectId: undefined,
|
|
17
|
+
fileAttachment: null,
|
|
18
|
+
uidsToNotify: null,
|
|
19
|
+
reactions: null,
|
|
20
|
+
isDeleted: false,
|
|
21
|
+
...overrides,
|
|
22
|
+
});
|
|
23
|
+
describe(`${UPDATE_COMMENTS} tool`, () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
jest.clearAllMocks();
|
|
26
|
+
});
|
|
27
|
+
it('should update comment content', async () => {
|
|
28
|
+
const mockComment = createMockComment({
|
|
29
|
+
id: '98765',
|
|
30
|
+
content: 'Updated content here',
|
|
31
|
+
taskId: 'task456',
|
|
32
|
+
});
|
|
33
|
+
mockTodoistApi.updateComment.mockResolvedValue(mockComment);
|
|
34
|
+
const result = await updateComments.execute({
|
|
35
|
+
comments: [
|
|
36
|
+
{
|
|
37
|
+
id: '98765',
|
|
38
|
+
content: 'Updated content here',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
}, mockTodoistApi);
|
|
42
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledWith('98765', {
|
|
43
|
+
content: 'Updated content here',
|
|
44
|
+
});
|
|
45
|
+
// Verify result is a concise summary
|
|
46
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
47
|
+
// Verify structured content
|
|
48
|
+
const structuredContent = extractStructuredContent(result);
|
|
49
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
50
|
+
comments: [
|
|
51
|
+
expect.objectContaining({
|
|
52
|
+
id: '98765',
|
|
53
|
+
content: 'Updated content here',
|
|
54
|
+
taskId: 'task456',
|
|
55
|
+
fileAttachment: null,
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
totalCount: 1,
|
|
59
|
+
updatedCommentIds: ['98765'],
|
|
60
|
+
appliedOperations: {
|
|
61
|
+
updateCount: 1,
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
65
|
+
it('should handle project comment', async () => {
|
|
66
|
+
const mockComment = createMockComment({
|
|
67
|
+
id: '98767',
|
|
68
|
+
content: 'Updated project comment',
|
|
69
|
+
taskId: undefined,
|
|
70
|
+
projectId: 'project789',
|
|
71
|
+
});
|
|
72
|
+
mockTodoistApi.updateComment.mockResolvedValue(mockComment);
|
|
73
|
+
const result = await updateComments.execute({
|
|
74
|
+
comments: [
|
|
75
|
+
{
|
|
76
|
+
id: '98767',
|
|
77
|
+
content: 'Updated project comment',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
}, mockTodoistApi);
|
|
81
|
+
// Verify result is a concise summary
|
|
82
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
83
|
+
// Verify structured content
|
|
84
|
+
const structuredContent = extractStructuredContent(result);
|
|
85
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
86
|
+
comments: [
|
|
87
|
+
expect.objectContaining({
|
|
88
|
+
id: '98767',
|
|
89
|
+
content: 'Updated project comment',
|
|
90
|
+
taskId: undefined,
|
|
91
|
+
projectId: 'project789',
|
|
92
|
+
fileAttachment: null,
|
|
93
|
+
}),
|
|
94
|
+
],
|
|
95
|
+
totalCount: 1,
|
|
96
|
+
updatedCommentIds: ['98767'],
|
|
97
|
+
appliedOperations: {
|
|
98
|
+
updateCount: 1,
|
|
99
|
+
},
|
|
100
|
+
}));
|
|
101
|
+
});
|
|
102
|
+
describe('bulk operations', () => {
|
|
103
|
+
it('should update multiple comments from different entities (task + project)', async () => {
|
|
104
|
+
const mockTaskComment = createMockComment({
|
|
105
|
+
id: '11111',
|
|
106
|
+
content: 'Updated task comment',
|
|
107
|
+
taskId: 'task123',
|
|
108
|
+
projectId: undefined,
|
|
109
|
+
});
|
|
110
|
+
const mockProjectComment = createMockComment({
|
|
111
|
+
id: '22222',
|
|
112
|
+
content: 'Updated project comment',
|
|
113
|
+
taskId: undefined,
|
|
114
|
+
projectId: 'project456',
|
|
115
|
+
});
|
|
116
|
+
mockTodoistApi.updateComment
|
|
117
|
+
.mockResolvedValueOnce(mockTaskComment)
|
|
118
|
+
.mockResolvedValueOnce(mockProjectComment);
|
|
119
|
+
const result = await updateComments.execute({
|
|
120
|
+
comments: [
|
|
121
|
+
{ id: '11111', content: 'Updated task comment' },
|
|
122
|
+
{ id: '22222', content: 'Updated project comment' },
|
|
123
|
+
],
|
|
124
|
+
}, mockTodoistApi);
|
|
125
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledTimes(2);
|
|
126
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledWith('11111', {
|
|
127
|
+
content: 'Updated task comment',
|
|
128
|
+
});
|
|
129
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledWith('22222', {
|
|
130
|
+
content: 'Updated project comment',
|
|
131
|
+
});
|
|
132
|
+
// Verify result is a concise summary
|
|
133
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
134
|
+
const structuredContent = extractStructuredContent(result);
|
|
135
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
136
|
+
comments: [
|
|
137
|
+
expect.objectContaining({
|
|
138
|
+
id: '11111',
|
|
139
|
+
content: 'Updated task comment',
|
|
140
|
+
taskId: 'task123',
|
|
141
|
+
}),
|
|
142
|
+
expect.objectContaining({
|
|
143
|
+
id: '22222',
|
|
144
|
+
content: 'Updated project comment',
|
|
145
|
+
projectId: 'project456',
|
|
146
|
+
}),
|
|
147
|
+
],
|
|
148
|
+
totalCount: 2,
|
|
149
|
+
updatedCommentIds: ['11111', '22222'],
|
|
150
|
+
appliedOperations: {
|
|
151
|
+
updateCount: 2,
|
|
152
|
+
},
|
|
153
|
+
}));
|
|
154
|
+
});
|
|
155
|
+
it('should update multiple comments from different tasks', async () => {
|
|
156
|
+
const mockComment1 = createMockComment({
|
|
157
|
+
id: '33333',
|
|
158
|
+
content: 'Updated first task comment',
|
|
159
|
+
taskId: 'task111',
|
|
160
|
+
});
|
|
161
|
+
const mockComment2 = createMockComment({
|
|
162
|
+
id: '44444',
|
|
163
|
+
content: 'Updated second task comment',
|
|
164
|
+
taskId: 'task222',
|
|
165
|
+
});
|
|
166
|
+
mockTodoistApi.updateComment
|
|
167
|
+
.mockResolvedValueOnce(mockComment1)
|
|
168
|
+
.mockResolvedValueOnce(mockComment2);
|
|
169
|
+
const result = await updateComments.execute({
|
|
170
|
+
comments: [
|
|
171
|
+
{ id: '33333', content: 'Updated first task comment' },
|
|
172
|
+
{ id: '44444', content: 'Updated second task comment' },
|
|
173
|
+
],
|
|
174
|
+
}, mockTodoistApi);
|
|
175
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledTimes(2);
|
|
176
|
+
// Verify result is a concise summary
|
|
177
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
178
|
+
const structuredContent = extractStructuredContent(result);
|
|
179
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
180
|
+
comments: expect.arrayContaining([
|
|
181
|
+
expect.objectContaining({
|
|
182
|
+
id: '33333',
|
|
183
|
+
content: 'Updated first task comment',
|
|
184
|
+
taskId: 'task111',
|
|
185
|
+
}),
|
|
186
|
+
expect.objectContaining({
|
|
187
|
+
id: '44444',
|
|
188
|
+
content: 'Updated second task comment',
|
|
189
|
+
taskId: 'task222',
|
|
190
|
+
}),
|
|
191
|
+
]),
|
|
192
|
+
totalCount: 2,
|
|
193
|
+
updatedCommentIds: ['33333', '44444'],
|
|
194
|
+
appliedOperations: {
|
|
195
|
+
updateCount: 2,
|
|
196
|
+
},
|
|
197
|
+
}));
|
|
198
|
+
});
|
|
199
|
+
it('should update multiple comments from the same task', async () => {
|
|
200
|
+
const mockComment1 = createMockComment({
|
|
201
|
+
id: '55555',
|
|
202
|
+
content: 'Updated first comment on same task',
|
|
203
|
+
taskId: 'task999',
|
|
204
|
+
});
|
|
205
|
+
const mockComment2 = createMockComment({
|
|
206
|
+
id: '66666',
|
|
207
|
+
content: 'Updated second comment on same task',
|
|
208
|
+
taskId: 'task999',
|
|
209
|
+
});
|
|
210
|
+
mockTodoistApi.updateComment
|
|
211
|
+
.mockResolvedValueOnce(mockComment1)
|
|
212
|
+
.mockResolvedValueOnce(mockComment2);
|
|
213
|
+
const result = await updateComments.execute({
|
|
214
|
+
comments: [
|
|
215
|
+
{ id: '55555', content: 'Updated first comment on same task' },
|
|
216
|
+
{ id: '66666', content: 'Updated second comment on same task' },
|
|
217
|
+
],
|
|
218
|
+
}, mockTodoistApi);
|
|
219
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledTimes(2);
|
|
220
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledWith('55555', {
|
|
221
|
+
content: 'Updated first comment on same task',
|
|
222
|
+
});
|
|
223
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledWith('66666', {
|
|
224
|
+
content: 'Updated second comment on same task',
|
|
225
|
+
});
|
|
226
|
+
// Verify result is a concise summary
|
|
227
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
228
|
+
const structuredContent = extractStructuredContent(result);
|
|
229
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
230
|
+
comments: expect.arrayContaining([
|
|
231
|
+
expect.objectContaining({
|
|
232
|
+
id: '55555',
|
|
233
|
+
content: 'Updated first comment on same task',
|
|
234
|
+
taskId: 'task999',
|
|
235
|
+
}),
|
|
236
|
+
expect.objectContaining({
|
|
237
|
+
id: '66666',
|
|
238
|
+
content: 'Updated second comment on same task',
|
|
239
|
+
taskId: 'task999',
|
|
240
|
+
}),
|
|
241
|
+
]),
|
|
242
|
+
totalCount: 2,
|
|
243
|
+
updatedCommentIds: ['55555', '66666'],
|
|
244
|
+
appliedOperations: {
|
|
245
|
+
updateCount: 2,
|
|
246
|
+
},
|
|
247
|
+
}));
|
|
248
|
+
});
|
|
249
|
+
it('should update multiple comments from the same project', async () => {
|
|
250
|
+
const mockComment1 = createMockComment({
|
|
251
|
+
id: '77777',
|
|
252
|
+
content: 'Updated first project comment',
|
|
253
|
+
taskId: undefined,
|
|
254
|
+
projectId: 'project888',
|
|
255
|
+
});
|
|
256
|
+
const mockComment2 = createMockComment({
|
|
257
|
+
id: '88888',
|
|
258
|
+
content: 'Updated second project comment',
|
|
259
|
+
taskId: undefined,
|
|
260
|
+
projectId: 'project888',
|
|
261
|
+
});
|
|
262
|
+
mockTodoistApi.updateComment
|
|
263
|
+
.mockResolvedValueOnce(mockComment1)
|
|
264
|
+
.mockResolvedValueOnce(mockComment2);
|
|
265
|
+
const result = await updateComments.execute({
|
|
266
|
+
comments: [
|
|
267
|
+
{ id: '77777', content: 'Updated first project comment' },
|
|
268
|
+
{ id: '88888', content: 'Updated second project comment' },
|
|
269
|
+
],
|
|
270
|
+
}, mockTodoistApi);
|
|
271
|
+
expect(mockTodoistApi.updateComment).toHaveBeenCalledTimes(2);
|
|
272
|
+
// Verify result is a concise summary
|
|
273
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
274
|
+
const structuredContent = extractStructuredContent(result);
|
|
275
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
276
|
+
comments: expect.arrayContaining([
|
|
277
|
+
expect.objectContaining({
|
|
278
|
+
id: '77777',
|
|
279
|
+
content: 'Updated first project comment',
|
|
280
|
+
projectId: 'project888',
|
|
281
|
+
}),
|
|
282
|
+
expect.objectContaining({
|
|
283
|
+
id: '88888',
|
|
284
|
+
content: 'Updated second project comment',
|
|
285
|
+
projectId: 'project888',
|
|
286
|
+
}),
|
|
287
|
+
]),
|
|
288
|
+
totalCount: 2,
|
|
289
|
+
updatedCommentIds: ['77777', '88888'],
|
|
290
|
+
appliedOperations: {
|
|
291
|
+
updateCount: 2,
|
|
292
|
+
},
|
|
293
|
+
}));
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-projects.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/update-projects.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { createMockProject, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { updateProjects } from '../update-projects.js';
|
|
5
|
+
// Mock the Todoist API
|
|
6
|
+
const mockTodoistApi = {
|
|
7
|
+
updateProject: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
const { FIND_PROJECTS, UPDATE_PROJECTS, GET_OVERVIEW } = ToolNames;
|
|
10
|
+
describe(`${UPDATE_PROJECTS} tool`, () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
jest.clearAllMocks();
|
|
13
|
+
});
|
|
14
|
+
describe('updating a single project', () => {
|
|
15
|
+
it('should update a project when id and name are provided', async () => {
|
|
16
|
+
const mockApiResponse = {
|
|
17
|
+
url: 'https://todoist.com/projects/existing-project-123',
|
|
18
|
+
id: 'existing-project-123',
|
|
19
|
+
parentId: null,
|
|
20
|
+
isDeleted: false,
|
|
21
|
+
updatedAt: '2025-08-13T22:10:30.000000Z',
|
|
22
|
+
childOrder: 1,
|
|
23
|
+
description: '',
|
|
24
|
+
isCollapsed: false,
|
|
25
|
+
canAssignTasks: false,
|
|
26
|
+
color: 'red',
|
|
27
|
+
isFavorite: false,
|
|
28
|
+
isFrozen: false,
|
|
29
|
+
name: 'Updated Project Name',
|
|
30
|
+
viewStyle: 'list',
|
|
31
|
+
isArchived: false,
|
|
32
|
+
inboxProject: false,
|
|
33
|
+
isShared: false,
|
|
34
|
+
createdAt: '2024-01-01T00:00:00Z',
|
|
35
|
+
defaultOrder: 0,
|
|
36
|
+
};
|
|
37
|
+
mockTodoistApi.updateProject.mockResolvedValue(mockApiResponse);
|
|
38
|
+
const result = await updateProjects.execute({ projects: [{ id: 'existing-project-123', name: 'Updated Project Name' }] }, mockTodoistApi);
|
|
39
|
+
expect(mockTodoistApi.updateProject).toHaveBeenCalledWith('existing-project-123', {
|
|
40
|
+
name: 'Updated Project Name',
|
|
41
|
+
});
|
|
42
|
+
const textContent = extractTextContent(result);
|
|
43
|
+
expect(textContent).toMatchSnapshot();
|
|
44
|
+
expect(textContent).toContain('Updated 1 project:');
|
|
45
|
+
expect(textContent).toContain('Updated Project Name (id=existing-project-123)');
|
|
46
|
+
expect(textContent).toContain(`Use ${GET_OVERVIEW} with projectId=existing-project-123`);
|
|
47
|
+
// Verify structured content
|
|
48
|
+
const structuredContent = extractStructuredContent(result);
|
|
49
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
50
|
+
projects: [mockApiResponse],
|
|
51
|
+
totalCount: 1,
|
|
52
|
+
updatedProjectIds: ['existing-project-123'],
|
|
53
|
+
appliedOperations: {
|
|
54
|
+
updateCount: 1,
|
|
55
|
+
skippedCount: 0,
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
it('should update project with isFavorite and viewStyle options', async () => {
|
|
60
|
+
const mockApiResponse = {
|
|
61
|
+
url: 'https://todoist.com/projects/project-123',
|
|
62
|
+
id: 'project-123',
|
|
63
|
+
parentId: null,
|
|
64
|
+
isDeleted: false,
|
|
65
|
+
updatedAt: '2025-08-13T22:10:30.000000Z',
|
|
66
|
+
childOrder: 1,
|
|
67
|
+
description: '',
|
|
68
|
+
isCollapsed: false,
|
|
69
|
+
canAssignTasks: false,
|
|
70
|
+
color: 'red',
|
|
71
|
+
isFavorite: true,
|
|
72
|
+
isFrozen: false,
|
|
73
|
+
name: 'Updated Favorite Project',
|
|
74
|
+
viewStyle: 'board',
|
|
75
|
+
isArchived: false,
|
|
76
|
+
inboxProject: false,
|
|
77
|
+
isShared: false,
|
|
78
|
+
createdAt: '2024-01-01T00:00:00Z',
|
|
79
|
+
defaultOrder: 0,
|
|
80
|
+
};
|
|
81
|
+
mockTodoistApi.updateProject.mockResolvedValue(mockApiResponse);
|
|
82
|
+
const result = await updateProjects.execute({
|
|
83
|
+
projects: [
|
|
84
|
+
{
|
|
85
|
+
id: 'project-123',
|
|
86
|
+
name: 'Updated Favorite Project',
|
|
87
|
+
isFavorite: true,
|
|
88
|
+
viewStyle: 'board',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}, mockTodoistApi);
|
|
92
|
+
expect(mockTodoistApi.updateProject).toHaveBeenCalledWith('project-123', {
|
|
93
|
+
name: 'Updated Favorite Project',
|
|
94
|
+
isFavorite: true,
|
|
95
|
+
viewStyle: 'board',
|
|
96
|
+
});
|
|
97
|
+
const textContent = extractTextContent(result);
|
|
98
|
+
expect(textContent).toMatchSnapshot();
|
|
99
|
+
expect(textContent).toContain('Updated 1 project:');
|
|
100
|
+
expect(textContent).toContain('Updated Favorite Project (id=project-123)');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('updating multiple projects', () => {
|
|
104
|
+
it('should update multiple projects and return mapped results', async () => {
|
|
105
|
+
const mockProjects = [
|
|
106
|
+
createMockProject({ id: 'project-1', name: 'Updated First Project' }),
|
|
107
|
+
createMockProject({ id: 'project-2', name: 'Updated Second Project' }),
|
|
108
|
+
createMockProject({ id: 'project-3', name: 'Updated Third Project' }),
|
|
109
|
+
];
|
|
110
|
+
const [project1, project2, project3] = mockProjects;
|
|
111
|
+
mockTodoistApi.updateProject
|
|
112
|
+
.mockResolvedValueOnce(project1)
|
|
113
|
+
.mockResolvedValueOnce(project2)
|
|
114
|
+
.mockResolvedValueOnce(project3);
|
|
115
|
+
const result = await updateProjects.execute({
|
|
116
|
+
projects: [
|
|
117
|
+
{ id: 'project-1', name: 'Updated First Project' },
|
|
118
|
+
{ id: 'project-2', name: 'Updated Second Project' },
|
|
119
|
+
{ id: 'project-3', name: 'Updated Third Project' },
|
|
120
|
+
],
|
|
121
|
+
}, mockTodoistApi);
|
|
122
|
+
// Verify API was called correctly for each project
|
|
123
|
+
expect(mockTodoistApi.updateProject).toHaveBeenCalledTimes(3);
|
|
124
|
+
expect(mockTodoistApi.updateProject).toHaveBeenNthCalledWith(1, 'project-1', {
|
|
125
|
+
name: 'Updated First Project',
|
|
126
|
+
});
|
|
127
|
+
expect(mockTodoistApi.updateProject).toHaveBeenNthCalledWith(2, 'project-2', {
|
|
128
|
+
name: 'Updated Second Project',
|
|
129
|
+
});
|
|
130
|
+
expect(mockTodoistApi.updateProject).toHaveBeenNthCalledWith(3, 'project-3', {
|
|
131
|
+
name: 'Updated Third Project',
|
|
132
|
+
});
|
|
133
|
+
const textContent = extractTextContent(result);
|
|
134
|
+
expect(textContent).toMatchSnapshot();
|
|
135
|
+
expect(textContent).toContain('Updated 3 projects:');
|
|
136
|
+
expect(textContent).toContain('Updated First Project (id=project-1)');
|
|
137
|
+
expect(textContent).toContain('Updated Second Project (id=project-2)');
|
|
138
|
+
expect(textContent).toContain('Updated Third Project (id=project-3)');
|
|
139
|
+
expect(textContent).toContain(`Use ${FIND_PROJECTS} to see all projects`);
|
|
140
|
+
// Verify structured content
|
|
141
|
+
const structuredContent = extractStructuredContent(result);
|
|
142
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
143
|
+
projects: mockProjects,
|
|
144
|
+
totalCount: 3,
|
|
145
|
+
updatedProjectIds: ['project-1', 'project-2', 'project-3'],
|
|
146
|
+
appliedOperations: {
|
|
147
|
+
updateCount: 3,
|
|
148
|
+
skippedCount: 0,
|
|
149
|
+
},
|
|
150
|
+
}));
|
|
151
|
+
});
|
|
152
|
+
it('should skip projects with no updates and report correctly', async () => {
|
|
153
|
+
const mockProject = createMockProject({
|
|
154
|
+
id: 'project-1',
|
|
155
|
+
name: 'Updated Project',
|
|
156
|
+
});
|
|
157
|
+
mockTodoistApi.updateProject.mockResolvedValue(mockProject);
|
|
158
|
+
const result = await updateProjects.execute({
|
|
159
|
+
projects: [
|
|
160
|
+
{ id: 'project-1', name: 'Updated Project' },
|
|
161
|
+
{ id: 'project-2' }, // No name provided, should be skipped
|
|
162
|
+
],
|
|
163
|
+
}, mockTodoistApi);
|
|
164
|
+
// Should only call API once for the project with actual updates
|
|
165
|
+
expect(mockTodoistApi.updateProject).toHaveBeenCalledTimes(1);
|
|
166
|
+
expect(mockTodoistApi.updateProject).toHaveBeenCalledWith('project-1', {
|
|
167
|
+
name: 'Updated Project',
|
|
168
|
+
});
|
|
169
|
+
const textContent = extractTextContent(result);
|
|
170
|
+
expect(textContent).toMatchSnapshot();
|
|
171
|
+
expect(textContent).toContain('Updated 1 project (1 skipped - no changes):');
|
|
172
|
+
expect(textContent).toContain('Updated Project (id=project-1)');
|
|
173
|
+
// Verify structured content reflects skipped count
|
|
174
|
+
const structuredContent = extractStructuredContent(result);
|
|
175
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
176
|
+
appliedOperations: {
|
|
177
|
+
updateCount: 1,
|
|
178
|
+
skippedCount: 1,
|
|
179
|
+
},
|
|
180
|
+
}));
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('error handling', () => {
|
|
184
|
+
it('should propagate API errors', async () => {
|
|
185
|
+
const apiError = new Error('API Error: Project not found');
|
|
186
|
+
mockTodoistApi.updateProject.mockRejectedValue(apiError);
|
|
187
|
+
await expect(updateProjects.execute({ projects: [{ id: 'nonexistent', name: 'New Name' }] }, mockTodoistApi)).rejects.toThrow('API Error: Project not found');
|
|
188
|
+
});
|
|
189
|
+
it('should handle partial failures in multiple projects', async () => {
|
|
190
|
+
const mockProject = createMockProject({
|
|
191
|
+
id: 'project-1',
|
|
192
|
+
name: 'Updated Project',
|
|
193
|
+
});
|
|
194
|
+
mockTodoistApi.updateProject
|
|
195
|
+
.mockResolvedValueOnce(mockProject)
|
|
196
|
+
.mockRejectedValueOnce(new Error('API Error: Project not found'));
|
|
197
|
+
await expect(updateProjects.execute({
|
|
198
|
+
projects: [
|
|
199
|
+
{ id: 'project-1', name: 'Updated Project' },
|
|
200
|
+
{ id: 'nonexistent', name: 'New Name' },
|
|
201
|
+
],
|
|
202
|
+
}, mockTodoistApi)).rejects.toThrow('API Error: Project not found');
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-sections.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/update-sections.test.ts"],"names":[],"mappings":""}
|