@vibescope/mcp-server 0.0.1 → 0.2.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 +113 -98
- package/dist/api-client.d.ts +1169 -0
- package/dist/api-client.js +713 -0
- package/dist/cli.d.ts +1 -6
- package/dist/cli.js +39 -240
- package/dist/config/tool-categories.d.ts +31 -0
- package/dist/config/tool-categories.js +253 -0
- package/dist/handlers/blockers.js +57 -58
- package/dist/handlers/bodies-of-work.d.ts +2 -0
- package/dist/handlers/bodies-of-work.js +108 -477
- package/dist/handlers/cost.d.ts +1 -0
- package/dist/handlers/cost.js +35 -113
- package/dist/handlers/decisions.d.ts +2 -0
- package/dist/handlers/decisions.js +28 -27
- package/dist/handlers/deployment.js +113 -828
- package/dist/handlers/discovery.d.ts +3 -0
- package/dist/handlers/discovery.js +26 -627
- package/dist/handlers/fallback.d.ts +2 -0
- package/dist/handlers/fallback.js +56 -142
- package/dist/handlers/findings.d.ts +8 -1
- package/dist/handlers/findings.js +65 -68
- package/dist/handlers/git-issues.d.ts +9 -13
- package/dist/handlers/git-issues.js +80 -225
- package/dist/handlers/ideas.d.ts +3 -0
- package/dist/handlers/ideas.js +53 -134
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +6 -0
- package/dist/handlers/milestones.d.ts +2 -0
- package/dist/handlers/milestones.js +51 -98
- package/dist/handlers/organizations.js +79 -275
- package/dist/handlers/progress.d.ts +2 -0
- package/dist/handlers/progress.js +25 -123
- package/dist/handlers/project.js +42 -221
- package/dist/handlers/requests.d.ts +2 -0
- package/dist/handlers/requests.js +23 -83
- package/dist/handlers/session.js +119 -590
- package/dist/handlers/sprints.d.ts +32 -0
- package/dist/handlers/sprints.js +275 -0
- package/dist/handlers/tasks.d.ts +7 -10
- package/dist/handlers/tasks.js +245 -894
- package/dist/handlers/tool-docs.d.ts +9 -0
- package/dist/handlers/tool-docs.js +904 -0
- package/dist/handlers/types.d.ts +11 -3
- package/dist/handlers/validation.d.ts +1 -1
- package/dist/handlers/validation.js +38 -153
- package/dist/index.js +493 -162
- package/dist/knowledge.js +106 -9
- package/dist/tools.js +34 -4
- package/dist/validators.d.ts +21 -0
- package/dist/validators.js +91 -0
- package/package.json +2 -3
- package/src/api-client.ts +1822 -0
- package/src/cli.test.ts +128 -302
- package/src/cli.ts +41 -285
- package/src/handlers/__test-setup__.ts +215 -0
- package/src/handlers/__test-utils__.ts +4 -134
- package/src/handlers/blockers.test.ts +114 -124
- package/src/handlers/blockers.ts +68 -70
- package/src/handlers/bodies-of-work.test.ts +236 -831
- package/src/handlers/bodies-of-work.ts +210 -525
- package/src/handlers/cost.test.ts +149 -113
- package/src/handlers/cost.ts +44 -132
- package/src/handlers/decisions.test.ts +111 -209
- package/src/handlers/decisions.ts +35 -27
- package/src/handlers/deployment.test.ts +193 -239
- package/src/handlers/deployment.ts +143 -896
- package/src/handlers/discovery.test.ts +20 -67
- package/src/handlers/discovery.ts +29 -714
- package/src/handlers/fallback.test.ts +206 -361
- package/src/handlers/fallback.ts +81 -156
- package/src/handlers/findings.test.ts +229 -320
- package/src/handlers/findings.ts +76 -64
- package/src/handlers/git-issues.test.ts +623 -0
- package/src/handlers/git-issues.ts +174 -0
- package/src/handlers/ideas.test.ts +229 -343
- package/src/handlers/ideas.ts +69 -143
- package/src/handlers/index.ts +6 -0
- package/src/handlers/milestones.test.ts +167 -281
- package/src/handlers/milestones.ts +54 -93
- package/src/handlers/organizations.test.ts +275 -467
- package/src/handlers/organizations.ts +84 -294
- package/src/handlers/progress.test.ts +112 -218
- package/src/handlers/progress.ts +29 -142
- package/src/handlers/project.test.ts +203 -226
- package/src/handlers/project.ts +48 -238
- package/src/handlers/requests.test.ts +74 -342
- package/src/handlers/requests.ts +25 -83
- package/src/handlers/session.test.ts +276 -206
- package/src/handlers/session.ts +136 -662
- package/src/handlers/sprints.test.ts +711 -0
- package/src/handlers/sprints.ts +510 -0
- package/src/handlers/tasks.test.ts +669 -353
- package/src/handlers/tasks.ts +263 -1015
- package/src/handlers/tool-docs.ts +1024 -0
- package/src/handlers/types.ts +12 -4
- package/src/handlers/validation.test.ts +237 -568
- package/src/handlers/validation.ts +43 -167
- package/src/index.ts +493 -186
- package/src/tools.ts +2532 -0
- package/src/validators.test.ts +223 -223
- package/src/validators.ts +127 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +14 -13
- package/dist/cli.test.d.ts +0 -1
- package/dist/cli.test.js +0 -367
- package/dist/handlers/__test-utils__.d.ts +0 -72
- package/dist/handlers/__test-utils__.js +0 -176
- package/dist/handlers/checkouts.d.ts +0 -37
- package/dist/handlers/checkouts.js +0 -377
- package/dist/handlers/knowledge-query.d.ts +0 -22
- package/dist/handlers/knowledge-query.js +0 -253
- package/dist/handlers/knowledge.d.ts +0 -12
- package/dist/handlers/knowledge.js +0 -108
- package/dist/handlers/roles.d.ts +0 -30
- package/dist/handlers/roles.js +0 -281
- package/dist/handlers/tasks.test.d.ts +0 -1
- package/dist/handlers/tasks.test.js +0 -431
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -532
- package/dist/validators.test.d.ts +0 -1
- package/dist/validators.test.js +0 -176
- package/src/knowledge.ts +0 -132
- package/src/tmpclaude-0078-cwd +0 -1
- package/src/tmpclaude-0ee1-cwd +0 -1
- package/src/tmpclaude-2dd5-cwd +0 -1
- package/src/tmpclaude-344c-cwd +0 -1
- package/src/tmpclaude-3860-cwd +0 -1
- package/src/tmpclaude-4b63-cwd +0 -1
- package/src/tmpclaude-5c73-cwd +0 -1
- package/src/tmpclaude-5ee3-cwd +0 -1
- package/src/tmpclaude-6795-cwd +0 -1
- package/src/tmpclaude-709e-cwd +0 -1
- package/src/tmpclaude-9839-cwd +0 -1
- package/src/tmpclaude-d829-cwd +0 -1
- package/src/tmpclaude-e072-cwd +0 -1
- package/src/tmpclaude-f6ee-cwd +0 -1
- package/tmpclaude-0439-cwd +0 -1
- package/tmpclaude-132f-cwd +0 -1
- package/tmpclaude-15bb-cwd +0 -1
- package/tmpclaude-165a-cwd +0 -1
- package/tmpclaude-1ba9-cwd +0 -1
- package/tmpclaude-21a3-cwd +0 -1
- package/tmpclaude-2a38-cwd +0 -1
- package/tmpclaude-2adf-cwd +0 -1
- package/tmpclaude-2f56-cwd +0 -1
- package/tmpclaude-3626-cwd +0 -1
- package/tmpclaude-3727-cwd +0 -1
- package/tmpclaude-40bc-cwd +0 -1
- package/tmpclaude-436f-cwd +0 -1
- package/tmpclaude-4783-cwd +0 -1
- package/tmpclaude-4b6d-cwd +0 -1
- package/tmpclaude-4ba4-cwd +0 -1
- package/tmpclaude-51e6-cwd +0 -1
- package/tmpclaude-5ecf-cwd +0 -1
- package/tmpclaude-6f97-cwd +0 -1
- package/tmpclaude-7fb2-cwd +0 -1
- package/tmpclaude-825c-cwd +0 -1
- package/tmpclaude-8baf-cwd +0 -1
- package/tmpclaude-8d9f-cwd +0 -1
- package/tmpclaude-975c-cwd +0 -1
- package/tmpclaude-9983-cwd +0 -1
- package/tmpclaude-a045-cwd +0 -1
- package/tmpclaude-ac4a-cwd +0 -1
- package/tmpclaude-b593-cwd +0 -1
- package/tmpclaude-b891-cwd +0 -1
- package/tmpclaude-c032-cwd +0 -1
- package/tmpclaude-cf43-cwd +0 -1
- package/tmpclaude-d040-cwd +0 -1
- package/tmpclaude-dcdd-cwd +0 -1
- package/tmpclaude-dcee-cwd +0 -1
- package/tmpclaude-e16b-cwd +0 -1
- package/tmpclaude-ecd2-cwd +0 -1
- package/tmpclaude-f48d-cwd +0 -1
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
3
|
-
import type { HandlerContext, TokenUsage } from './types.js';
|
|
4
2
|
import {
|
|
5
3
|
startFallbackActivity,
|
|
6
4
|
stopFallbackActivity,
|
|
@@ -8,118 +6,8 @@ import {
|
|
|
8
6
|
getActivitySchedules,
|
|
9
7
|
} from './fallback.js';
|
|
10
8
|
import { ValidationError } from '../validators.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// Test Utilities
|
|
14
|
-
// ============================================================================
|
|
15
|
-
|
|
16
|
-
function createMockSupabase(overrides: {
|
|
17
|
-
selectResult?: { data: unknown; error: unknown };
|
|
18
|
-
insertResult?: { data: unknown; error: unknown };
|
|
19
|
-
updateResult?: { data: unknown; error: unknown };
|
|
20
|
-
deleteResult?: { data: unknown; error: unknown };
|
|
21
|
-
} = {}) {
|
|
22
|
-
const defaultResult = { data: null, error: null };
|
|
23
|
-
let currentOperation = 'select';
|
|
24
|
-
let insertThenSelect = false;
|
|
25
|
-
|
|
26
|
-
const mock = {
|
|
27
|
-
from: vi.fn().mockReturnThis(),
|
|
28
|
-
select: vi.fn(() => {
|
|
29
|
-
if (currentOperation === 'insert') {
|
|
30
|
-
insertThenSelect = true;
|
|
31
|
-
} else {
|
|
32
|
-
currentOperation = 'select';
|
|
33
|
-
insertThenSelect = false;
|
|
34
|
-
}
|
|
35
|
-
return mock;
|
|
36
|
-
}),
|
|
37
|
-
insert: vi.fn(() => {
|
|
38
|
-
currentOperation = 'insert';
|
|
39
|
-
insertThenSelect = false;
|
|
40
|
-
return mock;
|
|
41
|
-
}),
|
|
42
|
-
update: vi.fn(() => {
|
|
43
|
-
currentOperation = 'update';
|
|
44
|
-
insertThenSelect = false;
|
|
45
|
-
return mock;
|
|
46
|
-
}),
|
|
47
|
-
delete: vi.fn(() => {
|
|
48
|
-
currentOperation = 'delete';
|
|
49
|
-
insertThenSelect = false;
|
|
50
|
-
return mock;
|
|
51
|
-
}),
|
|
52
|
-
eq: vi.fn().mockReturnThis(),
|
|
53
|
-
neq: vi.fn().mockReturnThis(),
|
|
54
|
-
in: vi.fn().mockReturnThis(),
|
|
55
|
-
is: vi.fn().mockReturnThis(),
|
|
56
|
-
not: vi.fn().mockReturnThis(),
|
|
57
|
-
or: vi.fn().mockReturnThis(),
|
|
58
|
-
gt: vi.fn().mockReturnThis(),
|
|
59
|
-
gte: vi.fn().mockReturnThis(),
|
|
60
|
-
lte: vi.fn().mockReturnThis(),
|
|
61
|
-
lt: vi.fn().mockReturnThis(),
|
|
62
|
-
order: vi.fn().mockReturnThis(),
|
|
63
|
-
limit: vi.fn().mockReturnThis(),
|
|
64
|
-
single: vi.fn(() => {
|
|
65
|
-
if (currentOperation === 'insert' || insertThenSelect) {
|
|
66
|
-
return Promise.resolve(overrides.insertResult ?? defaultResult);
|
|
67
|
-
}
|
|
68
|
-
if (currentOperation === 'select') {
|
|
69
|
-
return Promise.resolve(overrides.selectResult ?? defaultResult);
|
|
70
|
-
}
|
|
71
|
-
if (currentOperation === 'update') {
|
|
72
|
-
return Promise.resolve(overrides.updateResult ?? defaultResult);
|
|
73
|
-
}
|
|
74
|
-
return Promise.resolve(defaultResult);
|
|
75
|
-
}),
|
|
76
|
-
maybeSingle: vi.fn(() => {
|
|
77
|
-
return Promise.resolve(overrides.selectResult ?? defaultResult);
|
|
78
|
-
}),
|
|
79
|
-
then: vi.fn((resolve: (value: unknown) => void) => {
|
|
80
|
-
if (currentOperation === 'insert' || insertThenSelect) {
|
|
81
|
-
return Promise.resolve(overrides.insertResult ?? defaultResult).then(resolve);
|
|
82
|
-
}
|
|
83
|
-
if (currentOperation === 'select') {
|
|
84
|
-
return Promise.resolve(overrides.selectResult ?? defaultResult).then(resolve);
|
|
85
|
-
}
|
|
86
|
-
if (currentOperation === 'update') {
|
|
87
|
-
return Promise.resolve(overrides.updateResult ?? defaultResult).then(resolve);
|
|
88
|
-
}
|
|
89
|
-
if (currentOperation === 'delete') {
|
|
90
|
-
return Promise.resolve(overrides.deleteResult ?? defaultResult).then(resolve);
|
|
91
|
-
}
|
|
92
|
-
return Promise.resolve(defaultResult).then(resolve);
|
|
93
|
-
}),
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
return mock as unknown as SupabaseClient;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function createMockContext(
|
|
100
|
-
supabase: SupabaseClient,
|
|
101
|
-
options: { sessionId?: string | null } = {}
|
|
102
|
-
): HandlerContext {
|
|
103
|
-
const defaultTokenUsage: TokenUsage = {
|
|
104
|
-
callCount: 5,
|
|
105
|
-
totalTokens: 2500,
|
|
106
|
-
byTool: {},
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const sessionId = 'sessionId' in options ? options.sessionId : 'session-123';
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
supabase,
|
|
113
|
-
auth: { userId: 'user-123', apiKeyId: 'api-key-123' },
|
|
114
|
-
session: {
|
|
115
|
-
instanceId: 'instance-abc',
|
|
116
|
-
currentSessionId: sessionId,
|
|
117
|
-
currentPersona: 'Wave',
|
|
118
|
-
tokenUsage: defaultTokenUsage,
|
|
119
|
-
},
|
|
120
|
-
updateSession: vi.fn(),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
9
|
+
import { createMockContext } from './__test-utils__.js';
|
|
10
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
123
11
|
|
|
124
12
|
// ============================================================================
|
|
125
13
|
// startFallbackActivity Tests
|
|
@@ -129,8 +17,7 @@ describe('startFallbackActivity', () => {
|
|
|
129
17
|
beforeEach(() => vi.clearAllMocks());
|
|
130
18
|
|
|
131
19
|
it('should throw error for missing project_id', async () => {
|
|
132
|
-
const
|
|
133
|
-
const ctx = createMockContext(supabase);
|
|
20
|
+
const ctx = createMockContext();
|
|
134
21
|
|
|
135
22
|
await expect(
|
|
136
23
|
startFallbackActivity({ activity: 'code_review' }, ctx)
|
|
@@ -138,8 +25,7 @@ describe('startFallbackActivity', () => {
|
|
|
138
25
|
});
|
|
139
26
|
|
|
140
27
|
it('should throw error for invalid project_id UUID', async () => {
|
|
141
|
-
const
|
|
142
|
-
const ctx = createMockContext(supabase);
|
|
28
|
+
const ctx = createMockContext();
|
|
143
29
|
|
|
144
30
|
await expect(
|
|
145
31
|
startFallbackActivity({ project_id: 'invalid', activity: 'code_review' }, ctx)
|
|
@@ -147,8 +33,7 @@ describe('startFallbackActivity', () => {
|
|
|
147
33
|
});
|
|
148
34
|
|
|
149
35
|
it('should throw error for missing activity', async () => {
|
|
150
|
-
const
|
|
151
|
-
const ctx = createMockContext(supabase);
|
|
36
|
+
const ctx = createMockContext();
|
|
152
37
|
|
|
153
38
|
await expect(
|
|
154
39
|
startFallbackActivity({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
@@ -156,8 +41,7 @@ describe('startFallbackActivity', () => {
|
|
|
156
41
|
});
|
|
157
42
|
|
|
158
43
|
it('should throw error for invalid activity type', async () => {
|
|
159
|
-
const
|
|
160
|
-
const ctx = createMockContext(supabase);
|
|
44
|
+
const ctx = createMockContext();
|
|
161
45
|
|
|
162
46
|
await expect(
|
|
163
47
|
startFallbackActivity({
|
|
@@ -168,10 +52,11 @@ describe('startFallbackActivity', () => {
|
|
|
168
52
|
});
|
|
169
53
|
|
|
170
54
|
it('should start fallback activity successfully', async () => {
|
|
171
|
-
|
|
172
|
-
|
|
55
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
56
|
+
ok: true,
|
|
57
|
+
data: { message: 'Started code_review' },
|
|
173
58
|
});
|
|
174
|
-
const ctx = createMockContext(
|
|
59
|
+
const ctx = createMockContext();
|
|
175
60
|
|
|
176
61
|
const result = await startFallbackActivity(
|
|
177
62
|
{
|
|
@@ -188,11 +73,12 @@ describe('startFallbackActivity', () => {
|
|
|
188
73
|
expect((result.result as { title: string }).title).toBeDefined();
|
|
189
74
|
});
|
|
190
75
|
|
|
191
|
-
it('should
|
|
192
|
-
|
|
193
|
-
|
|
76
|
+
it('should call API client with correct parameters', async () => {
|
|
77
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
78
|
+
ok: true,
|
|
79
|
+
data: { message: 'Started' },
|
|
194
80
|
});
|
|
195
|
-
const ctx = createMockContext(
|
|
81
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
196
82
|
|
|
197
83
|
await startFallbackActivity(
|
|
198
84
|
{
|
|
@@ -202,15 +88,11 @@ describe('startFallbackActivity', () => {
|
|
|
202
88
|
ctx
|
|
203
89
|
);
|
|
204
90
|
|
|
205
|
-
expect(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
current_task_id: null,
|
|
210
|
-
status: 'active',
|
|
211
|
-
})
|
|
91
|
+
expect(mockApiClient.startFallbackActivity).toHaveBeenCalledWith(
|
|
92
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
93
|
+
'security_review',
|
|
94
|
+
'my-session'
|
|
212
95
|
);
|
|
213
|
-
expect(supabase.eq).toHaveBeenCalledWith('id', 'my-session');
|
|
214
96
|
});
|
|
215
97
|
|
|
216
98
|
it('should accept all valid activity types', async () => {
|
|
@@ -228,10 +110,11 @@ describe('startFallbackActivity', () => {
|
|
|
228
110
|
];
|
|
229
111
|
|
|
230
112
|
for (const activity of validActivities) {
|
|
231
|
-
|
|
232
|
-
|
|
113
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
114
|
+
ok: true,
|
|
115
|
+
data: { message: `Started ${activity}` },
|
|
233
116
|
});
|
|
234
|
-
const ctx = createMockContext(
|
|
117
|
+
const ctx = createMockContext();
|
|
235
118
|
|
|
236
119
|
const result = await startFallbackActivity(
|
|
237
120
|
{
|
|
@@ -248,25 +131,97 @@ describe('startFallbackActivity', () => {
|
|
|
248
131
|
}
|
|
249
132
|
});
|
|
250
133
|
|
|
251
|
-
it('should throw error when
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
...supabase,
|
|
258
|
-
eq: vi.fn().mockReturnValue({
|
|
259
|
-
then: (resolve: (val: unknown) => void) =>
|
|
260
|
-
Promise.resolve({ data: null, error: { message: 'Update failed' } }).then(resolve),
|
|
261
|
-
}),
|
|
262
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
134
|
+
it('should throw error when API call fails', async () => {
|
|
135
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
136
|
+
ok: false,
|
|
137
|
+
error: 'Failed to start activity',
|
|
138
|
+
});
|
|
139
|
+
const ctx = createMockContext();
|
|
263
140
|
|
|
264
141
|
await expect(
|
|
265
142
|
startFallbackActivity({
|
|
266
143
|
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
267
144
|
activity: 'code_review',
|
|
268
145
|
}, ctx)
|
|
269
|
-
).rejects.toThrow();
|
|
146
|
+
).rejects.toThrow('Failed to start fallback activity');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should pass through worktree guidance when API returns it', async () => {
|
|
150
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
151
|
+
ok: true,
|
|
152
|
+
data: {
|
|
153
|
+
success: true,
|
|
154
|
+
activity: 'code_review',
|
|
155
|
+
message: 'Started code_review',
|
|
156
|
+
git_workflow: {
|
|
157
|
+
workflow: 'git-flow',
|
|
158
|
+
base_branch: 'develop',
|
|
159
|
+
worktree_recommended: true,
|
|
160
|
+
note: 'Fallback activities use the base branch directly (read-only).',
|
|
161
|
+
},
|
|
162
|
+
worktree_setup: {
|
|
163
|
+
message: 'RECOMMENDED: Create a worktree to avoid conflicts.',
|
|
164
|
+
commands: [
|
|
165
|
+
'git checkout develop',
|
|
166
|
+
'git pull origin develop',
|
|
167
|
+
'git worktree add ../Project-code-review develop',
|
|
168
|
+
'cd ../Project-code-review',
|
|
169
|
+
],
|
|
170
|
+
worktree_path: '../Project-code-review',
|
|
171
|
+
branch_name: 'develop',
|
|
172
|
+
cleanup_command: 'git worktree remove ../Project-code-review',
|
|
173
|
+
report_worktree: 'heartbeat(current_worktree_path: "../Project-code-review")',
|
|
174
|
+
},
|
|
175
|
+
next_step: 'After setting up worktree: call heartbeat to report your location.',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
const ctx = createMockContext();
|
|
179
|
+
|
|
180
|
+
const result = await startFallbackActivity(
|
|
181
|
+
{
|
|
182
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
183
|
+
activity: 'code_review',
|
|
184
|
+
},
|
|
185
|
+
ctx
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect(result.result).toMatchObject({
|
|
189
|
+
success: true,
|
|
190
|
+
activity: 'code_review',
|
|
191
|
+
});
|
|
192
|
+
expect((result.result as { git_workflow?: unknown }).git_workflow).toBeDefined();
|
|
193
|
+
expect((result.result as { git_workflow: { workflow: string } }).git_workflow.workflow).toBe('git-flow');
|
|
194
|
+
expect((result.result as { worktree_setup?: unknown }).worktree_setup).toBeDefined();
|
|
195
|
+
expect((result.result as { worktree_setup: { worktree_path: string } }).worktree_setup.worktree_path).toBe('../Project-code-review');
|
|
196
|
+
expect((result.result as { next_step?: string }).next_step).toContain('heartbeat');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should not include worktree guidance when API does not return it', async () => {
|
|
200
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
201
|
+
ok: true,
|
|
202
|
+
data: {
|
|
203
|
+
success: true,
|
|
204
|
+
activity: 'code_review',
|
|
205
|
+
message: 'Started code_review',
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
const ctx = createMockContext();
|
|
209
|
+
|
|
210
|
+
const result = await startFallbackActivity(
|
|
211
|
+
{
|
|
212
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
213
|
+
activity: 'code_review',
|
|
214
|
+
},
|
|
215
|
+
ctx
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
expect(result.result).toMatchObject({
|
|
219
|
+
success: true,
|
|
220
|
+
activity: 'code_review',
|
|
221
|
+
});
|
|
222
|
+
expect((result.result as { git_workflow?: unknown }).git_workflow).toBeUndefined();
|
|
223
|
+
expect((result.result as { worktree_setup?: unknown }).worktree_setup).toBeUndefined();
|
|
224
|
+
expect((result.result as { next_step?: string }).next_step).toBeUndefined();
|
|
270
225
|
});
|
|
271
226
|
});
|
|
272
227
|
|
|
@@ -278,46 +233,25 @@ describe('stopFallbackActivity', () => {
|
|
|
278
233
|
beforeEach(() => vi.clearAllMocks());
|
|
279
234
|
|
|
280
235
|
it('should throw error for missing project_id', async () => {
|
|
281
|
-
const
|
|
282
|
-
const ctx = createMockContext(supabase);
|
|
236
|
+
const ctx = createMockContext();
|
|
283
237
|
|
|
284
238
|
await expect(stopFallbackActivity({}, ctx)).rejects.toThrow(ValidationError);
|
|
285
239
|
});
|
|
286
240
|
|
|
287
241
|
it('should throw error for invalid project_id UUID', async () => {
|
|
288
|
-
const
|
|
289
|
-
const ctx = createMockContext(supabase);
|
|
242
|
+
const ctx = createMockContext();
|
|
290
243
|
|
|
291
244
|
await expect(
|
|
292
245
|
stopFallbackActivity({ project_id: 'invalid' }, ctx)
|
|
293
246
|
).rejects.toThrow(ValidationError);
|
|
294
247
|
});
|
|
295
248
|
|
|
296
|
-
it('should stop fallback activity successfully
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
updateResult: { data: null, error: null },
|
|
249
|
+
it('should stop fallback activity successfully', async () => {
|
|
250
|
+
mockApiClient.stopFallbackActivity.mockResolvedValue({
|
|
251
|
+
ok: true,
|
|
252
|
+
data: { success: true },
|
|
301
253
|
});
|
|
302
|
-
const ctx = createMockContext(
|
|
303
|
-
|
|
304
|
-
const result = await stopFallbackActivity(
|
|
305
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
306
|
-
ctx
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
expect(result.result).toMatchObject({
|
|
310
|
-
success: true,
|
|
311
|
-
});
|
|
312
|
-
expect((result.result as { message: string }).message).toContain('code_review');
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it('should stop fallback activity when no activity was active', async () => {
|
|
316
|
-
const supabase = createMockSupabase({
|
|
317
|
-
selectResult: { data: { current_fallback_activity: null }, error: null },
|
|
318
|
-
updateResult: { data: null, error: null },
|
|
319
|
-
});
|
|
320
|
-
const ctx = createMockContext(supabase);
|
|
254
|
+
const ctx = createMockContext();
|
|
321
255
|
|
|
322
256
|
const result = await stopFallbackActivity(
|
|
323
257
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -330,13 +264,12 @@ describe('stopFallbackActivity', () => {
|
|
|
330
264
|
});
|
|
331
265
|
});
|
|
332
266
|
|
|
333
|
-
it('should
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
updateResult: { data: null, error: null },
|
|
267
|
+
it('should call API client with summary when provided', async () => {
|
|
268
|
+
mockApiClient.stopFallbackActivity.mockResolvedValue({
|
|
269
|
+
ok: true,
|
|
270
|
+
data: { success: true },
|
|
338
271
|
});
|
|
339
|
-
const ctx = createMockContext(
|
|
272
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
340
273
|
|
|
341
274
|
await stopFallbackActivity(
|
|
342
275
|
{
|
|
@@ -346,32 +279,25 @@ describe('stopFallbackActivity', () => {
|
|
|
346
279
|
ctx
|
|
347
280
|
);
|
|
348
281
|
|
|
349
|
-
expect(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
})
|
|
282
|
+
expect(mockApiClient.stopFallbackActivity).toHaveBeenCalledWith(
|
|
283
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
284
|
+
'Reviewed 5 files, found 3 issues',
|
|
285
|
+
'my-session'
|
|
354
286
|
);
|
|
355
287
|
});
|
|
356
288
|
|
|
357
|
-
it('should
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
289
|
+
it('should throw error when API call fails', async () => {
|
|
290
|
+
mockApiClient.stopFallbackActivity.mockResolvedValue({
|
|
291
|
+
ok: false,
|
|
292
|
+
error: 'Failed to stop activity',
|
|
361
293
|
});
|
|
362
|
-
const ctx = createMockContext(
|
|
294
|
+
const ctx = createMockContext();
|
|
363
295
|
|
|
364
|
-
await
|
|
365
|
-
{
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
expect(supabase.update).toHaveBeenCalledWith(
|
|
370
|
-
expect.objectContaining({
|
|
371
|
-
current_fallback_activity: null,
|
|
372
|
-
status: 'idle',
|
|
373
|
-
})
|
|
374
|
-
);
|
|
296
|
+
await expect(
|
|
297
|
+
stopFallbackActivity({
|
|
298
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
299
|
+
}, ctx)
|
|
300
|
+
).rejects.toThrow('Failed to stop fallback activity');
|
|
375
301
|
});
|
|
376
302
|
});
|
|
377
303
|
|
|
@@ -383,15 +309,13 @@ describe('getActivityHistory', () => {
|
|
|
383
309
|
beforeEach(() => vi.clearAllMocks());
|
|
384
310
|
|
|
385
311
|
it('should throw error for missing project_id', async () => {
|
|
386
|
-
const
|
|
387
|
-
const ctx = createMockContext(supabase);
|
|
312
|
+
const ctx = createMockContext();
|
|
388
313
|
|
|
389
314
|
await expect(getActivityHistory({}, ctx)).rejects.toThrow(ValidationError);
|
|
390
315
|
});
|
|
391
316
|
|
|
392
317
|
it('should throw error for invalid project_id UUID', async () => {
|
|
393
|
-
const
|
|
394
|
-
const ctx = createMockContext(supabase);
|
|
318
|
+
const ctx = createMockContext();
|
|
395
319
|
|
|
396
320
|
await expect(
|
|
397
321
|
getActivityHistory({ project_id: 'invalid' }, ctx)
|
|
@@ -399,10 +323,15 @@ describe('getActivityHistory', () => {
|
|
|
399
323
|
});
|
|
400
324
|
|
|
401
325
|
it('should return empty history when no activities', async () => {
|
|
402
|
-
|
|
403
|
-
|
|
326
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
327
|
+
ok: true,
|
|
328
|
+
data: {
|
|
329
|
+
history: [],
|
|
330
|
+
latest_by_type: {},
|
|
331
|
+
count: 0,
|
|
332
|
+
},
|
|
404
333
|
});
|
|
405
|
-
const ctx = createMockContext(
|
|
334
|
+
const ctx = createMockContext();
|
|
406
335
|
|
|
407
336
|
const result = await getActivityHistory(
|
|
408
337
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -415,28 +344,31 @@ describe('getActivityHistory', () => {
|
|
|
415
344
|
});
|
|
416
345
|
});
|
|
417
346
|
|
|
418
|
-
it('should return activity history', async () => {
|
|
347
|
+
it('should return activity history from API', async () => {
|
|
419
348
|
const mockHistory = [
|
|
420
349
|
{
|
|
421
350
|
id: 'h1',
|
|
422
351
|
activity_type: 'code_review',
|
|
423
352
|
completed_at: '2025-01-14T10:00:00Z',
|
|
424
353
|
summary: 'Reviewed auth module',
|
|
425
|
-
agent_sessions: { agent_name: 'Wave' },
|
|
426
354
|
},
|
|
427
355
|
{
|
|
428
356
|
id: 'h2',
|
|
429
357
|
activity_type: 'security_review',
|
|
430
358
|
completed_at: '2025-01-14T09:00:00Z',
|
|
431
359
|
summary: null,
|
|
432
|
-
agent_sessions: { agent_name: 'Glitch' },
|
|
433
360
|
},
|
|
434
361
|
];
|
|
435
362
|
|
|
436
|
-
|
|
437
|
-
|
|
363
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
364
|
+
ok: true,
|
|
365
|
+
data: {
|
|
366
|
+
history: mockHistory,
|
|
367
|
+
latest_by_type: { code_review: mockHistory[0] },
|
|
368
|
+
count: 2,
|
|
369
|
+
},
|
|
438
370
|
});
|
|
439
|
-
const ctx = createMockContext(
|
|
371
|
+
const ctx = createMockContext();
|
|
440
372
|
|
|
441
373
|
const result = await getActivityHistory(
|
|
442
374
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -447,83 +379,42 @@ describe('getActivityHistory', () => {
|
|
|
447
379
|
expect((result.result as { count: number }).count).toBe(2);
|
|
448
380
|
});
|
|
449
381
|
|
|
450
|
-
it('should
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
activity_type: 'code_review',
|
|
455
|
-
completed_at: '2025-01-14T10:00:00Z',
|
|
456
|
-
agent_sessions: null,
|
|
457
|
-
},
|
|
458
|
-
{
|
|
459
|
-
id: 'h2',
|
|
460
|
-
activity_type: 'code_review',
|
|
461
|
-
completed_at: '2025-01-14T09:00:00Z',
|
|
462
|
-
agent_sessions: null,
|
|
463
|
-
},
|
|
464
|
-
];
|
|
465
|
-
|
|
466
|
-
const supabase = createMockSupabase({
|
|
467
|
-
selectResult: { data: mockHistory, error: null },
|
|
382
|
+
it('should call API proxy with correct parameters', async () => {
|
|
383
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
384
|
+
ok: true,
|
|
385
|
+
data: { history: [], count: 0 },
|
|
468
386
|
});
|
|
469
|
-
const ctx = createMockContext(
|
|
470
|
-
|
|
471
|
-
const result = await getActivityHistory(
|
|
472
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
473
|
-
ctx
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
const latestByType = (result.result as { latest_by_type: Record<string, unknown> }).latest_by_type;
|
|
477
|
-
expect(latestByType['code_review']).toBeDefined();
|
|
478
|
-
expect((latestByType['code_review'] as { id: string }).id).toBe('h1');
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
it('should filter by activity_type when provided', async () => {
|
|
482
|
-
const supabase = createMockSupabase({
|
|
483
|
-
selectResult: { data: [], error: null },
|
|
484
|
-
});
|
|
485
|
-
const ctx = createMockContext(supabase);
|
|
387
|
+
const ctx = createMockContext();
|
|
486
388
|
|
|
487
389
|
await getActivityHistory(
|
|
488
390
|
{
|
|
489
391
|
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
490
392
|
activity_type: 'security_review',
|
|
393
|
+
limit: 10,
|
|
491
394
|
},
|
|
492
395
|
ctx
|
|
493
396
|
);
|
|
494
397
|
|
|
495
|
-
expect(
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
it('should respect limit parameter', async () => {
|
|
499
|
-
const supabase = createMockSupabase({
|
|
500
|
-
selectResult: { data: [], error: null },
|
|
501
|
-
});
|
|
502
|
-
const ctx = createMockContext(supabase);
|
|
503
|
-
|
|
504
|
-
await getActivityHistory(
|
|
398
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
399
|
+
'get_activity_history',
|
|
505
400
|
{
|
|
506
401
|
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
402
|
+
activity_type: 'security_review',
|
|
507
403
|
limit: 10,
|
|
508
|
-
}
|
|
509
|
-
ctx
|
|
404
|
+
}
|
|
510
405
|
);
|
|
511
|
-
|
|
512
|
-
expect(supabase.limit).toHaveBeenCalledWith(10);
|
|
513
406
|
});
|
|
514
407
|
|
|
515
|
-
it('should
|
|
516
|
-
|
|
517
|
-
|
|
408
|
+
it('should throw error when API call fails', async () => {
|
|
409
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
410
|
+
ok: false,
|
|
411
|
+
error: 'Query failed',
|
|
518
412
|
});
|
|
519
|
-
const ctx = createMockContext(
|
|
520
|
-
|
|
521
|
-
await getActivityHistory(
|
|
522
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
523
|
-
ctx
|
|
524
|
-
);
|
|
413
|
+
const ctx = createMockContext();
|
|
525
414
|
|
|
526
|
-
expect(
|
|
415
|
+
await expect(
|
|
416
|
+
getActivityHistory({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
417
|
+
).rejects.toThrow('Failed to get activity history');
|
|
527
418
|
});
|
|
528
419
|
});
|
|
529
420
|
|
|
@@ -535,15 +426,13 @@ describe('getActivitySchedules', () => {
|
|
|
535
426
|
beforeEach(() => vi.clearAllMocks());
|
|
536
427
|
|
|
537
428
|
it('should throw error for missing project_id', async () => {
|
|
538
|
-
const
|
|
539
|
-
const ctx = createMockContext(supabase);
|
|
429
|
+
const ctx = createMockContext();
|
|
540
430
|
|
|
541
431
|
await expect(getActivitySchedules({}, ctx)).rejects.toThrow(ValidationError);
|
|
542
432
|
});
|
|
543
433
|
|
|
544
434
|
it('should throw error for invalid project_id UUID', async () => {
|
|
545
|
-
const
|
|
546
|
-
const ctx = createMockContext(supabase);
|
|
435
|
+
const ctx = createMockContext();
|
|
547
436
|
|
|
548
437
|
await expect(
|
|
549
438
|
getActivitySchedules({ project_id: 'invalid' }, ctx)
|
|
@@ -551,10 +440,15 @@ describe('getActivitySchedules', () => {
|
|
|
551
440
|
});
|
|
552
441
|
|
|
553
442
|
it('should return empty schedules when none exist', async () => {
|
|
554
|
-
|
|
555
|
-
|
|
443
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
444
|
+
ok: true,
|
|
445
|
+
data: {
|
|
446
|
+
schedules: [],
|
|
447
|
+
due_activities: [],
|
|
448
|
+
count: 0,
|
|
449
|
+
},
|
|
556
450
|
});
|
|
557
|
-
const ctx = createMockContext(
|
|
451
|
+
const ctx = createMockContext();
|
|
558
452
|
|
|
559
453
|
const result = await getActivitySchedules(
|
|
560
454
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -568,7 +462,7 @@ describe('getActivitySchedules', () => {
|
|
|
568
462
|
});
|
|
569
463
|
});
|
|
570
464
|
|
|
571
|
-
it('should return activity schedules', async () => {
|
|
465
|
+
it('should return activity schedules from API', async () => {
|
|
572
466
|
const mockSchedules = [
|
|
573
467
|
{
|
|
574
468
|
id: 's1',
|
|
@@ -586,10 +480,15 @@ describe('getActivitySchedules', () => {
|
|
|
586
480
|
},
|
|
587
481
|
];
|
|
588
482
|
|
|
589
|
-
|
|
590
|
-
|
|
483
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
484
|
+
ok: true,
|
|
485
|
+
data: {
|
|
486
|
+
schedules: mockSchedules,
|
|
487
|
+
due_activities: ['code_review'],
|
|
488
|
+
count: 2,
|
|
489
|
+
},
|
|
591
490
|
});
|
|
592
|
-
const ctx = createMockContext(
|
|
491
|
+
const ctx = createMockContext();
|
|
593
492
|
|
|
594
493
|
const result = await getActivitySchedules(
|
|
595
494
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -598,90 +497,36 @@ describe('getActivitySchedules', () => {
|
|
|
598
497
|
|
|
599
498
|
expect((result.result as { schedules: unknown[] }).schedules).toHaveLength(2);
|
|
600
499
|
expect((result.result as { count: number }).count).toBe(2);
|
|
500
|
+
expect((result.result as { due_activities: string[] }).due_activities).toContain('code_review');
|
|
601
501
|
});
|
|
602
502
|
|
|
603
|
-
it('should
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
const mockSchedules = [
|
|
608
|
-
{
|
|
609
|
-
id: 's1',
|
|
610
|
-
activity_type: 'code_review',
|
|
611
|
-
enabled: true,
|
|
612
|
-
next_run_at: pastDate, // Due
|
|
613
|
-
},
|
|
614
|
-
{
|
|
615
|
-
id: 's2',
|
|
616
|
-
activity_type: 'security_review',
|
|
617
|
-
enabled: true,
|
|
618
|
-
next_run_at: futureDate, // Not due
|
|
619
|
-
},
|
|
620
|
-
{
|
|
621
|
-
id: 's3',
|
|
622
|
-
activity_type: 'test_coverage',
|
|
623
|
-
enabled: false, // Disabled
|
|
624
|
-
next_run_at: pastDate,
|
|
625
|
-
},
|
|
626
|
-
];
|
|
627
|
-
|
|
628
|
-
const supabase = createMockSupabase({
|
|
629
|
-
selectResult: { data: mockSchedules, error: null },
|
|
630
|
-
});
|
|
631
|
-
const ctx = createMockContext(supabase);
|
|
632
|
-
|
|
633
|
-
const result = await getActivitySchedules(
|
|
634
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
635
|
-
ctx
|
|
636
|
-
);
|
|
637
|
-
|
|
638
|
-
const dueActivities = (result.result as { due_activities: string[] }).due_activities;
|
|
639
|
-
expect(dueActivities).toContain('code_review');
|
|
640
|
-
expect(dueActivities).not.toContain('security_review');
|
|
641
|
-
expect(dueActivities).not.toContain('test_coverage');
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
it('should query background_activity_schedules table', async () => {
|
|
645
|
-
const supabase = createMockSupabase({
|
|
646
|
-
selectResult: { data: [], error: null },
|
|
503
|
+
it('should call API proxy with correct parameters', async () => {
|
|
504
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
505
|
+
ok: true,
|
|
506
|
+
data: { schedules: [], due_activities: [], count: 0 },
|
|
647
507
|
});
|
|
648
|
-
const ctx = createMockContext(
|
|
508
|
+
const ctx = createMockContext();
|
|
649
509
|
|
|
650
510
|
await getActivitySchedules(
|
|
651
511
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
652
512
|
ctx
|
|
653
513
|
);
|
|
654
514
|
|
|
655
|
-
expect(
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
it('should order schedules by activity_type', async () => {
|
|
659
|
-
const supabase = createMockSupabase({
|
|
660
|
-
selectResult: { data: [], error: null },
|
|
661
|
-
});
|
|
662
|
-
const ctx = createMockContext(supabase);
|
|
663
|
-
|
|
664
|
-
await getActivitySchedules(
|
|
665
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
666
|
-
ctx
|
|
515
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
516
|
+
'get_activity_schedules',
|
|
517
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' }
|
|
667
518
|
);
|
|
668
|
-
|
|
669
|
-
expect(supabase.order).toHaveBeenCalledWith('activity_type');
|
|
670
519
|
});
|
|
671
520
|
|
|
672
|
-
it('should throw error when
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
...supabase,
|
|
679
|
-
then: (resolve: (val: unknown) => void) =>
|
|
680
|
-
Promise.resolve({ data: null, error: { message: 'Query failed' } }).then(resolve),
|
|
681
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
521
|
+
it('should throw error when API call fails', async () => {
|
|
522
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
523
|
+
ok: false,
|
|
524
|
+
error: 'Query failed',
|
|
525
|
+
});
|
|
526
|
+
const ctx = createMockContext();
|
|
682
527
|
|
|
683
528
|
await expect(
|
|
684
529
|
getActivitySchedules({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
685
|
-
).rejects.toThrow();
|
|
530
|
+
).rejects.toThrow('Failed to get activity schedules');
|
|
686
531
|
});
|
|
687
532
|
});
|