@vibescope/mcp-server 0.0.1 → 0.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 +113 -98
- package/dist/api-client.d.ts +1114 -0
- package/dist/api-client.js +698 -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 +106 -476
- 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 +112 -828
- package/dist/handlers/discovery.js +31 -0
- package/dist/handlers/fallback.d.ts +2 -0
- package/dist/handlers/fallback.js +39 -134
- package/dist/handlers/findings.js +43 -67
- 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 +99 -585
- package/dist/handlers/sprints.d.ts +32 -0
- package/dist/handlers/sprints.js +274 -0
- package/dist/handlers/tasks.d.ts +7 -10
- package/dist/handlers/tasks.js +230 -900
- package/dist/handlers/tool-docs.d.ts +8 -0
- package/dist/handlers/tool-docs.js +657 -0
- package/dist/handlers/types.d.ts +11 -3
- package/dist/handlers/validation.d.ts +1 -1
- package/dist/handlers/validation.js +26 -153
- package/dist/index.js +473 -160
- package/dist/knowledge.js +106 -9
- package/dist/tools.js +4 -0
- package/dist/validators.d.ts +21 -0
- package/dist/validators.js +91 -0
- package/package.json +2 -3
- package/src/api-client.ts +1752 -0
- package/src/cli.test.ts +128 -302
- package/src/cli.ts +41 -285
- package/src/handlers/__test-setup__.ts +210 -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 +194 -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 +140 -895
- package/src/handlers/discovery.test.ts +20 -67
- package/src/handlers/discovery.ts +32 -0
- package/src/handlers/fallback.test.ts +128 -361
- package/src/handlers/fallback.ts +62 -148
- package/src/handlers/findings.test.ts +127 -345
- package/src/handlers/findings.ts +49 -66
- 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 +241 -206
- package/src/handlers/session.ts +110 -657
- package/src/handlers/sprints.test.ts +711 -0
- package/src/handlers/sprints.ts +497 -0
- package/src/handlers/tasks.test.ts +608 -353
- package/src/handlers/tasks.ts +248 -1025
- package/src/handlers/types.ts +12 -4
- package/src/handlers/validation.test.ts +189 -572
- package/src/handlers/validation.ts +29 -166
- package/src/index.ts +473 -184
- package/src/knowledge.ts +107 -9
- package/src/tools.ts +2506 -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/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,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect,
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import {
|
|
3
3
|
addIdea,
|
|
4
4
|
updateIdea,
|
|
@@ -7,18 +7,18 @@ import {
|
|
|
7
7
|
convertIdeaToTask,
|
|
8
8
|
} from './ideas.js';
|
|
9
9
|
import { ValidationError } from '../validators.js';
|
|
10
|
-
import {
|
|
10
|
+
import { createMockContext } from './__test-utils__.js';
|
|
11
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
11
12
|
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// addIdea Tests
|
|
14
15
|
// ============================================================================
|
|
15
16
|
|
|
16
17
|
describe('addIdea', () => {
|
|
17
|
-
beforeEach(() =>
|
|
18
|
+
beforeEach(() => {});
|
|
18
19
|
|
|
19
20
|
it('should throw error for missing project_id', async () => {
|
|
20
|
-
const
|
|
21
|
-
const ctx = createMockContext(supabase);
|
|
21
|
+
const ctx = createMockContext();
|
|
22
22
|
|
|
23
23
|
await expect(
|
|
24
24
|
addIdea({ title: 'New Feature' }, ctx)
|
|
@@ -26,8 +26,7 @@ describe('addIdea', () => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('should throw error for invalid project_id UUID', async () => {
|
|
29
|
-
const
|
|
30
|
-
const ctx = createMockContext(supabase);
|
|
29
|
+
const ctx = createMockContext();
|
|
31
30
|
|
|
32
31
|
await expect(
|
|
33
32
|
addIdea({ project_id: 'invalid', title: 'New Feature' }, ctx)
|
|
@@ -35,8 +34,7 @@ describe('addIdea', () => {
|
|
|
35
34
|
});
|
|
36
35
|
|
|
37
36
|
it('should throw error for missing title', async () => {
|
|
38
|
-
const
|
|
39
|
-
const ctx = createMockContext(supabase);
|
|
37
|
+
const ctx = createMockContext();
|
|
40
38
|
|
|
41
39
|
await expect(
|
|
42
40
|
addIdea({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
@@ -44,10 +42,11 @@ describe('addIdea', () => {
|
|
|
44
42
|
});
|
|
45
43
|
|
|
46
44
|
it('should add idea successfully', async () => {
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
mockApiClient.addIdea.mockResolvedValue({
|
|
46
|
+
ok: true,
|
|
47
|
+
data: { idea_id: 'idea-1' },
|
|
49
48
|
});
|
|
50
|
-
const ctx = createMockContext(
|
|
49
|
+
const ctx = createMockContext();
|
|
51
50
|
|
|
52
51
|
const result = await addIdea(
|
|
53
52
|
{
|
|
@@ -64,11 +63,12 @@ describe('addIdea', () => {
|
|
|
64
63
|
});
|
|
65
64
|
});
|
|
66
65
|
|
|
67
|
-
it('should
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
it('should call API client with default status "raw"', async () => {
|
|
67
|
+
mockApiClient.addIdea.mockResolvedValue({
|
|
68
|
+
ok: true,
|
|
69
|
+
data: { idea_id: 'idea-1' },
|
|
70
70
|
});
|
|
71
|
-
const ctx = createMockContext(
|
|
71
|
+
const ctx = createMockContext();
|
|
72
72
|
|
|
73
73
|
await addIdea(
|
|
74
74
|
{
|
|
@@ -78,18 +78,23 @@ describe('addIdea', () => {
|
|
|
78
78
|
ctx
|
|
79
79
|
);
|
|
80
80
|
|
|
81
|
-
expect(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
expect(mockApiClient.addIdea).toHaveBeenCalledWith(
|
|
82
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
83
|
+
{
|
|
84
|
+
title: 'New Feature',
|
|
85
|
+
description: undefined,
|
|
86
|
+
status: undefined, // Default status applied server-side
|
|
87
|
+
},
|
|
88
|
+
'session-123'
|
|
85
89
|
);
|
|
86
90
|
});
|
|
87
91
|
|
|
88
|
-
it('should
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
it('should call API client with custom status', async () => {
|
|
93
|
+
mockApiClient.addIdea.mockResolvedValue({
|
|
94
|
+
ok: true,
|
|
95
|
+
data: { idea_id: 'idea-1' },
|
|
91
96
|
});
|
|
92
|
-
const ctx = createMockContext(
|
|
97
|
+
const ctx = createMockContext();
|
|
93
98
|
|
|
94
99
|
await addIdea(
|
|
95
100
|
{
|
|
@@ -100,18 +105,23 @@ describe('addIdea', () => {
|
|
|
100
105
|
ctx
|
|
101
106
|
);
|
|
102
107
|
|
|
103
|
-
expect(
|
|
104
|
-
|
|
108
|
+
expect(mockApiClient.addIdea).toHaveBeenCalledWith(
|
|
109
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
110
|
+
{
|
|
111
|
+
title: 'New Feature',
|
|
112
|
+
description: undefined,
|
|
105
113
|
status: 'exploring',
|
|
106
|
-
}
|
|
114
|
+
},
|
|
115
|
+
'session-123'
|
|
107
116
|
);
|
|
108
117
|
});
|
|
109
118
|
|
|
110
|
-
it('should include session_id in
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
it('should include session_id in API call', async () => {
|
|
120
|
+
mockApiClient.addIdea.mockResolvedValue({
|
|
121
|
+
ok: true,
|
|
122
|
+
data: { idea_id: 'idea-1' },
|
|
113
123
|
});
|
|
114
|
-
const ctx = createMockContext(
|
|
124
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
115
125
|
|
|
116
126
|
await addIdea(
|
|
117
127
|
{
|
|
@@ -121,19 +131,19 @@ describe('addIdea', () => {
|
|
|
121
131
|
ctx
|
|
122
132
|
);
|
|
123
133
|
|
|
124
|
-
expect(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
})
|
|
134
|
+
expect(mockApiClient.addIdea).toHaveBeenCalledWith(
|
|
135
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
136
|
+
expect.any(Object),
|
|
137
|
+
'my-session'
|
|
129
138
|
);
|
|
130
139
|
});
|
|
131
140
|
|
|
132
|
-
it('should throw error when
|
|
133
|
-
|
|
134
|
-
|
|
141
|
+
it('should throw error when API call fails', async () => {
|
|
142
|
+
mockApiClient.addIdea.mockResolvedValue({
|
|
143
|
+
ok: false,
|
|
144
|
+
error: 'Insert failed',
|
|
135
145
|
});
|
|
136
|
-
const ctx = createMockContext(
|
|
146
|
+
const ctx = createMockContext();
|
|
137
147
|
|
|
138
148
|
await expect(
|
|
139
149
|
addIdea({
|
|
@@ -149,41 +159,28 @@ describe('addIdea', () => {
|
|
|
149
159
|
// ============================================================================
|
|
150
160
|
|
|
151
161
|
describe('updateIdea', () => {
|
|
152
|
-
beforeEach(() =>
|
|
162
|
+
beforeEach(() => {});
|
|
153
163
|
|
|
154
164
|
it('should throw error for missing idea_id', async () => {
|
|
155
|
-
const
|
|
156
|
-
const ctx = createMockContext(supabase);
|
|
165
|
+
const ctx = createMockContext();
|
|
157
166
|
|
|
158
167
|
await expect(updateIdea({}, ctx)).rejects.toThrow(ValidationError);
|
|
159
168
|
});
|
|
160
169
|
|
|
161
170
|
it('should throw error for invalid idea_id UUID', async () => {
|
|
162
|
-
const
|
|
163
|
-
const ctx = createMockContext(supabase);
|
|
171
|
+
const ctx = createMockContext();
|
|
164
172
|
|
|
165
173
|
await expect(
|
|
166
174
|
updateIdea({ idea_id: 'invalid' }, ctx)
|
|
167
175
|
).rejects.toThrow(ValidationError);
|
|
168
176
|
});
|
|
169
177
|
|
|
170
|
-
it('should throw error when idea not found', async () => {
|
|
171
|
-
const supabase = createMockSupabase({
|
|
172
|
-
selectResult: { data: null, error: null },
|
|
173
|
-
});
|
|
174
|
-
const ctx = createMockContext(supabase);
|
|
175
|
-
|
|
176
|
-
await expect(
|
|
177
|
-
updateIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
178
|
-
).rejects.toThrow('Idea not found');
|
|
179
|
-
});
|
|
180
|
-
|
|
181
178
|
it('should update idea title', async () => {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
mockApiClient.updateIdea.mockResolvedValue({
|
|
180
|
+
ok: true,
|
|
181
|
+
data: { idea: { id: 'idea-1', title: 'Updated Title' } },
|
|
185
182
|
});
|
|
186
|
-
const ctx = createMockContext(
|
|
183
|
+
const ctx = createMockContext();
|
|
187
184
|
|
|
188
185
|
const result = await updateIdea(
|
|
189
186
|
{
|
|
@@ -197,20 +194,14 @@ describe('updateIdea', () => {
|
|
|
197
194
|
success: true,
|
|
198
195
|
idea_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
199
196
|
});
|
|
200
|
-
expect(supabase.update).toHaveBeenCalledWith(
|
|
201
|
-
expect.objectContaining({
|
|
202
|
-
title: 'Updated Title',
|
|
203
|
-
updated_at: expect.any(String),
|
|
204
|
-
})
|
|
205
|
-
);
|
|
206
197
|
});
|
|
207
198
|
|
|
208
|
-
it('should
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
199
|
+
it('should call API client with status update', async () => {
|
|
200
|
+
mockApiClient.updateIdea.mockResolvedValue({
|
|
201
|
+
ok: true,
|
|
202
|
+
data: { idea: { id: 'idea-1', status: 'planned' } },
|
|
212
203
|
});
|
|
213
|
-
const ctx = createMockContext(
|
|
204
|
+
const ctx = createMockContext();
|
|
214
205
|
|
|
215
206
|
await updateIdea(
|
|
216
207
|
{
|
|
@@ -220,43 +211,23 @@ describe('updateIdea', () => {
|
|
|
220
211
|
ctx
|
|
221
212
|
);
|
|
222
213
|
|
|
223
|
-
expect(
|
|
224
|
-
|
|
225
|
-
status: 'planned',
|
|
226
|
-
planned_at: expect.any(String),
|
|
227
|
-
})
|
|
228
|
-
);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('should not set planned_at when already in planned status', async () => {
|
|
232
|
-
const supabase = createMockSupabase({
|
|
233
|
-
selectResult: { data: { status: 'planned' }, error: null },
|
|
234
|
-
updateResult: { data: null, error: null },
|
|
235
|
-
});
|
|
236
|
-
const ctx = createMockContext(supabase);
|
|
237
|
-
|
|
238
|
-
await updateIdea(
|
|
214
|
+
expect(mockApiClient.updateIdea).toHaveBeenCalledWith(
|
|
215
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
239
216
|
{
|
|
240
|
-
|
|
217
|
+
title: undefined,
|
|
218
|
+
description: undefined,
|
|
241
219
|
status: 'planned',
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
// Should NOT have planned_at since it's already planned
|
|
247
|
-
expect(supabase.update).toHaveBeenCalledWith(
|
|
248
|
-
expect.not.objectContaining({
|
|
249
|
-
planned_at: expect.any(String),
|
|
250
|
-
})
|
|
220
|
+
doc_url: undefined,
|
|
221
|
+
}
|
|
251
222
|
);
|
|
252
223
|
});
|
|
253
224
|
|
|
254
225
|
it('should update doc_url', async () => {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
226
|
+
mockApiClient.updateIdea.mockResolvedValue({
|
|
227
|
+
ok: true,
|
|
228
|
+
data: { idea: { id: 'idea-1' } },
|
|
258
229
|
});
|
|
259
|
-
const ctx = createMockContext(
|
|
230
|
+
const ctx = createMockContext();
|
|
260
231
|
|
|
261
232
|
await updateIdea(
|
|
262
233
|
{
|
|
@@ -266,27 +237,23 @@ describe('updateIdea', () => {
|
|
|
266
237
|
ctx
|
|
267
238
|
);
|
|
268
239
|
|
|
269
|
-
expect(
|
|
270
|
-
|
|
240
|
+
expect(mockApiClient.updateIdea).toHaveBeenCalledWith(
|
|
241
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
242
|
+
{
|
|
243
|
+
title: undefined,
|
|
244
|
+
description: undefined,
|
|
245
|
+
status: undefined,
|
|
271
246
|
doc_url: 'https://docs.example.com/feature',
|
|
272
|
-
}
|
|
247
|
+
}
|
|
273
248
|
);
|
|
274
249
|
});
|
|
275
250
|
|
|
276
|
-
it('should throw error when
|
|
277
|
-
|
|
278
|
-
|
|
251
|
+
it('should throw error when API call fails', async () => {
|
|
252
|
+
mockApiClient.updateIdea.mockResolvedValue({
|
|
253
|
+
ok: false,
|
|
254
|
+
error: 'Idea not found',
|
|
279
255
|
});
|
|
280
|
-
const ctx = createMockContext(
|
|
281
|
-
|
|
282
|
-
// Override update to return error
|
|
283
|
-
vi.mocked(supabase.from('').update).mockReturnValue({
|
|
284
|
-
...supabase,
|
|
285
|
-
eq: vi.fn().mockReturnValue({
|
|
286
|
-
then: (resolve: (val: unknown) => void) =>
|
|
287
|
-
Promise.resolve({ data: null, error: { message: 'Update failed' } }).then(resolve),
|
|
288
|
-
}),
|
|
289
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
256
|
+
const ctx = createMockContext();
|
|
290
257
|
|
|
291
258
|
await expect(
|
|
292
259
|
updateIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000', title: 'New' }, ctx)
|
|
@@ -299,18 +266,16 @@ describe('updateIdea', () => {
|
|
|
299
266
|
// ============================================================================
|
|
300
267
|
|
|
301
268
|
describe('getIdeas', () => {
|
|
302
|
-
beforeEach(() =>
|
|
269
|
+
beforeEach(() => {});
|
|
303
270
|
|
|
304
271
|
it('should throw error for missing project_id', async () => {
|
|
305
|
-
const
|
|
306
|
-
const ctx = createMockContext(supabase);
|
|
272
|
+
const ctx = createMockContext();
|
|
307
273
|
|
|
308
274
|
await expect(getIdeas({}, ctx)).rejects.toThrow(ValidationError);
|
|
309
275
|
});
|
|
310
276
|
|
|
311
277
|
it('should throw error for invalid project_id UUID', async () => {
|
|
312
|
-
const
|
|
313
|
-
const ctx = createMockContext(supabase);
|
|
278
|
+
const ctx = createMockContext();
|
|
314
279
|
|
|
315
280
|
await expect(
|
|
316
281
|
getIdeas({ project_id: 'invalid' }, ctx)
|
|
@@ -318,17 +283,11 @@ describe('getIdeas', () => {
|
|
|
318
283
|
});
|
|
319
284
|
|
|
320
285
|
it('should return empty list when no ideas', async () => {
|
|
321
|
-
|
|
322
|
-
|
|
286
|
+
mockApiClient.getIdeas.mockResolvedValue({
|
|
287
|
+
ok: true,
|
|
288
|
+
data: { ideas: [] },
|
|
323
289
|
});
|
|
324
|
-
const ctx = createMockContext(
|
|
325
|
-
|
|
326
|
-
// Override to return array result
|
|
327
|
-
vi.mocked(supabase.from('').select).mockReturnValue({
|
|
328
|
-
...supabase,
|
|
329
|
-
then: (resolve: (val: unknown) => void) =>
|
|
330
|
-
Promise.resolve({ data: [], error: null }).then(resolve),
|
|
331
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
290
|
+
const ctx = createMockContext();
|
|
332
291
|
|
|
333
292
|
const result = await getIdeas(
|
|
334
293
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -344,17 +303,11 @@ describe('getIdeas', () => {
|
|
|
344
303
|
{ id: 'i2', title: 'Idea 2', description: 'Some desc', status: 'exploring', doc_url: null },
|
|
345
304
|
];
|
|
346
305
|
|
|
347
|
-
|
|
348
|
-
|
|
306
|
+
mockApiClient.getIdeas.mockResolvedValue({
|
|
307
|
+
ok: true,
|
|
308
|
+
data: { ideas: mockIdeas },
|
|
349
309
|
});
|
|
350
|
-
const ctx = createMockContext(
|
|
351
|
-
|
|
352
|
-
// Override to return array result
|
|
353
|
-
vi.mocked(supabase.from('').select).mockReturnValue({
|
|
354
|
-
...supabase,
|
|
355
|
-
then: (resolve: (val: unknown) => void) =>
|
|
356
|
-
Promise.resolve({ data: mockIdeas, error: null }).then(resolve),
|
|
357
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
310
|
+
const ctx = createMockContext();
|
|
358
311
|
|
|
359
312
|
const result = await getIdeas(
|
|
360
313
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -364,58 +317,58 @@ describe('getIdeas', () => {
|
|
|
364
317
|
expect((result.result as { ideas: unknown[] }).ideas).toHaveLength(2);
|
|
365
318
|
});
|
|
366
319
|
|
|
367
|
-
it('should
|
|
368
|
-
|
|
369
|
-
|
|
320
|
+
it('should pass status filter to API', async () => {
|
|
321
|
+
mockApiClient.getIdeas.mockResolvedValue({
|
|
322
|
+
ok: true,
|
|
323
|
+
data: { ideas: [] },
|
|
370
324
|
});
|
|
371
|
-
const ctx = createMockContext(
|
|
325
|
+
const ctx = createMockContext();
|
|
372
326
|
|
|
373
327
|
await getIdeas(
|
|
374
328
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000', status: 'planned' },
|
|
375
329
|
ctx
|
|
376
330
|
);
|
|
377
331
|
|
|
378
|
-
expect(
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
await getIdeas(
|
|
388
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
389
|
-
ctx
|
|
332
|
+
expect(mockApiClient.getIdeas).toHaveBeenCalledWith(
|
|
333
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
334
|
+
{
|
|
335
|
+
status: 'planned',
|
|
336
|
+
limit: 50,
|
|
337
|
+
offset: 0,
|
|
338
|
+
search_query: undefined,
|
|
339
|
+
}
|
|
390
340
|
);
|
|
391
|
-
|
|
392
|
-
expect(supabase.from).toHaveBeenCalledWith('ideas');
|
|
393
341
|
});
|
|
394
342
|
|
|
395
|
-
it('should
|
|
396
|
-
|
|
397
|
-
|
|
343
|
+
it('should pass limit and offset to API', async () => {
|
|
344
|
+
mockApiClient.getIdeas.mockResolvedValue({
|
|
345
|
+
ok: true,
|
|
346
|
+
data: { ideas: [] },
|
|
398
347
|
});
|
|
399
|
-
const ctx = createMockContext(
|
|
348
|
+
const ctx = createMockContext();
|
|
400
349
|
|
|
401
350
|
await getIdeas(
|
|
402
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
351
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000', limit: 10, offset: 5 },
|
|
403
352
|
ctx
|
|
404
353
|
);
|
|
405
354
|
|
|
406
|
-
expect(
|
|
355
|
+
expect(mockApiClient.getIdeas).toHaveBeenCalledWith(
|
|
356
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
357
|
+
{
|
|
358
|
+
status: undefined,
|
|
359
|
+
limit: 10,
|
|
360
|
+
offset: 5,
|
|
361
|
+
search_query: undefined,
|
|
362
|
+
}
|
|
363
|
+
);
|
|
407
364
|
});
|
|
408
365
|
|
|
409
|
-
it('should throw error when
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
...supabase,
|
|
416
|
-
then: (resolve: (val: unknown) => void) =>
|
|
417
|
-
Promise.resolve({ data: null, error: { message: 'Query failed' } }).then(resolve),
|
|
418
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
366
|
+
it('should throw error when API call fails', async () => {
|
|
367
|
+
mockApiClient.getIdeas.mockResolvedValue({
|
|
368
|
+
ok: false,
|
|
369
|
+
error: 'Query failed',
|
|
370
|
+
});
|
|
371
|
+
const ctx = createMockContext();
|
|
419
372
|
|
|
420
373
|
await expect(
|
|
421
374
|
getIdeas({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
@@ -428,18 +381,16 @@ describe('getIdeas', () => {
|
|
|
428
381
|
// ============================================================================
|
|
429
382
|
|
|
430
383
|
describe('deleteIdea', () => {
|
|
431
|
-
beforeEach(() =>
|
|
384
|
+
beforeEach(() => {});
|
|
432
385
|
|
|
433
386
|
it('should throw error for missing idea_id', async () => {
|
|
434
|
-
const
|
|
435
|
-
const ctx = createMockContext(supabase);
|
|
387
|
+
const ctx = createMockContext();
|
|
436
388
|
|
|
437
389
|
await expect(deleteIdea({}, ctx)).rejects.toThrow(ValidationError);
|
|
438
390
|
});
|
|
439
391
|
|
|
440
392
|
it('should throw error for invalid idea_id UUID', async () => {
|
|
441
|
-
const
|
|
442
|
-
const ctx = createMockContext(supabase);
|
|
393
|
+
const ctx = createMockContext();
|
|
443
394
|
|
|
444
395
|
await expect(
|
|
445
396
|
deleteIdea({ idea_id: 'invalid' }, ctx)
|
|
@@ -447,19 +398,11 @@ describe('deleteIdea', () => {
|
|
|
447
398
|
});
|
|
448
399
|
|
|
449
400
|
it('should delete idea successfully', async () => {
|
|
450
|
-
|
|
451
|
-
|
|
401
|
+
mockApiClient.deleteIdea.mockResolvedValue({
|
|
402
|
+
ok: true,
|
|
403
|
+
data: { success: true },
|
|
452
404
|
});
|
|
453
|
-
const ctx = createMockContext(
|
|
454
|
-
|
|
455
|
-
// Override delete to return success
|
|
456
|
-
vi.mocked(supabase.from('').delete).mockReturnValue({
|
|
457
|
-
...supabase,
|
|
458
|
-
eq: vi.fn().mockReturnValue({
|
|
459
|
-
then: (resolve: (val: unknown) => void) =>
|
|
460
|
-
Promise.resolve({ data: null, error: null }).then(resolve),
|
|
461
|
-
}),
|
|
462
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
405
|
+
const ctx = createMockContext();
|
|
463
406
|
|
|
464
407
|
const result = await deleteIdea(
|
|
465
408
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -469,42 +412,29 @@ describe('deleteIdea', () => {
|
|
|
469
412
|
expect(result.result).toMatchObject({ success: true });
|
|
470
413
|
});
|
|
471
414
|
|
|
472
|
-
it('should call
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const mockEq = vi.fn().mockReturnValue({
|
|
477
|
-
then: (resolve: (val: unknown) => void) =>
|
|
478
|
-
Promise.resolve({ data: null, error: null }).then(resolve),
|
|
415
|
+
it('should call API client deleteIdea', async () => {
|
|
416
|
+
mockApiClient.deleteIdea.mockResolvedValue({
|
|
417
|
+
ok: true,
|
|
418
|
+
data: { success: true },
|
|
479
419
|
});
|
|
480
|
-
|
|
481
|
-
vi.mocked(supabase.from('').delete).mockReturnValue({
|
|
482
|
-
...supabase,
|
|
483
|
-
eq: mockEq,
|
|
484
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
420
|
+
const ctx = createMockContext();
|
|
485
421
|
|
|
486
422
|
await deleteIdea(
|
|
487
423
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
488
424
|
ctx
|
|
489
425
|
);
|
|
490
426
|
|
|
491
|
-
expect(
|
|
492
|
-
|
|
493
|
-
|
|
427
|
+
expect(mockApiClient.deleteIdea).toHaveBeenCalledWith(
|
|
428
|
+
'123e4567-e89b-12d3-a456-426614174000'
|
|
429
|
+
);
|
|
494
430
|
});
|
|
495
431
|
|
|
496
|
-
it('should throw error when
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
...supabase,
|
|
503
|
-
eq: vi.fn().mockReturnValue({
|
|
504
|
-
then: (resolve: (val: unknown) => void) =>
|
|
505
|
-
Promise.resolve({ data: null, error: { message: 'Delete failed' } }).then(resolve),
|
|
506
|
-
}),
|
|
507
|
-
} as unknown as ReturnType<SupabaseClient['from']>);
|
|
432
|
+
it('should throw error when API call fails', async () => {
|
|
433
|
+
mockApiClient.deleteIdea.mockResolvedValue({
|
|
434
|
+
ok: false,
|
|
435
|
+
error: 'Delete failed',
|
|
436
|
+
});
|
|
437
|
+
const ctx = createMockContext();
|
|
508
438
|
|
|
509
439
|
await expect(
|
|
510
440
|
deleteIdea({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
@@ -517,18 +447,16 @@ describe('deleteIdea', () => {
|
|
|
517
447
|
// ============================================================================
|
|
518
448
|
|
|
519
449
|
describe('convertIdeaToTask', () => {
|
|
520
|
-
beforeEach(() =>
|
|
450
|
+
beforeEach(() => {});
|
|
521
451
|
|
|
522
452
|
it('should throw error for missing idea_id', async () => {
|
|
523
|
-
const
|
|
524
|
-
const ctx = createMockContext(supabase);
|
|
453
|
+
const ctx = createMockContext();
|
|
525
454
|
|
|
526
455
|
await expect(convertIdeaToTask({}, ctx)).rejects.toThrow(ValidationError);
|
|
527
456
|
});
|
|
528
457
|
|
|
529
458
|
it('should throw error for invalid idea_id UUID', async () => {
|
|
530
|
-
const
|
|
531
|
-
const ctx = createMockContext(supabase);
|
|
459
|
+
const ctx = createMockContext();
|
|
532
460
|
|
|
533
461
|
await expect(
|
|
534
462
|
convertIdeaToTask({ idea_id: 'invalid' }, ctx)
|
|
@@ -536,8 +464,7 @@ describe('convertIdeaToTask', () => {
|
|
|
536
464
|
});
|
|
537
465
|
|
|
538
466
|
it('should throw error for invalid priority', async () => {
|
|
539
|
-
const
|
|
540
|
-
const ctx = createMockContext(supabase);
|
|
467
|
+
const ctx = createMockContext();
|
|
541
468
|
|
|
542
469
|
await expect(
|
|
543
470
|
convertIdeaToTask({
|
|
@@ -547,32 +474,16 @@ describe('convertIdeaToTask', () => {
|
|
|
547
474
|
).rejects.toThrow(ValidationError);
|
|
548
475
|
});
|
|
549
476
|
|
|
550
|
-
it('should throw error when idea not found', async () => {
|
|
551
|
-
const supabase = createMockSupabase({
|
|
552
|
-
selectResult: { data: null, error: { message: 'Not found' } },
|
|
553
|
-
});
|
|
554
|
-
const ctx = createMockContext(supabase);
|
|
555
|
-
|
|
556
|
-
await expect(
|
|
557
|
-
convertIdeaToTask({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
558
|
-
).rejects.toThrow('Idea not found');
|
|
559
|
-
});
|
|
560
|
-
|
|
561
477
|
it('should return error when idea already converted', async () => {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
description: null,
|
|
569
|
-
status: 'in_development',
|
|
570
|
-
converted_to_task_id: 'existing-task-id',
|
|
571
|
-
},
|
|
572
|
-
error: null,
|
|
478
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
479
|
+
ok: true,
|
|
480
|
+
data: {
|
|
481
|
+
success: false,
|
|
482
|
+
error: 'Idea has already been converted to a task',
|
|
483
|
+
existing_task_id: 'existing-task-id',
|
|
573
484
|
},
|
|
574
485
|
});
|
|
575
|
-
const ctx = createMockContext(
|
|
486
|
+
const ctx = createMockContext();
|
|
576
487
|
|
|
577
488
|
const result = await convertIdeaToTask(
|
|
578
489
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -587,21 +498,17 @@ describe('convertIdeaToTask', () => {
|
|
|
587
498
|
});
|
|
588
499
|
|
|
589
500
|
it('should convert idea to task successfully', async () => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const supabase = createMockSupabase({
|
|
600
|
-
selectResult: { data: mockIdea, error: null },
|
|
601
|
-
insertResult: { data: { id: 'task-1', title: 'Feature Request' }, error: null },
|
|
602
|
-
updateResult: { data: null, error: null },
|
|
501
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
502
|
+
ok: true,
|
|
503
|
+
data: {
|
|
504
|
+
success: true,
|
|
505
|
+
task_id: 'task-1',
|
|
506
|
+
task_title: 'Feature Request',
|
|
507
|
+
idea_id: 'idea-1',
|
|
508
|
+
idea_status: 'in_development',
|
|
509
|
+
},
|
|
603
510
|
});
|
|
604
|
-
const ctx = createMockContext(
|
|
511
|
+
const ctx = createMockContext();
|
|
605
512
|
|
|
606
513
|
const result = await convertIdeaToTask(
|
|
607
514
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -617,50 +524,34 @@ describe('convertIdeaToTask', () => {
|
|
|
617
524
|
});
|
|
618
525
|
|
|
619
526
|
it('should use default priority of 3', async () => {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
title: 'Feature Request',
|
|
624
|
-
description: null,
|
|
625
|
-
status: 'planned',
|
|
626
|
-
converted_to_task_id: null,
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
const supabase = createMockSupabase({
|
|
630
|
-
selectResult: { data: mockIdea, error: null },
|
|
631
|
-
insertResult: { data: { id: 'task-1', title: 'Feature Request' }, error: null },
|
|
632
|
-
updateResult: { data: null, error: null },
|
|
527
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
528
|
+
ok: true,
|
|
529
|
+
data: { success: true, task_id: 'task-1' },
|
|
633
530
|
});
|
|
634
|
-
const ctx = createMockContext(
|
|
531
|
+
const ctx = createMockContext();
|
|
635
532
|
|
|
636
533
|
await convertIdeaToTask(
|
|
637
534
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
638
535
|
ctx
|
|
639
536
|
);
|
|
640
537
|
|
|
641
|
-
expect(
|
|
642
|
-
|
|
538
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
539
|
+
'convert_idea_to_task',
|
|
540
|
+
{
|
|
541
|
+
idea_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
643
542
|
priority: 3,
|
|
644
|
-
|
|
543
|
+
estimated_minutes: undefined,
|
|
544
|
+
update_status: true,
|
|
545
|
+
}
|
|
645
546
|
);
|
|
646
547
|
});
|
|
647
548
|
|
|
648
549
|
it('should use custom priority when provided', async () => {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
title: 'Feature Request',
|
|
653
|
-
description: null,
|
|
654
|
-
status: 'planned',
|
|
655
|
-
converted_to_task_id: null,
|
|
656
|
-
};
|
|
657
|
-
|
|
658
|
-
const supabase = createMockSupabase({
|
|
659
|
-
selectResult: { data: mockIdea, error: null },
|
|
660
|
-
insertResult: { data: { id: 'task-1', title: 'Feature Request' }, error: null },
|
|
661
|
-
updateResult: { data: null, error: null },
|
|
550
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
551
|
+
ok: true,
|
|
552
|
+
data: { success: true, task_id: 'task-1' },
|
|
662
553
|
});
|
|
663
|
-
const ctx = createMockContext(
|
|
554
|
+
const ctx = createMockContext();
|
|
664
555
|
|
|
665
556
|
await convertIdeaToTask(
|
|
666
557
|
{
|
|
@@ -670,29 +561,29 @@ describe('convertIdeaToTask', () => {
|
|
|
670
561
|
ctx
|
|
671
562
|
);
|
|
672
563
|
|
|
673
|
-
expect(
|
|
674
|
-
|
|
564
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
565
|
+
'convert_idea_to_task',
|
|
566
|
+
{
|
|
567
|
+
idea_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
675
568
|
priority: 1,
|
|
676
|
-
|
|
569
|
+
estimated_minutes: undefined,
|
|
570
|
+
update_status: true,
|
|
571
|
+
}
|
|
677
572
|
);
|
|
678
573
|
});
|
|
679
574
|
|
|
680
575
|
it('should update idea status to in_development by default', async () => {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const supabase = createMockSupabase({
|
|
691
|
-
selectResult: { data: mockIdea, error: null },
|
|
692
|
-
insertResult: { data: { id: 'task-1', title: 'Feature Request' }, error: null },
|
|
693
|
-
updateResult: { data: null, error: null },
|
|
576
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
577
|
+
ok: true,
|
|
578
|
+
data: {
|
|
579
|
+
success: true,
|
|
580
|
+
task_id: 'task-1',
|
|
581
|
+
task_title: 'Feature Request',
|
|
582
|
+
idea_id: 'idea-1',
|
|
583
|
+
idea_status: 'in_development',
|
|
584
|
+
},
|
|
694
585
|
});
|
|
695
|
-
const ctx = createMockContext(
|
|
586
|
+
const ctx = createMockContext();
|
|
696
587
|
|
|
697
588
|
const result = await convertIdeaToTask(
|
|
698
589
|
{ idea_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -703,23 +594,19 @@ describe('convertIdeaToTask', () => {
|
|
|
703
594
|
});
|
|
704
595
|
|
|
705
596
|
it('should not update status when update_status is false', async () => {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
const supabase = createMockSupabase({
|
|
716
|
-
selectResult: { data: mockIdea, error: null },
|
|
717
|
-
insertResult: { data: { id: 'task-1', title: 'Feature Request' }, error: null },
|
|
718
|
-
updateResult: { data: null, error: null },
|
|
597
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
598
|
+
ok: true,
|
|
599
|
+
data: {
|
|
600
|
+
success: true,
|
|
601
|
+
task_id: 'task-1',
|
|
602
|
+
task_title: 'Feature Request',
|
|
603
|
+
idea_id: 'idea-1',
|
|
604
|
+
idea_status: 'planned',
|
|
605
|
+
},
|
|
719
606
|
});
|
|
720
|
-
const ctx = createMockContext(
|
|
607
|
+
const ctx = createMockContext();
|
|
721
608
|
|
|
722
|
-
|
|
609
|
+
await convertIdeaToTask(
|
|
723
610
|
{
|
|
724
611
|
idea_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
725
612
|
update_status: false,
|
|
@@ -727,27 +614,26 @@ describe('convertIdeaToTask', () => {
|
|
|
727
614
|
ctx
|
|
728
615
|
);
|
|
729
616
|
|
|
730
|
-
expect(
|
|
617
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
618
|
+
'convert_idea_to_task',
|
|
619
|
+
{
|
|
620
|
+
idea_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
621
|
+
priority: 3,
|
|
622
|
+
estimated_minutes: undefined,
|
|
623
|
+
update_status: false,
|
|
624
|
+
}
|
|
625
|
+
);
|
|
731
626
|
});
|
|
732
627
|
|
|
733
|
-
it('should throw error when
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
title: 'Feature Request',
|
|
738
|
-
description: null,
|
|
739
|
-
status: 'planned',
|
|
740
|
-
converted_to_task_id: null,
|
|
741
|
-
};
|
|
742
|
-
|
|
743
|
-
const supabase = createMockSupabase({
|
|
744
|
-
selectResult: { data: mockIdea, error: null },
|
|
745
|
-
insertResult: { data: null, error: { message: 'Insert failed' } },
|
|
628
|
+
it('should throw error when API call fails', async () => {
|
|
629
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
630
|
+
ok: false,
|
|
631
|
+
error: 'Idea not found',
|
|
746
632
|
});
|
|
747
|
-
const ctx = createMockContext(
|
|
633
|
+
const ctx = createMockContext();
|
|
748
634
|
|
|
749
635
|
await expect(
|
|
750
636
|
convertIdeaToTask({ idea_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
751
|
-
).rejects.toThrow('Failed to
|
|
637
|
+
).rejects.toThrow('Failed to convert idea');
|
|
752
638
|
});
|
|
753
639
|
});
|