@doist/todoist-ai 3.0.0 → 4.1.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 +2 -18
- package/dist/index.d.ts +296 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -6
- package/dist/main.js +2 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +16 -4
- 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.js +16 -10
- 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-sections.test.js +2 -2
- 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/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/{manage-sections.d.ts → add-sections.d.ts} +21 -13
- 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 +15 -8
- package/dist/tools/add-tasks.d.ts.map +1 -1
- package/dist/tools/add-tasks.js +46 -37
- package/dist/tools/delete-object.d.ts +3 -3
- package/dist/tools/delete-object.d.ts.map +1 -1
- package/dist/tools/delete-object.js +13 -3
- 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-projects.js +2 -2
- package/dist/tools/find-sections.js +4 -4
- 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/utils/constants.d.ts +4 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +4 -0
- package/dist/utils/tool-names.d.ts +7 -2
- package/dist/utils/tool-names.d.ts.map +1 -1
- package/dist/utils/tool-names.js +8 -2
- package/package.json +1 -1
- package/dist/tools/__tests__/manage-projects.test.d.ts +0 -2
- package/dist/tools/__tests__/manage-projects.test.d.ts.map +0 -1
- package/dist/tools/__tests__/manage-projects.test.js +0 -109
- package/dist/tools/__tests__/manage-sections.test.d.ts +0 -2
- package/dist/tools/__tests__/manage-sections.test.d.ts.map +0 -1
- package/dist/tools/__tests__/manage-sections.test.js +0 -162
- package/dist/tools/manage-projects.d.ts +0 -35
- package/dist/tools/manage-projects.d.ts.map +0 -1
- package/dist/tools/manage-projects.js +0 -63
- package/dist/tools/manage-sections.d.ts.map +0 -1
- package/dist/tools/manage-sections.js +0 -78
|
@@ -0,0 +1,242 @@
|
|
|
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 { findComments } from '../find-comments.js';
|
|
5
|
+
// Mock the Todoist API
|
|
6
|
+
const mockTodoistApi = {
|
|
7
|
+
getComment: jest.fn(),
|
|
8
|
+
getComments: jest.fn(),
|
|
9
|
+
};
|
|
10
|
+
const { FIND_COMMENTS } = ToolNames;
|
|
11
|
+
const createMockComment = (overrides = {}) => ({
|
|
12
|
+
id: '12345',
|
|
13
|
+
content: 'Test comment content',
|
|
14
|
+
postedAt: '2024-01-01T12:00:00Z',
|
|
15
|
+
postedUid: 'user123',
|
|
16
|
+
taskId: 'task123',
|
|
17
|
+
projectId: undefined,
|
|
18
|
+
fileAttachment: null,
|
|
19
|
+
uidsToNotify: null,
|
|
20
|
+
reactions: null,
|
|
21
|
+
isDeleted: false,
|
|
22
|
+
...overrides,
|
|
23
|
+
});
|
|
24
|
+
describe(`${FIND_COMMENTS} tool`, () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
jest.clearAllMocks();
|
|
27
|
+
});
|
|
28
|
+
describe('finding comments by task', () => {
|
|
29
|
+
it('should find comments for a task', async () => {
|
|
30
|
+
const mockComments = [
|
|
31
|
+
createMockComment({ id: '1', content: 'First comment', taskId: 'task123' }),
|
|
32
|
+
createMockComment({ id: '2', content: 'Second comment', taskId: 'task123' }),
|
|
33
|
+
];
|
|
34
|
+
mockTodoistApi.getComments.mockResolvedValue({
|
|
35
|
+
results: mockComments,
|
|
36
|
+
nextCursor: null,
|
|
37
|
+
});
|
|
38
|
+
const result = await findComments.execute({
|
|
39
|
+
taskId: 'task123',
|
|
40
|
+
}, mockTodoistApi);
|
|
41
|
+
expect(mockTodoistApi.getComments).toHaveBeenCalledWith({
|
|
42
|
+
taskId: 'task123',
|
|
43
|
+
cursor: null,
|
|
44
|
+
limit: 10,
|
|
45
|
+
});
|
|
46
|
+
// Verify result is a concise summary
|
|
47
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
48
|
+
// Verify structured content
|
|
49
|
+
const structuredContent = extractStructuredContent(result);
|
|
50
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
51
|
+
comments: expect.arrayContaining([
|
|
52
|
+
expect.objectContaining({ id: '1', content: 'First comment' }),
|
|
53
|
+
expect.objectContaining({ id: '2', content: 'Second comment' }),
|
|
54
|
+
]),
|
|
55
|
+
searchType: 'task',
|
|
56
|
+
searchId: 'task123',
|
|
57
|
+
hasMore: false,
|
|
58
|
+
nextCursor: null,
|
|
59
|
+
totalCount: 2,
|
|
60
|
+
}));
|
|
61
|
+
});
|
|
62
|
+
it('should handle pagination', async () => {
|
|
63
|
+
const mockComments = [createMockComment({ id: '1', content: 'Comment 1' })];
|
|
64
|
+
mockTodoistApi.getComments.mockResolvedValue({
|
|
65
|
+
results: mockComments,
|
|
66
|
+
nextCursor: 'next_page_token',
|
|
67
|
+
});
|
|
68
|
+
const result = await findComments.execute({
|
|
69
|
+
taskId: 'task123',
|
|
70
|
+
limit: 1,
|
|
71
|
+
cursor: 'current_cursor',
|
|
72
|
+
}, mockTodoistApi);
|
|
73
|
+
expect(mockTodoistApi.getComments).toHaveBeenCalledWith({
|
|
74
|
+
taskId: 'task123',
|
|
75
|
+
cursor: 'current_cursor',
|
|
76
|
+
limit: 1,
|
|
77
|
+
});
|
|
78
|
+
// Verify result includes pagination info
|
|
79
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
80
|
+
// Verify structured content includes pagination
|
|
81
|
+
const structuredContent = extractStructuredContent(result);
|
|
82
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
83
|
+
comments: expect.arrayContaining([
|
|
84
|
+
expect.objectContaining({ id: '1', content: 'Comment 1' }),
|
|
85
|
+
]),
|
|
86
|
+
searchType: 'task',
|
|
87
|
+
searchId: 'task123',
|
|
88
|
+
hasMore: true,
|
|
89
|
+
nextCursor: 'next_page_token',
|
|
90
|
+
totalCount: 1,
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('finding comments by project', () => {
|
|
95
|
+
it('should find comments for a project', async () => {
|
|
96
|
+
const mockComments = [
|
|
97
|
+
createMockComment({
|
|
98
|
+
id: '1',
|
|
99
|
+
content: 'Project comment',
|
|
100
|
+
taskId: undefined,
|
|
101
|
+
projectId: 'project456',
|
|
102
|
+
}),
|
|
103
|
+
];
|
|
104
|
+
mockTodoistApi.getComments.mockResolvedValue({
|
|
105
|
+
results: mockComments,
|
|
106
|
+
nextCursor: null,
|
|
107
|
+
});
|
|
108
|
+
const result = await findComments.execute({
|
|
109
|
+
projectId: 'project456',
|
|
110
|
+
}, mockTodoistApi);
|
|
111
|
+
expect(mockTodoistApi.getComments).toHaveBeenCalledWith({
|
|
112
|
+
projectId: 'project456',
|
|
113
|
+
cursor: null,
|
|
114
|
+
limit: 10,
|
|
115
|
+
});
|
|
116
|
+
// Verify result is a concise summary
|
|
117
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
118
|
+
// Verify structured content
|
|
119
|
+
const structuredContent = extractStructuredContent(result);
|
|
120
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
121
|
+
comments: expect.arrayContaining([
|
|
122
|
+
expect.objectContaining({
|
|
123
|
+
id: '1',
|
|
124
|
+
content: 'Project comment',
|
|
125
|
+
projectId: 'project456',
|
|
126
|
+
}),
|
|
127
|
+
]),
|
|
128
|
+
searchType: 'project',
|
|
129
|
+
searchId: 'project456',
|
|
130
|
+
hasMore: false,
|
|
131
|
+
nextCursor: null,
|
|
132
|
+
totalCount: 1,
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('finding single comment', () => {
|
|
137
|
+
it('should find comment by ID', async () => {
|
|
138
|
+
const mockComment = createMockComment({
|
|
139
|
+
id: 'comment789',
|
|
140
|
+
content: 'Single comment content',
|
|
141
|
+
taskId: 'task123',
|
|
142
|
+
});
|
|
143
|
+
mockTodoistApi.getComment.mockResolvedValue(mockComment);
|
|
144
|
+
const result = await findComments.execute({
|
|
145
|
+
commentId: 'comment789',
|
|
146
|
+
}, mockTodoistApi);
|
|
147
|
+
expect(mockTodoistApi.getComment).toHaveBeenCalledWith('comment789');
|
|
148
|
+
// Verify result is a concise summary
|
|
149
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
150
|
+
// Verify structured content
|
|
151
|
+
const structuredContent = extractStructuredContent(result);
|
|
152
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
153
|
+
comments: expect.arrayContaining([
|
|
154
|
+
expect.objectContaining({
|
|
155
|
+
id: 'comment789',
|
|
156
|
+
content: 'Single comment content',
|
|
157
|
+
taskId: 'task123',
|
|
158
|
+
fileAttachment: null,
|
|
159
|
+
}),
|
|
160
|
+
]),
|
|
161
|
+
searchType: 'single',
|
|
162
|
+
searchId: 'comment789',
|
|
163
|
+
hasMore: false,
|
|
164
|
+
nextCursor: null,
|
|
165
|
+
totalCount: 1,
|
|
166
|
+
}));
|
|
167
|
+
});
|
|
168
|
+
it('should handle comment with attachment', async () => {
|
|
169
|
+
const mockComment = createMockComment({
|
|
170
|
+
id: 'comment789',
|
|
171
|
+
content: 'Comment with file',
|
|
172
|
+
fileAttachment: {
|
|
173
|
+
resourceType: 'file',
|
|
174
|
+
fileName: 'document.pdf',
|
|
175
|
+
fileUrl: 'https://example.com/document.pdf',
|
|
176
|
+
fileType: 'application/pdf',
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
mockTodoistApi.getComment.mockResolvedValue(mockComment);
|
|
180
|
+
const result = await findComments.execute({
|
|
181
|
+
commentId: 'comment789',
|
|
182
|
+
}, mockTodoistApi);
|
|
183
|
+
// Verify result includes attachment info
|
|
184
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
185
|
+
// Verify structured content includes attachment
|
|
186
|
+
const structuredContent = extractStructuredContent(result);
|
|
187
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
188
|
+
comments: expect.arrayContaining([
|
|
189
|
+
expect.objectContaining({
|
|
190
|
+
id: 'comment789',
|
|
191
|
+
content: 'Comment with file',
|
|
192
|
+
fileAttachment: expect.objectContaining({
|
|
193
|
+
resourceType: 'file',
|
|
194
|
+
fileName: 'document.pdf',
|
|
195
|
+
fileUrl: 'https://example.com/document.pdf',
|
|
196
|
+
fileType: 'application/pdf',
|
|
197
|
+
}),
|
|
198
|
+
}),
|
|
199
|
+
]),
|
|
200
|
+
searchType: 'single',
|
|
201
|
+
searchId: 'comment789',
|
|
202
|
+
hasMore: false,
|
|
203
|
+
nextCursor: null,
|
|
204
|
+
totalCount: 1,
|
|
205
|
+
}));
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('validation', () => {
|
|
209
|
+
it('should throw error when no search parameter provided', async () => {
|
|
210
|
+
await expect(findComments.execute({}, mockTodoistApi)).rejects.toThrow('Must provide exactly one of: taskId, projectId, or commentId.');
|
|
211
|
+
});
|
|
212
|
+
it('should throw error when multiple search parameters provided', async () => {
|
|
213
|
+
await expect(findComments.execute({
|
|
214
|
+
taskId: 'task123',
|
|
215
|
+
projectId: 'project456',
|
|
216
|
+
}, mockTodoistApi)).rejects.toThrow('Cannot provide multiple search parameters.');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
describe('empty results', () => {
|
|
220
|
+
it('should handle no comments found', async () => {
|
|
221
|
+
mockTodoistApi.getComments.mockResolvedValue({
|
|
222
|
+
results: [],
|
|
223
|
+
nextCursor: null,
|
|
224
|
+
});
|
|
225
|
+
const result = await findComments.execute({
|
|
226
|
+
taskId: 'task123',
|
|
227
|
+
}, mockTodoistApi);
|
|
228
|
+
// Verify result handles empty case
|
|
229
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
230
|
+
// Verify structured content
|
|
231
|
+
const structuredContent = extractStructuredContent(result);
|
|
232
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
233
|
+
comments: [],
|
|
234
|
+
searchType: 'task',
|
|
235
|
+
searchId: 'task123',
|
|
236
|
+
hasMore: false,
|
|
237
|
+
nextCursor: null,
|
|
238
|
+
totalCount: 0,
|
|
239
|
+
}));
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|
|
@@ -6,7 +6,7 @@ import { findSections } from '../find-sections.js';
|
|
|
6
6
|
const mockTodoistApi = {
|
|
7
7
|
getSections: jest.fn(),
|
|
8
8
|
};
|
|
9
|
-
const { FIND_SECTIONS,
|
|
9
|
+
const { FIND_SECTIONS, ADD_SECTIONS } = ToolNames;
|
|
10
10
|
describe(`${FIND_SECTIONS} tool`, () => {
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
jest.clearAllMocks();
|
|
@@ -74,7 +74,7 @@ describe(`${FIND_SECTIONS} tool`, () => {
|
|
|
74
74
|
const textContent = extractTextContent(result);
|
|
75
75
|
expect(textContent).toMatchSnapshot();
|
|
76
76
|
expect(textContent).toContain('Project has no sections yet');
|
|
77
|
-
expect(textContent).toContain(`Use ${
|
|
77
|
+
expect(textContent).toContain(`Use ${ADD_SECTIONS} to create sections`);
|
|
78
78
|
// Verify structured content
|
|
79
79
|
const structuredContent = extractStructuredContent(result);
|
|
80
80
|
expect(structuredContent.sections).toHaveLength(0);
|
|
@@ -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":""}
|