@vibescope/mcp-server 0.2.5 → 0.2.7
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/CHANGELOG.md +84 -84
- package/README.md +194 -194
- package/dist/cli.js +26 -26
- package/dist/handlers/tool-docs.js +828 -828
- package/dist/index.js +73 -73
- package/dist/templates/agent-guidelines.js +185 -185
- package/dist/token-tracking.js +4 -2
- package/dist/tools.js +65 -65
- package/dist/utils.js +11 -11
- package/docs/TOOLS.md +2053 -2053
- package/package.json +3 -2
- package/scripts/generate-docs.ts +212 -212
- package/scripts/version-bump.ts +203 -203
- package/src/api-client.test.ts +723 -723
- package/src/api-client.ts +2499 -2499
- package/src/cli.ts +212 -212
- package/src/handlers/__test-setup__.ts +236 -236
- package/src/handlers/__test-utils__.ts +87 -87
- package/src/handlers/blockers.test.ts +468 -468
- package/src/handlers/blockers.ts +163 -163
- package/src/handlers/bodies-of-work.test.ts +704 -704
- package/src/handlers/bodies-of-work.ts +526 -526
- package/src/handlers/connectors.test.ts +834 -834
- package/src/handlers/connectors.ts +229 -229
- package/src/handlers/cost.test.ts +462 -462
- package/src/handlers/cost.ts +285 -285
- package/src/handlers/decisions.test.ts +382 -382
- package/src/handlers/decisions.ts +153 -153
- package/src/handlers/deployment.test.ts +551 -551
- package/src/handlers/deployment.ts +541 -541
- package/src/handlers/discovery.test.ts +206 -206
- package/src/handlers/discovery.ts +390 -390
- package/src/handlers/fallback.test.ts +537 -537
- package/src/handlers/fallback.ts +194 -194
- package/src/handlers/file-checkouts.test.ts +750 -750
- package/src/handlers/file-checkouts.ts +185 -185
- package/src/handlers/findings.test.ts +633 -633
- package/src/handlers/findings.ts +239 -239
- package/src/handlers/git-issues.test.ts +631 -631
- package/src/handlers/git-issues.ts +136 -136
- package/src/handlers/ideas.test.ts +644 -644
- package/src/handlers/ideas.ts +207 -207
- package/src/handlers/index.ts +84 -84
- package/src/handlers/milestones.test.ts +475 -475
- package/src/handlers/milestones.ts +180 -180
- package/src/handlers/organizations.test.ts +826 -826
- package/src/handlers/organizations.ts +315 -315
- package/src/handlers/progress.test.ts +269 -269
- package/src/handlers/progress.ts +77 -77
- package/src/handlers/project.test.ts +546 -546
- package/src/handlers/project.ts +239 -239
- package/src/handlers/requests.test.ts +303 -303
- package/src/handlers/requests.ts +99 -99
- package/src/handlers/roles.test.ts +303 -303
- package/src/handlers/roles.ts +226 -226
- package/src/handlers/session.test.ts +875 -875
- package/src/handlers/session.ts +738 -738
- package/src/handlers/sprints.test.ts +732 -732
- package/src/handlers/sprints.ts +537 -537
- package/src/handlers/tasks.test.ts +907 -907
- package/src/handlers/tasks.ts +945 -945
- package/src/handlers/tool-categories.test.ts +66 -66
- package/src/handlers/tool-docs.ts +1096 -1096
- package/src/handlers/types.test.ts +259 -259
- package/src/handlers/types.ts +175 -175
- package/src/handlers/validation.test.ts +582 -582
- package/src/handlers/validation.ts +97 -97
- package/src/index.ts +792 -792
- package/src/setup.test.ts +233 -231
- package/src/setup.ts +370 -370
- package/src/templates/agent-guidelines.ts +210 -210
- package/src/token-tracking.test.ts +463 -453
- package/src/token-tracking.ts +166 -164
- package/src/tools.ts +3562 -3562
- package/src/utils.test.ts +683 -683
- package/src/utils.ts +436 -436
- package/src/validators.test.ts +223 -223
- package/src/validators.ts +249 -249
- package/tsconfig.json +16 -16
- package/vitest.config.ts +14 -14
- package/dist/knowledge.d.ts +0 -6
- package/dist/knowledge.js +0 -218
|
@@ -1,269 +1,269 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { logProgress, getActivityFeed } from './progress.js';
|
|
3
|
-
import { ValidationError } from '../validators.js';
|
|
4
|
-
import { createMockContext } from './__test-utils__.js';
|
|
5
|
-
import { mockApiClient } from './__test-setup__.js';
|
|
6
|
-
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// logProgress Tests
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
describe('logProgress', () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.clearAllMocks();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should log progress successfully', async () => {
|
|
17
|
-
mockApiClient.logProgress.mockResolvedValue({
|
|
18
|
-
ok: true,
|
|
19
|
-
data: { progress_id: 'prog-123' },
|
|
20
|
-
});
|
|
21
|
-
const ctx = createMockContext();
|
|
22
|
-
|
|
23
|
-
const result = await logProgress(
|
|
24
|
-
{
|
|
25
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
26
|
-
summary: 'Completed initial setup',
|
|
27
|
-
},
|
|
28
|
-
ctx
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
expect(result.result).toMatchObject({
|
|
32
|
-
success: true,
|
|
33
|
-
progress_id: 'prog-123',
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should log progress with task_id and details', async () => {
|
|
38
|
-
mockApiClient.logProgress.mockResolvedValue({
|
|
39
|
-
ok: true,
|
|
40
|
-
data: { progress_id: 'prog-456' },
|
|
41
|
-
});
|
|
42
|
-
const ctx = createMockContext();
|
|
43
|
-
|
|
44
|
-
await logProgress(
|
|
45
|
-
{
|
|
46
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
47
|
-
task_id: '456e4567-e89b-12d3-a456-426614174000',
|
|
48
|
-
summary: 'Working on feature',
|
|
49
|
-
details: 'Added the main component and started styling',
|
|
50
|
-
},
|
|
51
|
-
ctx
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
expect(mockApiClient.logProgress).toHaveBeenCalledWith(
|
|
55
|
-
'123e4567-e89b-12d3-a456-426614174000',
|
|
56
|
-
{
|
|
57
|
-
summary: 'Working on feature',
|
|
58
|
-
details: 'Added the main component and started styling',
|
|
59
|
-
task_id: '456e4567-e89b-12d3-a456-426614174000',
|
|
60
|
-
session_id: 'session-123',
|
|
61
|
-
}
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should include session_id in request', async () => {
|
|
66
|
-
mockApiClient.logProgress.mockResolvedValue({
|
|
67
|
-
ok: true,
|
|
68
|
-
data: { progress_id: 'prog-789' },
|
|
69
|
-
});
|
|
70
|
-
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
71
|
-
|
|
72
|
-
await logProgress(
|
|
73
|
-
{
|
|
74
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
75
|
-
summary: 'Progress update',
|
|
76
|
-
},
|
|
77
|
-
ctx
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
expect(mockApiClient.logProgress).toHaveBeenCalledWith(
|
|
81
|
-
'123e4567-e89b-12d3-a456-426614174000',
|
|
82
|
-
expect.objectContaining({
|
|
83
|
-
session_id: 'my-session',
|
|
84
|
-
})
|
|
85
|
-
);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('should call API client logProgress', async () => {
|
|
89
|
-
mockApiClient.logProgress.mockResolvedValue({
|
|
90
|
-
ok: true,
|
|
91
|
-
data: { progress_id: 'prog-abc' },
|
|
92
|
-
});
|
|
93
|
-
const ctx = createMockContext();
|
|
94
|
-
|
|
95
|
-
await logProgress(
|
|
96
|
-
{
|
|
97
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
98
|
-
summary: 'Progress',
|
|
99
|
-
},
|
|
100
|
-
ctx
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
expect(mockApiClient.logProgress).toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should return error when API call fails', async () => {
|
|
107
|
-
mockApiClient.logProgress.mockResolvedValue({
|
|
108
|
-
ok: false,
|
|
109
|
-
error: 'Insert failed',
|
|
110
|
-
});
|
|
111
|
-
const ctx = createMockContext();
|
|
112
|
-
|
|
113
|
-
const result = await logProgress({
|
|
114
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
115
|
-
summary: 'Progress',
|
|
116
|
-
}, ctx);
|
|
117
|
-
|
|
118
|
-
expect(result.isError).toBe(true);
|
|
119
|
-
expect(result.result).toMatchObject({
|
|
120
|
-
error: 'Insert failed',
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('should throw error for missing project_id', async () => {
|
|
125
|
-
const ctx = createMockContext();
|
|
126
|
-
|
|
127
|
-
await expect(
|
|
128
|
-
logProgress({ summary: 'Progress' }, ctx)
|
|
129
|
-
).rejects.toThrow(ValidationError);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('should throw error for invalid project_id UUID', async () => {
|
|
133
|
-
const ctx = createMockContext();
|
|
134
|
-
|
|
135
|
-
await expect(
|
|
136
|
-
logProgress({ project_id: 'invalid', summary: 'Progress' }, ctx)
|
|
137
|
-
).rejects.toThrow(ValidationError);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('should throw error for missing summary', async () => {
|
|
141
|
-
const ctx = createMockContext();
|
|
142
|
-
|
|
143
|
-
await expect(
|
|
144
|
-
logProgress({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
145
|
-
).rejects.toThrow(ValidationError);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// ============================================================================
|
|
150
|
-
// getActivityFeed Tests
|
|
151
|
-
// ============================================================================
|
|
152
|
-
|
|
153
|
-
describe('getActivityFeed', () => {
|
|
154
|
-
beforeEach(() => {
|
|
155
|
-
vi.clearAllMocks();
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should throw error for missing project_id', async () => {
|
|
159
|
-
const ctx = createMockContext();
|
|
160
|
-
|
|
161
|
-
await expect(getActivityFeed({}, ctx)).rejects.toThrow(ValidationError);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should throw error for invalid project_id UUID', async () => {
|
|
165
|
-
const ctx = createMockContext();
|
|
166
|
-
|
|
167
|
-
await expect(
|
|
168
|
-
getActivityFeed({ project_id: 'invalid' }, ctx)
|
|
169
|
-
).rejects.toThrow(ValidationError);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('should return empty activities when no data', async () => {
|
|
173
|
-
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
174
|
-
ok: true,
|
|
175
|
-
data: { activities: [] },
|
|
176
|
-
});
|
|
177
|
-
const ctx = createMockContext();
|
|
178
|
-
|
|
179
|
-
const result = await getActivityFeed(
|
|
180
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
181
|
-
ctx
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
expect(result.result).toMatchObject({
|
|
185
|
-
activities: [],
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('should return activities from API', async () => {
|
|
190
|
-
const mockActivities = [
|
|
191
|
-
{ id: 'a1', type: 'task', created_at: '2025-01-14T10:00:00Z' },
|
|
192
|
-
{ id: 'a2', type: 'progress', created_at: '2025-01-14T11:00:00Z' },
|
|
193
|
-
];
|
|
194
|
-
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
195
|
-
ok: true,
|
|
196
|
-
data: { activities: mockActivities },
|
|
197
|
-
});
|
|
198
|
-
const ctx = createMockContext();
|
|
199
|
-
|
|
200
|
-
const result = await getActivityFeed(
|
|
201
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
202
|
-
ctx
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
expect(result.result).toMatchObject({
|
|
206
|
-
activities: mockActivities,
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('should pass limit parameter to API', async () => {
|
|
211
|
-
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
212
|
-
ok: true,
|
|
213
|
-
data: { activities: [] },
|
|
214
|
-
});
|
|
215
|
-
const ctx = createMockContext();
|
|
216
|
-
|
|
217
|
-
await getActivityFeed(
|
|
218
|
-
{
|
|
219
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
220
|
-
limit: 10,
|
|
221
|
-
},
|
|
222
|
-
ctx
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
expect(mockApiClient.getActivityFeed).toHaveBeenCalledWith(
|
|
226
|
-
'123e4567-e89b-12d3-a456-426614174000',
|
|
227
|
-
expect.objectContaining({ limit: 10 })
|
|
228
|
-
);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('should cap limit at 200', async () => {
|
|
232
|
-
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
233
|
-
ok: true,
|
|
234
|
-
data: { activities: [] },
|
|
235
|
-
});
|
|
236
|
-
const ctx = createMockContext();
|
|
237
|
-
|
|
238
|
-
await getActivityFeed(
|
|
239
|
-
{
|
|
240
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
241
|
-
limit: 500,
|
|
242
|
-
},
|
|
243
|
-
ctx
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
expect(mockApiClient.getActivityFeed).toHaveBeenCalledWith(
|
|
247
|
-
'123e4567-e89b-12d3-a456-426614174000',
|
|
248
|
-
expect.objectContaining({ limit: 200 })
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it('should return error when API call fails', async () => {
|
|
253
|
-
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
254
|
-
ok: false,
|
|
255
|
-
error: 'Query failed',
|
|
256
|
-
});
|
|
257
|
-
const ctx = createMockContext();
|
|
258
|
-
|
|
259
|
-
const result = await getActivityFeed(
|
|
260
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
261
|
-
ctx
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
expect(result.isError).toBe(true);
|
|
265
|
-
expect(result.result).toMatchObject({
|
|
266
|
-
error: 'Query failed',
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { logProgress, getActivityFeed } from './progress.js';
|
|
3
|
+
import { ValidationError } from '../validators.js';
|
|
4
|
+
import { createMockContext } from './__test-utils__.js';
|
|
5
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// logProgress Tests
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
describe('logProgress', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should log progress successfully', async () => {
|
|
17
|
+
mockApiClient.logProgress.mockResolvedValue({
|
|
18
|
+
ok: true,
|
|
19
|
+
data: { progress_id: 'prog-123' },
|
|
20
|
+
});
|
|
21
|
+
const ctx = createMockContext();
|
|
22
|
+
|
|
23
|
+
const result = await logProgress(
|
|
24
|
+
{
|
|
25
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
26
|
+
summary: 'Completed initial setup',
|
|
27
|
+
},
|
|
28
|
+
ctx
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(result.result).toMatchObject({
|
|
32
|
+
success: true,
|
|
33
|
+
progress_id: 'prog-123',
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should log progress with task_id and details', async () => {
|
|
38
|
+
mockApiClient.logProgress.mockResolvedValue({
|
|
39
|
+
ok: true,
|
|
40
|
+
data: { progress_id: 'prog-456' },
|
|
41
|
+
});
|
|
42
|
+
const ctx = createMockContext();
|
|
43
|
+
|
|
44
|
+
await logProgress(
|
|
45
|
+
{
|
|
46
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
47
|
+
task_id: '456e4567-e89b-12d3-a456-426614174000',
|
|
48
|
+
summary: 'Working on feature',
|
|
49
|
+
details: 'Added the main component and started styling',
|
|
50
|
+
},
|
|
51
|
+
ctx
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(mockApiClient.logProgress).toHaveBeenCalledWith(
|
|
55
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
56
|
+
{
|
|
57
|
+
summary: 'Working on feature',
|
|
58
|
+
details: 'Added the main component and started styling',
|
|
59
|
+
task_id: '456e4567-e89b-12d3-a456-426614174000',
|
|
60
|
+
session_id: 'session-123',
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should include session_id in request', async () => {
|
|
66
|
+
mockApiClient.logProgress.mockResolvedValue({
|
|
67
|
+
ok: true,
|
|
68
|
+
data: { progress_id: 'prog-789' },
|
|
69
|
+
});
|
|
70
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
71
|
+
|
|
72
|
+
await logProgress(
|
|
73
|
+
{
|
|
74
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
75
|
+
summary: 'Progress update',
|
|
76
|
+
},
|
|
77
|
+
ctx
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(mockApiClient.logProgress).toHaveBeenCalledWith(
|
|
81
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
82
|
+
expect.objectContaining({
|
|
83
|
+
session_id: 'my-session',
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should call API client logProgress', async () => {
|
|
89
|
+
mockApiClient.logProgress.mockResolvedValue({
|
|
90
|
+
ok: true,
|
|
91
|
+
data: { progress_id: 'prog-abc' },
|
|
92
|
+
});
|
|
93
|
+
const ctx = createMockContext();
|
|
94
|
+
|
|
95
|
+
await logProgress(
|
|
96
|
+
{
|
|
97
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
98
|
+
summary: 'Progress',
|
|
99
|
+
},
|
|
100
|
+
ctx
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(mockApiClient.logProgress).toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should return error when API call fails', async () => {
|
|
107
|
+
mockApiClient.logProgress.mockResolvedValue({
|
|
108
|
+
ok: false,
|
|
109
|
+
error: 'Insert failed',
|
|
110
|
+
});
|
|
111
|
+
const ctx = createMockContext();
|
|
112
|
+
|
|
113
|
+
const result = await logProgress({
|
|
114
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
115
|
+
summary: 'Progress',
|
|
116
|
+
}, ctx);
|
|
117
|
+
|
|
118
|
+
expect(result.isError).toBe(true);
|
|
119
|
+
expect(result.result).toMatchObject({
|
|
120
|
+
error: 'Insert failed',
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should throw error for missing project_id', async () => {
|
|
125
|
+
const ctx = createMockContext();
|
|
126
|
+
|
|
127
|
+
await expect(
|
|
128
|
+
logProgress({ summary: 'Progress' }, ctx)
|
|
129
|
+
).rejects.toThrow(ValidationError);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should throw error for invalid project_id UUID', async () => {
|
|
133
|
+
const ctx = createMockContext();
|
|
134
|
+
|
|
135
|
+
await expect(
|
|
136
|
+
logProgress({ project_id: 'invalid', summary: 'Progress' }, ctx)
|
|
137
|
+
).rejects.toThrow(ValidationError);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should throw error for missing summary', async () => {
|
|
141
|
+
const ctx = createMockContext();
|
|
142
|
+
|
|
143
|
+
await expect(
|
|
144
|
+
logProgress({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
145
|
+
).rejects.toThrow(ValidationError);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// getActivityFeed Tests
|
|
151
|
+
// ============================================================================
|
|
152
|
+
|
|
153
|
+
describe('getActivityFeed', () => {
|
|
154
|
+
beforeEach(() => {
|
|
155
|
+
vi.clearAllMocks();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw error for missing project_id', async () => {
|
|
159
|
+
const ctx = createMockContext();
|
|
160
|
+
|
|
161
|
+
await expect(getActivityFeed({}, ctx)).rejects.toThrow(ValidationError);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should throw error for invalid project_id UUID', async () => {
|
|
165
|
+
const ctx = createMockContext();
|
|
166
|
+
|
|
167
|
+
await expect(
|
|
168
|
+
getActivityFeed({ project_id: 'invalid' }, ctx)
|
|
169
|
+
).rejects.toThrow(ValidationError);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should return empty activities when no data', async () => {
|
|
173
|
+
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
174
|
+
ok: true,
|
|
175
|
+
data: { activities: [] },
|
|
176
|
+
});
|
|
177
|
+
const ctx = createMockContext();
|
|
178
|
+
|
|
179
|
+
const result = await getActivityFeed(
|
|
180
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
181
|
+
ctx
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(result.result).toMatchObject({
|
|
185
|
+
activities: [],
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should return activities from API', async () => {
|
|
190
|
+
const mockActivities = [
|
|
191
|
+
{ id: 'a1', type: 'task', created_at: '2025-01-14T10:00:00Z' },
|
|
192
|
+
{ id: 'a2', type: 'progress', created_at: '2025-01-14T11:00:00Z' },
|
|
193
|
+
];
|
|
194
|
+
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
195
|
+
ok: true,
|
|
196
|
+
data: { activities: mockActivities },
|
|
197
|
+
});
|
|
198
|
+
const ctx = createMockContext();
|
|
199
|
+
|
|
200
|
+
const result = await getActivityFeed(
|
|
201
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
202
|
+
ctx
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
expect(result.result).toMatchObject({
|
|
206
|
+
activities: mockActivities,
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should pass limit parameter to API', async () => {
|
|
211
|
+
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
212
|
+
ok: true,
|
|
213
|
+
data: { activities: [] },
|
|
214
|
+
});
|
|
215
|
+
const ctx = createMockContext();
|
|
216
|
+
|
|
217
|
+
await getActivityFeed(
|
|
218
|
+
{
|
|
219
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
220
|
+
limit: 10,
|
|
221
|
+
},
|
|
222
|
+
ctx
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
expect(mockApiClient.getActivityFeed).toHaveBeenCalledWith(
|
|
226
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
227
|
+
expect.objectContaining({ limit: 10 })
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should cap limit at 200', async () => {
|
|
232
|
+
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
233
|
+
ok: true,
|
|
234
|
+
data: { activities: [] },
|
|
235
|
+
});
|
|
236
|
+
const ctx = createMockContext();
|
|
237
|
+
|
|
238
|
+
await getActivityFeed(
|
|
239
|
+
{
|
|
240
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
241
|
+
limit: 500,
|
|
242
|
+
},
|
|
243
|
+
ctx
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect(mockApiClient.getActivityFeed).toHaveBeenCalledWith(
|
|
247
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
248
|
+
expect.objectContaining({ limit: 200 })
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should return error when API call fails', async () => {
|
|
253
|
+
mockApiClient.getActivityFeed.mockResolvedValue({
|
|
254
|
+
ok: false,
|
|
255
|
+
error: 'Query failed',
|
|
256
|
+
});
|
|
257
|
+
const ctx = createMockContext();
|
|
258
|
+
|
|
259
|
+
const result = await getActivityFeed(
|
|
260
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
261
|
+
ctx
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
expect(result.isError).toBe(true);
|
|
265
|
+
expect(result.result).toMatchObject({
|
|
266
|
+
error: 'Query failed',
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|