@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,12 +1,14 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createMockTask, extractTextContent } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { findCompletedTasks } from '../find-completed-tasks.js';
|
|
4
5
|
// Mock the Todoist API
|
|
5
6
|
const mockTodoistApi = {
|
|
6
7
|
getCompletedTasksByCompletionDate: jest.fn(),
|
|
7
8
|
getCompletedTasksByDueDate: jest.fn(),
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
+
const { FIND_COMPLETED_TASKS } = ToolNames;
|
|
11
|
+
describe(`${FIND_COMPLETED_TASKS} tool`, () => {
|
|
10
12
|
beforeEach(() => {
|
|
11
13
|
jest.clearAllMocks();
|
|
12
14
|
});
|
|
@@ -35,32 +37,20 @@ describe('tasks-list-completed tool', () => {
|
|
|
35
37
|
items: mockCompletedTasks,
|
|
36
38
|
nextCursor: null,
|
|
37
39
|
});
|
|
38
|
-
const result = await
|
|
40
|
+
const result = await findCompletedTasks.execute({ getBy: 'completion', limit: 50, since: '2025-08-10', until: '2025-08-15' }, mockTodoistApi);
|
|
39
41
|
expect(mockTodoistApi.getCompletedTasksByCompletionDate).toHaveBeenCalledWith({
|
|
40
42
|
since: '2025-08-10',
|
|
41
43
|
until: '2025-08-15',
|
|
42
44
|
limit: 50,
|
|
43
45
|
});
|
|
44
|
-
expect(result).
|
|
45
|
-
tasks: [
|
|
46
|
-
expect.objectContaining({
|
|
47
|
-
id: '8485093748',
|
|
48
|
-
content: 'Completed task 1',
|
|
49
|
-
description: 'Task completed yesterday',
|
|
50
|
-
dueDate: '2025-08-14',
|
|
51
|
-
priority: 2,
|
|
52
|
-
labels: ['work'],
|
|
53
|
-
}),
|
|
54
|
-
],
|
|
55
|
-
nextCursor: null,
|
|
56
|
-
});
|
|
46
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
57
47
|
});
|
|
58
48
|
it('should handle explicit completion date query', async () => {
|
|
59
49
|
mockTodoistApi.getCompletedTasksByCompletionDate.mockResolvedValue({
|
|
60
50
|
items: [],
|
|
61
51
|
nextCursor: 'next-cursor',
|
|
62
52
|
});
|
|
63
|
-
const result = await
|
|
53
|
+
const result = await findCompletedTasks.execute({
|
|
64
54
|
getBy: 'completion',
|
|
65
55
|
limit: 100,
|
|
66
56
|
since: '2025-08-01',
|
|
@@ -75,7 +65,7 @@ describe('tasks-list-completed tool', () => {
|
|
|
75
65
|
limit: 100,
|
|
76
66
|
cursor: 'current-cursor',
|
|
77
67
|
});
|
|
78
|
-
expect(result).
|
|
68
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
79
69
|
});
|
|
80
70
|
});
|
|
81
71
|
describe('getting completed tasks by due date', () => {
|
|
@@ -103,7 +93,7 @@ describe('tasks-list-completed tool', () => {
|
|
|
103
93
|
items: mockCompletedTasks,
|
|
104
94
|
nextCursor: null,
|
|
105
95
|
});
|
|
106
|
-
const result = await
|
|
96
|
+
const result = await findCompletedTasks.execute({
|
|
107
97
|
getBy: 'due',
|
|
108
98
|
limit: 50,
|
|
109
99
|
since: '2025-08-10',
|
|
@@ -115,34 +105,21 @@ describe('tasks-list-completed tool', () => {
|
|
|
115
105
|
limit: 50,
|
|
116
106
|
});
|
|
117
107
|
expect(mockTodoistApi.getCompletedTasksByCompletionDate).not.toHaveBeenCalled();
|
|
118
|
-
expect(result).
|
|
119
|
-
tasks: [
|
|
120
|
-
expect.objectContaining({
|
|
121
|
-
id: '8485093750',
|
|
122
|
-
content: 'Task completed by due date',
|
|
123
|
-
description: 'This task was due and completed',
|
|
124
|
-
dueDate: '2025-08-15',
|
|
125
|
-
recurring: 'every Monday',
|
|
126
|
-
priority: 3,
|
|
127
|
-
labels: ['urgent'],
|
|
128
|
-
}),
|
|
129
|
-
],
|
|
130
|
-
nextCursor: null,
|
|
131
|
-
});
|
|
108
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
132
109
|
});
|
|
133
110
|
});
|
|
134
111
|
describe('error handling', () => {
|
|
135
112
|
it('should propagate completion date API errors', async () => {
|
|
136
113
|
const apiError = new Error('API Error: Invalid date range');
|
|
137
114
|
mockTodoistApi.getCompletedTasksByCompletionDate.mockRejectedValue(apiError);
|
|
138
|
-
await expect(
|
|
115
|
+
await expect(findCompletedTasks.execute(
|
|
139
116
|
// invalid date range
|
|
140
117
|
{ getBy: 'completion', limit: 50, since: '2025-08-31', until: '2025-08-01' }, mockTodoistApi)).rejects.toThrow('API Error: Invalid date range');
|
|
141
118
|
});
|
|
142
119
|
it('should propagate due date API errors', async () => {
|
|
143
120
|
const apiError = new Error('API Error: Project not found');
|
|
144
121
|
mockTodoistApi.getCompletedTasksByDueDate.mockRejectedValue(apiError);
|
|
145
|
-
await expect(
|
|
122
|
+
await expect(findCompletedTasks.execute({
|
|
146
123
|
getBy: 'due',
|
|
147
124
|
limit: 50,
|
|
148
125
|
since: '2025-08-01',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-projects.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-projects.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TEST_ERRORS, TEST_IDS, createMockApiResponse, createMockProject, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { findProjects } from '../find-projects.js';
|
|
4
5
|
// Mock the Todoist API
|
|
5
6
|
const mockTodoistApi = {
|
|
6
7
|
getProjects: jest.fn(),
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
+
const { FIND_PROJECTS } = ToolNames;
|
|
10
|
+
describe(`${FIND_PROJECTS} tool`, () => {
|
|
9
11
|
beforeEach(() => {
|
|
10
12
|
jest.clearAllMocks();
|
|
11
13
|
});
|
|
@@ -38,37 +40,27 @@ describe('projects-list tool', () => {
|
|
|
38
40
|
}),
|
|
39
41
|
];
|
|
40
42
|
mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
|
|
41
|
-
const result = await
|
|
43
|
+
const result = await findProjects.execute({ limit: 50 }, mockTodoistApi);
|
|
42
44
|
// Verify API was called correctly
|
|
43
45
|
expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({
|
|
44
46
|
limit: 50,
|
|
45
47
|
cursor: null,
|
|
46
48
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
inboxProject: true,
|
|
55
|
-
}),
|
|
56
|
-
expect.objectContaining({
|
|
57
|
-
id: TEST_IDS.PROJECT_TEST,
|
|
58
|
-
name: 'test-abc123def456-project',
|
|
59
|
-
color: 'charcoal',
|
|
60
|
-
}),
|
|
61
|
-
expect.objectContaining({
|
|
62
|
-
id: TEST_IDS.PROJECT_WORK,
|
|
63
|
-
name: 'Work Project',
|
|
64
|
-
color: 'blue',
|
|
65
|
-
isFavorite: true,
|
|
66
|
-
isShared: true,
|
|
67
|
-
viewStyle: 'board',
|
|
68
|
-
}),
|
|
69
|
-
],
|
|
49
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
50
|
+
// Verify structured content
|
|
51
|
+
const structuredContent = extractStructuredContent(result);
|
|
52
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
53
|
+
projects: expect.any(Array),
|
|
54
|
+
totalCount: 3,
|
|
55
|
+
hasMore: false,
|
|
70
56
|
nextCursor: null,
|
|
71
|
-
|
|
57
|
+
appliedFilters: {
|
|
58
|
+
search: undefined,
|
|
59
|
+
limit: 50,
|
|
60
|
+
cursor: undefined,
|
|
61
|
+
},
|
|
62
|
+
}));
|
|
63
|
+
expect(structuredContent.projects).toHaveLength(3);
|
|
72
64
|
});
|
|
73
65
|
it('should handle pagination with limit and cursor', async () => {
|
|
74
66
|
const mockProject = createMockProject({
|
|
@@ -77,14 +69,23 @@ describe('projects-list tool', () => {
|
|
|
77
69
|
color: 'red',
|
|
78
70
|
});
|
|
79
71
|
mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse([mockProject], 'next-page-cursor'));
|
|
80
|
-
const result = await
|
|
72
|
+
const result = await findProjects.execute({ limit: 10, cursor: 'current-page-cursor' }, mockTodoistApi);
|
|
81
73
|
expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({
|
|
82
74
|
limit: 10,
|
|
83
75
|
cursor: 'current-page-cursor',
|
|
84
76
|
});
|
|
85
|
-
expect(result
|
|
86
|
-
|
|
87
|
-
|
|
77
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
78
|
+
// Verify structured content
|
|
79
|
+
const structuredContent = extractStructuredContent(result);
|
|
80
|
+
expect(structuredContent.projects).toHaveLength(1);
|
|
81
|
+
expect(structuredContent.totalCount).toBe(1);
|
|
82
|
+
expect(structuredContent.hasMore).toBe(true);
|
|
83
|
+
expect(structuredContent.nextCursor).toBe('next-page-cursor');
|
|
84
|
+
expect(structuredContent.appliedFilters).toEqual({
|
|
85
|
+
search: undefined,
|
|
86
|
+
limit: 10,
|
|
87
|
+
cursor: 'current-page-cursor',
|
|
88
|
+
});
|
|
88
89
|
});
|
|
89
90
|
});
|
|
90
91
|
describe('searching projects', () => {
|
|
@@ -103,10 +104,20 @@ describe('projects-list tool', () => {
|
|
|
103
104
|
createMockProject({ id: 'hobby-project-id', name: 'Hobby Work', color: 'orange' }),
|
|
104
105
|
];
|
|
105
106
|
mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
|
|
106
|
-
const result = await
|
|
107
|
+
const result = await findProjects.execute({ search: 'work', limit: 50 }, mockTodoistApi);
|
|
107
108
|
expect(mockTodoistApi.getProjects).toHaveBeenCalledWith({ limit: 50, cursor: null });
|
|
108
|
-
expect(result
|
|
109
|
-
|
|
109
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
110
|
+
// Verify structured content with search filter
|
|
111
|
+
const structuredContent = extractStructuredContent(result);
|
|
112
|
+
expect(structuredContent.projects).toHaveLength(2); // Should match filtered results
|
|
113
|
+
expect(structuredContent.totalCount).toBe(2);
|
|
114
|
+
expect(structuredContent.hasMore).toBe(false);
|
|
115
|
+
expect(structuredContent.nextCursor).toBeNull();
|
|
116
|
+
expect(structuredContent.appliedFilters).toEqual({
|
|
117
|
+
search: 'work',
|
|
118
|
+
limit: 50,
|
|
119
|
+
cursor: undefined,
|
|
120
|
+
});
|
|
110
121
|
});
|
|
111
122
|
it.each([
|
|
112
123
|
{
|
|
@@ -121,11 +132,16 @@ describe('projects-list tool', () => {
|
|
|
121
132
|
expectedCount: 1,
|
|
122
133
|
description: 'case insensitive matching',
|
|
123
134
|
},
|
|
124
|
-
])('should handle search with $description', async ({ search, projects
|
|
135
|
+
])('should handle search with $description', async ({ search, projects }) => {
|
|
125
136
|
const mockProjects = projects.map((name) => createMockProject({ name }));
|
|
126
137
|
mockTodoistApi.getProjects.mockResolvedValue(createMockApiResponse(mockProjects));
|
|
127
|
-
const result = await
|
|
128
|
-
expect(result
|
|
138
|
+
const result = await findProjects.execute({ search, limit: 50 }, mockTodoistApi);
|
|
139
|
+
expect(extractTextContent(result)).toMatchSnapshot();
|
|
140
|
+
// Verify structured content
|
|
141
|
+
const structuredContent = extractStructuredContent(result);
|
|
142
|
+
expect(structuredContent).toEqual(expect.objectContaining({
|
|
143
|
+
appliedFilters: expect.objectContaining({ search }),
|
|
144
|
+
}));
|
|
129
145
|
});
|
|
130
146
|
});
|
|
131
147
|
describe('error handling', () => {
|
|
@@ -134,7 +150,7 @@ describe('projects-list tool', () => {
|
|
|
134
150
|
{ error: TEST_ERRORS.INVALID_CURSOR, params: { cursor: 'invalid-cursor', limit: 50 } },
|
|
135
151
|
])('should propagate $error', async ({ error, params }) => {
|
|
136
152
|
mockTodoistApi.getProjects.mockRejectedValue(new Error(error));
|
|
137
|
-
await expect(
|
|
153
|
+
await expect(findProjects.execute(params, mockTodoistApi)).rejects.toThrow(error);
|
|
138
154
|
});
|
|
139
155
|
});
|
|
140
156
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-sections.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-sections.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jest } from '@jest/globals';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TEST_ERRORS, TEST_IDS, createMockSection, extractStructuredContent, extractTextContent, } from '../../utils/test-helpers.js';
|
|
3
|
+
import { ToolNames } from '../../utils/tool-names.js';
|
|
4
|
+
import { findSections } from '../find-sections.js';
|
|
4
5
|
// Mock the Todoist API
|
|
5
6
|
const mockTodoistApi = {
|
|
6
7
|
getSections: jest.fn(),
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
+
const { FIND_SECTIONS, ADD_SECTIONS } = ToolNames;
|
|
10
|
+
describe(`${FIND_SECTIONS} tool`, () => {
|
|
9
11
|
beforeEach(() => {
|
|
10
12
|
jest.clearAllMocks();
|
|
11
13
|
});
|
|
@@ -40,29 +42,47 @@ describe('sections-search tool', () => {
|
|
|
40
42
|
results: mockSections,
|
|
41
43
|
nextCursor: null,
|
|
42
44
|
});
|
|
43
|
-
const result = await
|
|
44
|
-
// Verify API was called correctly
|
|
45
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST }, mockTodoistApi);
|
|
45
46
|
expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
|
|
46
47
|
projectId: TEST_IDS.PROJECT_TEST,
|
|
47
48
|
});
|
|
48
|
-
|
|
49
|
-
expect(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
const textContent = extractTextContent(result);
|
|
50
|
+
expect(textContent).toMatchSnapshot();
|
|
51
|
+
expect(textContent).toContain('Sections in project');
|
|
52
|
+
expect(textContent).toContain('To Do • id=');
|
|
53
|
+
expect(textContent).toContain('In Progress • id=');
|
|
54
|
+
expect(textContent).toContain('Done • id=');
|
|
55
|
+
expect(textContent).toContain('Backlog Items • id=');
|
|
56
|
+
// Verify structured content
|
|
57
|
+
const structuredContent = extractStructuredContent(result);
|
|
58
|
+
expect(structuredContent.sections).toHaveLength(4);
|
|
59
|
+
expect(structuredContent.totalCount).toBe(4);
|
|
60
|
+
expect(structuredContent.appliedFilters).toEqual({
|
|
61
|
+
projectId: TEST_IDS.PROJECT_TEST,
|
|
62
|
+
search: undefined,
|
|
63
|
+
});
|
|
55
64
|
});
|
|
56
65
|
it('should handle project with no sections', async () => {
|
|
57
66
|
mockTodoistApi.getSections.mockResolvedValue({
|
|
58
67
|
results: [],
|
|
59
68
|
nextCursor: null,
|
|
60
69
|
});
|
|
61
|
-
const result = await
|
|
70
|
+
const result = await findSections.execute({ projectId: 'empty-project-id' }, mockTodoistApi);
|
|
62
71
|
expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
|
|
63
72
|
projectId: 'empty-project-id',
|
|
64
73
|
});
|
|
65
|
-
|
|
74
|
+
const textContent = extractTextContent(result);
|
|
75
|
+
expect(textContent).toMatchSnapshot();
|
|
76
|
+
expect(textContent).toContain('Project has no sections yet');
|
|
77
|
+
expect(textContent).toContain(`Use ${ADD_SECTIONS} to create sections`);
|
|
78
|
+
// Verify structured content
|
|
79
|
+
const structuredContent = extractStructuredContent(result);
|
|
80
|
+
expect(structuredContent.sections).toHaveLength(0);
|
|
81
|
+
expect(structuredContent.totalCount).toBe(0);
|
|
82
|
+
expect(structuredContent.appliedFilters).toEqual({
|
|
83
|
+
projectId: 'empty-project-id',
|
|
84
|
+
search: undefined,
|
|
85
|
+
});
|
|
66
86
|
});
|
|
67
87
|
});
|
|
68
88
|
describe('searching sections by name', () => {
|
|
@@ -96,18 +116,16 @@ describe('sections-search tool', () => {
|
|
|
96
116
|
results: mockSections,
|
|
97
117
|
nextCursor: null,
|
|
98
118
|
});
|
|
99
|
-
const result = await
|
|
100
|
-
projectId: TEST_IDS.PROJECT_TEST,
|
|
101
|
-
search: 'progress',
|
|
102
|
-
}, mockTodoistApi);
|
|
119
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'progress' }, mockTodoistApi);
|
|
103
120
|
expect(mockTodoistApi.getSections).toHaveBeenCalledWith({
|
|
104
121
|
projectId: TEST_IDS.PROJECT_TEST,
|
|
105
122
|
});
|
|
106
123
|
// Should return both "In Progress" and "Progress Review" (case insensitive partial match)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
124
|
+
const textContent = extractTextContent(result);
|
|
125
|
+
expect(textContent).toMatchSnapshot();
|
|
126
|
+
expect(textContent).toContain('matching "progress"');
|
|
127
|
+
expect(textContent).toContain('In Progress • id=');
|
|
128
|
+
expect(textContent).toContain('Progress Review • id=');
|
|
111
129
|
});
|
|
112
130
|
it('should handle search with no matches', async () => {
|
|
113
131
|
const mockSections = [
|
|
@@ -127,11 +145,12 @@ describe('sections-search tool', () => {
|
|
|
127
145
|
results: mockSections,
|
|
128
146
|
nextCursor: null,
|
|
129
147
|
});
|
|
130
|
-
const result = await
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
expect(
|
|
148
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'nonexistent' }, mockTodoistApi);
|
|
149
|
+
const textContent = extractTextContent(result);
|
|
150
|
+
expect(textContent).toMatchSnapshot();
|
|
151
|
+
expect(textContent).toContain('Try broader search terms');
|
|
152
|
+
expect(textContent).toContain('Check spelling');
|
|
153
|
+
expect(textContent).toContain('Remove search to see all sections');
|
|
135
154
|
});
|
|
136
155
|
it('should handle case sensitive search correctly', async () => {
|
|
137
156
|
const mockSections = [
|
|
@@ -151,13 +170,12 @@ describe('sections-search tool', () => {
|
|
|
151
170
|
results: mockSections,
|
|
152
171
|
nextCursor: null,
|
|
153
172
|
});
|
|
154
|
-
const result = await
|
|
155
|
-
projectId: TEST_IDS.PROJECT_TEST,
|
|
156
|
-
search: 'IMPORTANT',
|
|
157
|
-
}, mockTodoistApi);
|
|
173
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'IMPORTANT' }, mockTodoistApi);
|
|
158
174
|
// Should match despite different case
|
|
159
|
-
|
|
160
|
-
expect(
|
|
175
|
+
const textContent = extractTextContent(result);
|
|
176
|
+
expect(textContent).toMatchSnapshot();
|
|
177
|
+
expect(textContent).toContain('matching "IMPORTANT"');
|
|
178
|
+
expect(textContent).toContain('Important Tasks • id=');
|
|
161
179
|
});
|
|
162
180
|
it('should handle partial matches correctly', async () => {
|
|
163
181
|
const mockSections = [
|
|
@@ -183,15 +201,13 @@ describe('sections-search tool', () => {
|
|
|
183
201
|
results: mockSections,
|
|
184
202
|
nextCursor: null,
|
|
185
203
|
});
|
|
186
|
-
const result = await
|
|
187
|
-
projectId: TEST_IDS.PROJECT_TEST,
|
|
188
|
-
search: 'task',
|
|
189
|
-
}, mockTodoistApi);
|
|
204
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'task' }, mockTodoistApi);
|
|
190
205
|
// Should match both sections with "task" in the name
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
const textContent = extractTextContent(result);
|
|
207
|
+
expect(textContent).toMatchSnapshot();
|
|
208
|
+
expect(textContent).toContain('matching "task"');
|
|
209
|
+
expect(textContent).toContain('Development Tasks • id=');
|
|
210
|
+
expect(textContent).toContain('Testing Tasks • id=');
|
|
195
211
|
});
|
|
196
212
|
it('should handle exact matches', async () => {
|
|
197
213
|
const mockSections = [
|
|
@@ -211,15 +227,13 @@ describe('sections-search tool', () => {
|
|
|
211
227
|
results: mockSections,
|
|
212
228
|
nextCursor: null,
|
|
213
229
|
});
|
|
214
|
-
const result = await
|
|
215
|
-
projectId: TEST_IDS.PROJECT_TEST,
|
|
216
|
-
search: 'done',
|
|
217
|
-
}, mockTodoistApi);
|
|
230
|
+
const result = await findSections.execute({ projectId: TEST_IDS.PROJECT_TEST, search: 'done' }, mockTodoistApi);
|
|
218
231
|
// Should match both sections containing "done"
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
const textContent = extractTextContent(result);
|
|
233
|
+
expect(textContent).toMatchSnapshot();
|
|
234
|
+
expect(textContent).toContain('matching "done"');
|
|
235
|
+
expect(textContent).toContain('Done • id=');
|
|
236
|
+
expect(textContent).toContain('Done Soon • id=');
|
|
223
237
|
});
|
|
224
238
|
});
|
|
225
239
|
describe('error handling', () => {
|
|
@@ -229,7 +243,7 @@ describe('sections-search tool', () => {
|
|
|
229
243
|
{ error: 'API Error: Invalid project ID format', projectId: 'invalid-id-format' },
|
|
230
244
|
])('should propagate $error', async ({ error, projectId }) => {
|
|
231
245
|
mockTodoistApi.getSections.mockRejectedValue(new Error(error));
|
|
232
|
-
await expect(
|
|
246
|
+
await expect(findSections.execute({ projectId }, mockTodoistApi)).rejects.toThrow(error);
|
|
233
247
|
});
|
|
234
248
|
});
|
|
235
249
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-tasks-by-date.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/find-tasks-by-date.test.ts"],"names":[],"mappings":""}
|