@critical-path/client 0.20.5 → 0.20.6
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/package.json +9 -5
- package/CHANGELOG.md +0 -657
- package/dist/cli.test.d.ts +0 -2
- package/dist/cli.test.d.ts.map +0 -1
- package/dist/cli.test.js +0 -225
- package/dist/cli.test.js.map +0 -1
- package/dist/contract.test.d.ts +0 -2
- package/dist/contract.test.d.ts.map +0 -1
- package/dist/contract.test.js +0 -74
- package/dist/contract.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -359
- package/dist/index.test.js.map +0 -1
- package/dist/routes.test.d.ts +0 -2
- package/dist/routes.test.d.ts.map +0 -1
- package/dist/routes.test.js +0 -95
- package/dist/routes.test.js.map +0 -1
- package/dist/transport.test.d.ts +0 -2
- package/dist/transport.test.d.ts.map +0 -1
- package/dist/transport.test.js +0 -89
- package/dist/transport.test.js.map +0 -1
- package/src/bin/cli.ts +0 -480
- package/src/cli.test.ts +0 -266
- package/src/contract.test.ts +0 -88
- package/src/index.test.ts +0 -415
- package/src/index.ts +0 -888
- package/src/routes.test.ts +0 -96
- package/src/transport.test.ts +0 -111
- package/tsconfig.json +0 -8
- package/tsconfig.tsbuildinfo +0 -1
package/src/index.test.ts
DELETED
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { CriticalPathClient } from './index.js';
|
|
3
|
-
|
|
4
|
-
describe('@critical-path/client Tests', () => {
|
|
5
|
-
it('instantiates client and accepts custom mock fetch', async () => {
|
|
6
|
-
const mockFetch = async (url: string | URL | Request, init?: RequestInit) => {
|
|
7
|
-
const urlStr = url.toString();
|
|
8
|
-
if (urlStr.endsWith('/projects') && (!init?.method || init.method.toUpperCase() === 'GET')) {
|
|
9
|
-
return new Response(JSON.stringify({ projects: [{ id: 'p1', key: 'TEST', name: 'Mock Proj' }] }), { status: 200 });
|
|
10
|
-
}
|
|
11
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const client = new CriticalPathClient({
|
|
15
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
16
|
-
fetch: mockFetch as typeof fetch
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const projects = await client.getProjects();
|
|
20
|
-
expect(projects.length).toBe(1);
|
|
21
|
-
expect(projects[0].name).toBe('Mock Proj');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('fetches workflows and task allowed transitions via client SDK', async () => {
|
|
25
|
-
const mockFetch = async (url: string | URL | Request, init?: RequestInit) => {
|
|
26
|
-
const urlStr = url.toString();
|
|
27
|
-
if (urlStr.endsWith('/workflows')) {
|
|
28
|
-
return new Response(JSON.stringify({ workflows: [{ id: 'wf1', name: 'SDK Workflow' }] }), { status: 200 });
|
|
29
|
-
}
|
|
30
|
-
if (urlStr.endsWith('/tasks/t1/transitions')) {
|
|
31
|
-
return new Response(JSON.stringify({
|
|
32
|
-
allowedNextStatuses: ['in_progress', 'canceled'],
|
|
33
|
-
allowedPreviousStatuses: ['backlog']
|
|
34
|
-
}), { status: 200 });
|
|
35
|
-
}
|
|
36
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const client = new CriticalPathClient({
|
|
40
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
41
|
-
fetch: mockFetch as typeof fetch
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const workflows = await client.getWorkflows();
|
|
45
|
-
expect(workflows).toHaveLength(1);
|
|
46
|
-
expect(workflows[0].name).toBe('SDK Workflow');
|
|
47
|
-
|
|
48
|
-
const transitions = await client.getAllowedTaskTransitions('t1');
|
|
49
|
-
expect(transitions).toEqual(['in_progress', 'canceled']);
|
|
50
|
-
|
|
51
|
-
const previousTransitions = await client.getAllowedPreviousTaskTransitions('t1');
|
|
52
|
-
expect(previousTransitions).toEqual(['backlog']);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('handles comments and attachments through client SDK methods', async () => {
|
|
56
|
-
const mockFetch = async (url: string | URL | Request, init?: RequestInit) => {
|
|
57
|
-
const urlStr = url.toString();
|
|
58
|
-
const method = init?.method?.toUpperCase() || 'GET';
|
|
59
|
-
|
|
60
|
-
if (urlStr.includes('/comments?taskId=t1') && method === 'GET') {
|
|
61
|
-
return new Response(JSON.stringify({ comments: [{ id: 'c1', taskId: 't1', content: 'SDK Comment', authorId: 'u1', authorType: 'user' }] }), { status: 200 });
|
|
62
|
-
}
|
|
63
|
-
if (urlStr.endsWith('/comments') && method === 'POST') {
|
|
64
|
-
const body = JSON.parse(init?.body as string);
|
|
65
|
-
return new Response(JSON.stringify({ comment: { id: 'c2', ...body } }), { status: 201 });
|
|
66
|
-
}
|
|
67
|
-
if (urlStr.endsWith('/comments/c1') && method === 'PATCH') {
|
|
68
|
-
const body = JSON.parse(init?.body as string);
|
|
69
|
-
return new Response(JSON.stringify({ comment: { id: 'c1', content: body.content } }), { status: 200 });
|
|
70
|
-
}
|
|
71
|
-
if (urlStr.endsWith('/comments/c1/reactions') && method === 'POST') {
|
|
72
|
-
const body = JSON.parse(init?.body as string);
|
|
73
|
-
return new Response(JSON.stringify({ comment: { id: 'c1', reactions: [body] } }), { status: 200 });
|
|
74
|
-
}
|
|
75
|
-
if (urlStr.split('?')[0].endsWith('/comments/c1/reactions') && method === 'DELETE') {
|
|
76
|
-
return new Response(JSON.stringify({ comment: { id: 'c1', reactions: [] } }), { status: 200 });
|
|
77
|
-
}
|
|
78
|
-
if (urlStr.endsWith('/comments/c1') && method === 'DELETE') {
|
|
79
|
-
return new Response(JSON.stringify({ success: true }), { status: 200 });
|
|
80
|
-
}
|
|
81
|
-
if (urlStr.includes('/attachments?taskId=t1') && method === 'GET') {
|
|
82
|
-
return new Response(JSON.stringify({ attachments: [{ id: 'a1', filename: 'SDK Doc', mimeType: 'text/plain', sizeBytes: 50, url: 'https://cdn.example.com/a1' }] }), { status: 200 });
|
|
83
|
-
}
|
|
84
|
-
if (urlStr.endsWith('/attachments') && method === 'POST') {
|
|
85
|
-
const body = JSON.parse(init?.body as string);
|
|
86
|
-
return new Response(JSON.stringify({ attachment: { id: 'a2', ...body } }), { status: 201 });
|
|
87
|
-
}
|
|
88
|
-
if (urlStr.endsWith('/attachments/upload') && method === 'POST') {
|
|
89
|
-
const body = JSON.parse(init?.body as string);
|
|
90
|
-
return new Response(JSON.stringify({ attachment: { id: 'a_up', ...body, url: 'https://cdn.example.com/uploaded.png' } }), { status: 201 });
|
|
91
|
-
}
|
|
92
|
-
if (urlStr.endsWith('/attachments/a1') && method === 'DELETE') {
|
|
93
|
-
return new Response(JSON.stringify({ success: true }), { status: 200 });
|
|
94
|
-
}
|
|
95
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const client = new CriticalPathClient({
|
|
99
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
100
|
-
fetch: mockFetch as typeof fetch
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const comments = await client.getComments('t1');
|
|
104
|
-
expect(comments).toHaveLength(1);
|
|
105
|
-
expect(comments[0].content).toBe('SDK Comment');
|
|
106
|
-
|
|
107
|
-
const createdComment = await client.addComment({ taskId: 't1', content: 'New comment' });
|
|
108
|
-
expect(createdComment.id).toBe('c2');
|
|
109
|
-
|
|
110
|
-
const updatedComment = await client.updateComment('c1', { content: 'Updated' });
|
|
111
|
-
expect(updatedComment.content).toBe('Updated');
|
|
112
|
-
|
|
113
|
-
const reacted = await client.addCommentReaction('c1', { emoji: '🙌' });
|
|
114
|
-
expect(reacted.reactions).toHaveLength(1);
|
|
115
|
-
expect(reacted.reactions?.[0].emoji).toBe('🙌');
|
|
116
|
-
|
|
117
|
-
const unreacted = await client.removeCommentReaction('c1', { emoji: '🙌' });
|
|
118
|
-
expect(unreacted.reactions).toHaveLength(0);
|
|
119
|
-
|
|
120
|
-
const deletedComment = await client.deleteComment('c1');
|
|
121
|
-
expect(deletedComment).toBe(true);
|
|
122
|
-
|
|
123
|
-
const attachments = await client.getAttachments({ taskId: 't1' });
|
|
124
|
-
expect(attachments).toHaveLength(1);
|
|
125
|
-
expect(attachments[0].filename).toBe('SDK Doc');
|
|
126
|
-
|
|
127
|
-
const createdAtt = await client.createAttachment({ filename: 'file.txt', mimeType: 'text/plain', sizeBytes: 12, url: 'https://example.com/file.txt' });
|
|
128
|
-
expect(createdAtt.id).toBe('a2');
|
|
129
|
-
|
|
130
|
-
const uploadedAtt = await client.uploadAttachmentFile({ filename: 'uploaded.png', data: 'base64data' });
|
|
131
|
-
expect(uploadedAtt.id).toBe('a_up');
|
|
132
|
-
expect(uploadedAtt.url).toBe('https://cdn.example.com/uploaded.png');
|
|
133
|
-
|
|
134
|
-
const deletedAtt = await client.deleteAttachment('a1');
|
|
135
|
-
expect(deletedAtt).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('handles deliverables CRUD and summary rollups via client SDK', async () => {
|
|
139
|
-
const mockDeliverable = {
|
|
140
|
-
id: 'd1',
|
|
141
|
-
projectId: 'p1',
|
|
142
|
-
title: 'Hero Cut 30s',
|
|
143
|
-
status: 'planned' as const,
|
|
144
|
-
format: 'ProRes 422',
|
|
145
|
-
outputUrls: [],
|
|
146
|
-
createdAt: '2026-09-04T00:00:00Z',
|
|
147
|
-
updatedAt: '2026-09-04T00:00:00Z'
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const mockSummary = {
|
|
151
|
-
deliverable: mockDeliverable,
|
|
152
|
-
totalTasks: 4,
|
|
153
|
-
completedTasks: 2,
|
|
154
|
-
activeTasks: 2,
|
|
155
|
-
progressPercentage: 50,
|
|
156
|
-
estimatedHours: 20,
|
|
157
|
-
loggedHours: 12
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const mockFetch = async (url: string | URL | Request, init?: RequestInit) => {
|
|
161
|
-
const urlStr = url.toString();
|
|
162
|
-
const method = init?.method?.toUpperCase() || 'GET';
|
|
163
|
-
|
|
164
|
-
if (urlStr.includes('/deliverables?projectId=p1') && method === 'GET') {
|
|
165
|
-
return new Response(JSON.stringify({ deliverables: [mockDeliverable] }), { status: 200 });
|
|
166
|
-
}
|
|
167
|
-
if (urlStr.endsWith('/deliverables/d1/summary') && method === 'GET') {
|
|
168
|
-
return new Response(JSON.stringify({ summary: mockSummary }), { status: 200 });
|
|
169
|
-
}
|
|
170
|
-
if (urlStr.endsWith('/deliverables/d1') && method === 'GET') {
|
|
171
|
-
return new Response(JSON.stringify({ deliverable: mockDeliverable }), { status: 200 });
|
|
172
|
-
}
|
|
173
|
-
if (urlStr.endsWith('/deliverables') && method === 'POST') {
|
|
174
|
-
const body = JSON.parse(init?.body as string);
|
|
175
|
-
return new Response(JSON.stringify({ deliverable: { id: 'd2', ...body } }), { status: 201 });
|
|
176
|
-
}
|
|
177
|
-
if (urlStr.endsWith('/deliverables/d1') && method === 'PATCH') {
|
|
178
|
-
const body = JSON.parse(init?.body as string);
|
|
179
|
-
return new Response(JSON.stringify({ deliverable: { ...mockDeliverable, ...body } }), { status: 200 });
|
|
180
|
-
}
|
|
181
|
-
if (urlStr.endsWith('/deliverables/d1') && method === 'DELETE') {
|
|
182
|
-
return new Response(JSON.stringify({ success: true }), { status: 200 });
|
|
183
|
-
}
|
|
184
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const client = new CriticalPathClient({
|
|
188
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
189
|
-
fetch: mockFetch as typeof fetch
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const list = await client.getDeliverables('p1');
|
|
193
|
-
expect(list).toHaveLength(1);
|
|
194
|
-
expect(list[0].title).toBe('Hero Cut 30s');
|
|
195
|
-
|
|
196
|
-
const single = await client.getDeliverable('d1');
|
|
197
|
-
expect(single.id).toBe('d1');
|
|
198
|
-
|
|
199
|
-
const summary = await client.getDeliverableSummary('d1');
|
|
200
|
-
expect(summary.totalTasks).toBe(4);
|
|
201
|
-
expect(summary.progressPercentage).toBe(50);
|
|
202
|
-
|
|
203
|
-
const created = await client.createDeliverable({
|
|
204
|
-
projectId: 'p1',
|
|
205
|
-
title: 'Hero Cut 15s',
|
|
206
|
-
format: 'ProRes 422'
|
|
207
|
-
});
|
|
208
|
-
expect(created.id).toBe('d2');
|
|
209
|
-
|
|
210
|
-
const updated = await client.updateDeliverable('d1', { status: 'delivered' });
|
|
211
|
-
expect(updated.status).toBe('delivered');
|
|
212
|
-
|
|
213
|
-
const deleted = await client.deleteDeliverable('d1');
|
|
214
|
-
expect(deleted).toBe(true);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('retrieves task lifecycle state and dependencies via client SDK', async () => {
|
|
218
|
-
const mockState = {
|
|
219
|
-
semanticStatus: 'not_started' as const,
|
|
220
|
-
isReady: false,
|
|
221
|
-
isBlocked: true,
|
|
222
|
-
blockingTaskIds: ['task_upstream'],
|
|
223
|
-
isOverdue: false,
|
|
224
|
-
isUpcoming: false,
|
|
225
|
-
isUnplanned: true,
|
|
226
|
-
isUnassigned: false,
|
|
227
|
-
isStalled: false,
|
|
228
|
-
isOverEstimate: false,
|
|
229
|
-
isPaceWarning: false,
|
|
230
|
-
isDone: false,
|
|
231
|
-
isActive: false,
|
|
232
|
-
isCancelled: false
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
const mockFetch = async (url: string | URL | Request) => {
|
|
236
|
-
const urlStr = url.toString();
|
|
237
|
-
if (urlStr.endsWith('/tasks/t1/lifecycle')) {
|
|
238
|
-
return new Response(JSON.stringify({ state: mockState }), { status: 200 });
|
|
239
|
-
}
|
|
240
|
-
if (urlStr.endsWith('/tasks/t1/dependencies')) {
|
|
241
|
-
return new Response(JSON.stringify({
|
|
242
|
-
graph: {
|
|
243
|
-
taskId: 't1',
|
|
244
|
-
upstreamTasks: [{ id: 'task_upstream', title: 'API', status: 'in_progress' }],
|
|
245
|
-
downstreamTasks: [],
|
|
246
|
-
dependencies: [{ id: 'dep1', taskId: 't1', dependsOnTaskId: 'task_upstream', type: 'blocking' }]
|
|
247
|
-
}
|
|
248
|
-
}), { status: 200 });
|
|
249
|
-
}
|
|
250
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const client = new CriticalPathClient({
|
|
254
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
255
|
-
fetch: mockFetch as typeof fetch
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
const lifecycle = await client.getTaskLifecycleState('t1');
|
|
259
|
-
expect(lifecycle.isBlocked).toBe(true);
|
|
260
|
-
expect(lifecycle.isReady).toBe(false);
|
|
261
|
-
expect(lifecycle.blockingTaskIds).toEqual(['task_upstream']);
|
|
262
|
-
|
|
263
|
-
const deps = await client.getTaskDependencies('t1');
|
|
264
|
-
expect(deps.upstreamTasks).toHaveLength(1);
|
|
265
|
-
expect(deps.upstreamTasks[0].id).toBe('task_upstream');
|
|
266
|
-
expect(deps.dependencies).toHaveLength(1);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
it('fetches critical path and timeline ladder through client SDK', async () => {
|
|
270
|
-
const mockFetch = async (url: string | URL | Request) => {
|
|
271
|
-
const urlStr = url.toString();
|
|
272
|
-
|
|
273
|
-
if (urlStr.endsWith('/projects/p1/critical-path')) {
|
|
274
|
-
return new Response(JSON.stringify({
|
|
275
|
-
analysis: {
|
|
276
|
-
projectId: 'p1',
|
|
277
|
-
calculatedAt: '2026-09-11T10:00:00Z',
|
|
278
|
-
totalDurationHours: 18,
|
|
279
|
-
criticalTaskIds: ['t1', 't2'],
|
|
280
|
-
tasks: []
|
|
281
|
-
}
|
|
282
|
-
}), { status: 200 });
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (urlStr.includes('/projects/p1/ladder?level=macro')) {
|
|
286
|
-
return new Response(JSON.stringify({
|
|
287
|
-
ladder: {
|
|
288
|
-
projectId: 'p1',
|
|
289
|
-
generatedAt: '2026-09-11T10:00:00Z',
|
|
290
|
-
level: 'macro',
|
|
291
|
-
macro: {
|
|
292
|
-
projectId: 'p1',
|
|
293
|
-
projectName: 'Client Project',
|
|
294
|
-
totalDurationHours: 18,
|
|
295
|
-
criticalPathDurationHours: 18,
|
|
296
|
-
overallProgressPercentage: 50,
|
|
297
|
-
health: 'on_track',
|
|
298
|
-
totalTasks: 2,
|
|
299
|
-
completedTasks: 1,
|
|
300
|
-
inProgressTasks: 1,
|
|
301
|
-
blockedTasks: 0,
|
|
302
|
-
totalEstimatedHours: 18,
|
|
303
|
-
totalLoggedHours: 9,
|
|
304
|
-
phases: []
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}), { status: 200 });
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (urlStr.endsWith('/tasks/t2/ladder')) {
|
|
311
|
-
return new Response(JSON.stringify({
|
|
312
|
-
taskLadder: {
|
|
313
|
-
taskId: 't2',
|
|
314
|
-
standard: { id: 't2', title: 'Task 2', status: 'in_progress', priority: 'high' },
|
|
315
|
-
concrete: { taskId: 't2', attachments: [], deliverables: [], todos: [], timeEntries: [], dailyEffortDistribution: [], activities: [] }
|
|
316
|
-
}
|
|
317
|
-
}), { status: 200 });
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (urlStr.includes('/projects/p1/workload')) {
|
|
321
|
-
return new Response(JSON.stringify({
|
|
322
|
-
workload: {
|
|
323
|
-
projectId: 'p1',
|
|
324
|
-
startDate: '2026-09-01',
|
|
325
|
-
endDate: '2026-09-14',
|
|
326
|
-
interval: 'week',
|
|
327
|
-
groupBy: 'assignee',
|
|
328
|
-
metric: 'blended',
|
|
329
|
-
seriesKeys: ['u1', 'u2'],
|
|
330
|
-
seriesLabels: { u1: 'Alice', u2: 'Bob' },
|
|
331
|
-
buckets: [
|
|
332
|
-
{ date: '2026-09-01', timestamp: 1788220800000, totalHours: 20, values: { u1: 12, u2: 8 } }
|
|
333
|
-
],
|
|
334
|
-
totalHours: 20
|
|
335
|
-
}
|
|
336
|
-
}), { status: 200 });
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
const client = new CriticalPathClient({
|
|
343
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
344
|
-
fetch: mockFetch as typeof fetch
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
const cpm = await client.calculateCriticalPath('p1');
|
|
348
|
-
expect(cpm.totalDurationHours).toBe(18);
|
|
349
|
-
expect(cpm.criticalTaskIds).toEqual(['t1', 't2']);
|
|
350
|
-
|
|
351
|
-
const ladder = await client.getTimelineLadder('p1', { level: 'macro' });
|
|
352
|
-
expect(ladder.macro?.projectName).toBe('Client Project');
|
|
353
|
-
expect(ladder.level).toBe('macro');
|
|
354
|
-
|
|
355
|
-
const taskLadder = await client.getTaskLadder('t2');
|
|
356
|
-
expect(taskLadder.taskId).toBe('t2');
|
|
357
|
-
expect(taskLadder.standard.title).toBe('Task 2');
|
|
358
|
-
|
|
359
|
-
const workload = await client.getWorkloadDistribution('p1', { interval: 'week', metric: 'blended' });
|
|
360
|
-
expect(workload.projectId).toBe('p1');
|
|
361
|
-
expect(workload.totalHours).toBe(20);
|
|
362
|
-
expect(workload.seriesKeys).toEqual(['u1', 'u2']);
|
|
363
|
-
expect(workload.buckets[0].values.u1).toBe(12);
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
it('posts agent status updates via client.updateStatus', async () => {
|
|
367
|
-
let capturedBody: any = null;
|
|
368
|
-
const mockFetch = async (url: string | URL | Request, init?: RequestInit) => {
|
|
369
|
-
const urlStr = url.toString();
|
|
370
|
-
if (urlStr.endsWith('/status') && init?.method === 'POST') {
|
|
371
|
-
capturedBody = JSON.parse(init.body as string);
|
|
372
|
-
return new Response(JSON.stringify({ success: true, status: capturedBody.status, timestamp: 123456789 }), { status: 200 });
|
|
373
|
-
}
|
|
374
|
-
return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
const client = new CriticalPathClient({
|
|
378
|
-
baseUrl: 'http://localhost:3000/api/critical-path',
|
|
379
|
-
fetch: mockFetch as typeof fetch
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
const result = await client.updateStatus('Running unit tests', {
|
|
383
|
-
taskId: 't1',
|
|
384
|
-
projectId: 'p1',
|
|
385
|
-
details: 'vitest run 15 passed'
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
expect(result.success).toBe(true);
|
|
389
|
-
expect(result.status).toBe('Running unit tests');
|
|
390
|
-
expect(capturedBody).toEqual({
|
|
391
|
-
status: 'Running unit tests',
|
|
392
|
-
taskId: 't1',
|
|
393
|
-
projectId: 'p1',
|
|
394
|
-
details: 'vitest run 15 passed',
|
|
395
|
-
isEngaged: true
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
it('resolves delete methods to false on 404 and still throws other errors', async () => {
|
|
400
|
-
let status = 404;
|
|
401
|
-
const mockFetch = async () =>
|
|
402
|
-
new Response(JSON.stringify({ error: status === 404 ? 'Not found' : 'Internal Server Error' }), {
|
|
403
|
-
status,
|
|
404
|
-
headers: { 'Content-Type': 'application/json' }
|
|
405
|
-
});
|
|
406
|
-
const client = new CriticalPathClient({ baseUrl: 'http://localhost/api', fetch: mockFetch as typeof fetch });
|
|
407
|
-
|
|
408
|
-
expect(await client.deleteTask('missing')).toBe(false);
|
|
409
|
-
expect(await client.deleteComment('missing')).toBe(false);
|
|
410
|
-
|
|
411
|
-
status = 500;
|
|
412
|
-
await expect(client.deleteTask('t1')).rejects.toThrow('Internal Server Error');
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|