@aaronshaf/plane 0.1.3 → 0.1.5
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 +1 -1
- package/scripts/check-coverage.ts +2 -2
- package/src/api.ts +67 -59
- package/src/app.ts +78 -0
- package/src/bin.ts +6 -71
- package/src/commands/cycles.ts +104 -85
- package/src/commands/init.ts +57 -55
- package/src/commands/intake.ts +82 -65
- package/src/commands/issue.ts +418 -314
- package/src/commands/issues.ts +51 -43
- package/src/commands/labels.ts +52 -43
- package/src/commands/members.ts +25 -19
- package/src/commands/modules.ts +136 -99
- package/src/commands/pages.ts +58 -49
- package/src/commands/projects.ts +28 -22
- package/src/commands/states.ts +31 -25
- package/src/config.ts +152 -154
- package/src/format.ts +15 -8
- package/src/output.ts +28 -28
- package/src/resolve.ts +66 -53
- package/tests/api.test.ts +178 -155
- package/tests/cycles-extended.test.ts +205 -162
- package/tests/format.test.ts +72 -54
- package/tests/helpers/mock-api.ts +16 -14
- package/tests/intake.test.ts +173 -139
- package/tests/issue-activity.test.ts +191 -158
- package/tests/issue-commands.test.ts +587 -304
- package/tests/issue-comments-worklogs.test.ts +337 -265
- package/tests/issue-links.test.ts +229 -193
- package/tests/modules.test.ts +283 -239
- package/tests/new-schemas.test.ts +203 -183
- package/tests/new-schemas2.test.ts +195 -183
- package/tests/output.test.ts +66 -64
- package/tests/pages.test.ts +122 -108
- package/tests/resolve.test.ts +186 -156
- package/tests/schemas.test.ts +215 -177
|
@@ -1,291 +1,363 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
afterAll,
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeAll,
|
|
5
|
+
beforeEach,
|
|
6
|
+
describe,
|
|
7
|
+
expect,
|
|
8
|
+
it,
|
|
9
|
+
} from "bun:test";
|
|
10
|
+
import { Effect } from "effect";
|
|
11
|
+
import { http, HttpResponse } from "msw";
|
|
12
|
+
import { setupServer } from "msw/node";
|
|
13
|
+
import { _clearProjectCache } from "@/resolve";
|
|
6
14
|
|
|
7
|
-
const BASE = "http://cw-test.local"
|
|
8
|
-
const WS = "testws"
|
|
15
|
+
const BASE = "http://cw-test.local";
|
|
16
|
+
const WS = "testws";
|
|
9
17
|
|
|
10
|
-
const PROJECTS = [
|
|
11
|
-
|
|
18
|
+
const PROJECTS = [
|
|
19
|
+
{ id: "proj-acme", identifier: "ACME", name: "Acme Project" },
|
|
20
|
+
];
|
|
21
|
+
const ISSUES = [
|
|
22
|
+
{
|
|
23
|
+
id: "i1",
|
|
24
|
+
sequence_id: 29,
|
|
25
|
+
name: "Migrate Button",
|
|
26
|
+
priority: "high",
|
|
27
|
+
state: "s1",
|
|
28
|
+
},
|
|
29
|
+
];
|
|
12
30
|
const COMMENTS = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
31
|
+
{
|
|
32
|
+
id: "c1",
|
|
33
|
+
comment_html: "<p>Fixed in v2</p>",
|
|
34
|
+
actor_detail: { display_name: "Aaron" },
|
|
35
|
+
created_at: "2025-01-15T10:30:00Z",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "c2",
|
|
39
|
+
comment_html: "<p>LGTM</p>",
|
|
40
|
+
actor_detail: { display_name: "Bea" },
|
|
41
|
+
created_at: "2025-01-16T09:00:00Z",
|
|
42
|
+
},
|
|
43
|
+
];
|
|
26
44
|
const WORKLOGS = [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
]
|
|
45
|
+
{
|
|
46
|
+
id: "w1",
|
|
47
|
+
description: "Code review",
|
|
48
|
+
duration: 90,
|
|
49
|
+
logged_by_detail: { display_name: "Aaron" },
|
|
50
|
+
created_at: "2025-01-15T10:00:00Z",
|
|
51
|
+
},
|
|
52
|
+
];
|
|
35
53
|
|
|
36
54
|
const server = setupServer(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
55
|
+
http.get(`${BASE}/api/v1/workspaces/${WS}/projects/`, () =>
|
|
56
|
+
HttpResponse.json({ results: PROJECTS }),
|
|
57
|
+
),
|
|
58
|
+
http.get(`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/`, () =>
|
|
59
|
+
HttpResponse.json({ results: ISSUES }),
|
|
60
|
+
),
|
|
61
|
+
http.get(
|
|
62
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/comments/`,
|
|
63
|
+
() => HttpResponse.json({ results: COMMENTS }),
|
|
64
|
+
),
|
|
65
|
+
http.get(
|
|
66
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/worklogs/`,
|
|
67
|
+
() => HttpResponse.json({ results: WORKLOGS }),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
50
70
|
|
|
51
|
-
beforeAll(() => server.listen({ onUnhandledRequest: "error" }))
|
|
52
|
-
afterAll(() => server.close())
|
|
71
|
+
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
|
72
|
+
afterAll(() => server.close());
|
|
53
73
|
|
|
54
74
|
beforeEach(() => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
})
|
|
75
|
+
_clearProjectCache();
|
|
76
|
+
process.env["PLANE_HOST"] = BASE;
|
|
77
|
+
process.env["PLANE_WORKSPACE"] = WS;
|
|
78
|
+
process.env["PLANE_API_TOKEN"] = "test-token";
|
|
79
|
+
});
|
|
60
80
|
|
|
61
81
|
afterEach(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
82
|
+
server.resetHandlers();
|
|
83
|
+
delete process.env["PLANE_HOST"];
|
|
84
|
+
delete process.env["PLANE_WORKSPACE"];
|
|
85
|
+
delete process.env["PLANE_API_TOKEN"];
|
|
86
|
+
});
|
|
67
87
|
|
|
68
88
|
describe("issueCommentsList", () => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
it("lists comments with author and stripped HTML", async () => {
|
|
90
|
+
const { issueCommentsList } = await import("@/commands/issue");
|
|
91
|
+
const logs: string[] = [];
|
|
92
|
+
const orig = console.log;
|
|
93
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
94
|
+
try {
|
|
95
|
+
await Effect.runPromise(
|
|
96
|
+
(issueCommentsList as any).handler({ ref: "ACME-29" }),
|
|
97
|
+
);
|
|
98
|
+
} finally {
|
|
99
|
+
console.log = orig;
|
|
100
|
+
}
|
|
101
|
+
const output = logs.join("\n");
|
|
102
|
+
expect(output).toContain("c1");
|
|
103
|
+
expect(output).toContain("Aaron");
|
|
104
|
+
expect(output).toContain("Fixed in v2");
|
|
105
|
+
expect(output).not.toContain("<p>");
|
|
106
|
+
});
|
|
85
107
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
it("shows 'No comments' when empty", async () => {
|
|
109
|
+
server.use(
|
|
110
|
+
http.get(
|
|
111
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/comments/`,
|
|
112
|
+
() => HttpResponse.json({ results: [] }),
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
const { issueCommentsList } = await import("@/commands/issue");
|
|
116
|
+
const logs: string[] = [];
|
|
117
|
+
const orig = console.log;
|
|
118
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
119
|
+
try {
|
|
120
|
+
await Effect.runPromise(
|
|
121
|
+
(issueCommentsList as any).handler({ ref: "ACME-29" }),
|
|
122
|
+
);
|
|
123
|
+
} finally {
|
|
124
|
+
console.log = orig;
|
|
125
|
+
}
|
|
126
|
+
expect(logs.join("\n")).toBe("No comments");
|
|
127
|
+
});
|
|
103
128
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
it("shows '?' for missing actor", async () => {
|
|
130
|
+
server.use(
|
|
131
|
+
http.get(
|
|
132
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/comments/`,
|
|
133
|
+
() =>
|
|
134
|
+
HttpResponse.json({
|
|
135
|
+
results: [
|
|
136
|
+
{
|
|
137
|
+
id: "c3",
|
|
138
|
+
comment_html: "<p>hi</p>",
|
|
139
|
+
created_at: "2025-01-17T10:00:00Z",
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
}),
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
const { issueCommentsList } = await import("@/commands/issue");
|
|
146
|
+
const logs: string[] = [];
|
|
147
|
+
const orig = console.log;
|
|
148
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
149
|
+
try {
|
|
150
|
+
await Effect.runPromise(
|
|
151
|
+
(issueCommentsList as any).handler({ ref: "ACME-29" }),
|
|
152
|
+
);
|
|
153
|
+
} finally {
|
|
154
|
+
console.log = orig;
|
|
155
|
+
}
|
|
156
|
+
expect(logs.join("\n")).toContain("?");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
122
159
|
|
|
123
160
|
describe("issueCommentUpdate", () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
161
|
+
it("updates a comment", async () => {
|
|
162
|
+
let patchedBody: unknown;
|
|
163
|
+
server.use(
|
|
164
|
+
http.patch(
|
|
165
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/comments/c1/`,
|
|
166
|
+
async ({ request }) => {
|
|
167
|
+
patchedBody = await request.json();
|
|
168
|
+
return HttpResponse.json({
|
|
169
|
+
id: "c1",
|
|
170
|
+
comment_html: "<p>Updated</p>",
|
|
171
|
+
created_at: "2025-01-15T10:30:00Z",
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
const { issueCommentUpdate } = await import("@/commands/issue");
|
|
177
|
+
const logs: string[] = [];
|
|
178
|
+
const orig = console.log;
|
|
179
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
180
|
+
try {
|
|
181
|
+
await Effect.runPromise(
|
|
182
|
+
(issueCommentUpdate as any).handler({
|
|
183
|
+
ref: "ACME-29",
|
|
184
|
+
commentId: "c1",
|
|
185
|
+
text: "Updated text",
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
} finally {
|
|
189
|
+
console.log = orig;
|
|
190
|
+
}
|
|
191
|
+
expect((patchedBody as any).comment_html).toContain("Updated text");
|
|
192
|
+
expect(logs.join("\n")).toContain("c1");
|
|
193
|
+
expect(logs.join("\n")).toContain("updated");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
151
196
|
|
|
152
197
|
describe("issueCommentDelete", () => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
198
|
+
it("deletes a comment", async () => {
|
|
199
|
+
let deleted = false;
|
|
200
|
+
server.use(
|
|
201
|
+
http.delete(
|
|
202
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/comments/c1/`,
|
|
203
|
+
() => {
|
|
204
|
+
deleted = true;
|
|
205
|
+
return new HttpResponse(null, { status: 204 });
|
|
206
|
+
},
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
const { issueCommentDelete } = await import("@/commands/issue");
|
|
210
|
+
const logs: string[] = [];
|
|
211
|
+
const orig = console.log;
|
|
212
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
213
|
+
try {
|
|
214
|
+
await Effect.runPromise(
|
|
215
|
+
(issueCommentDelete as any).handler({
|
|
216
|
+
ref: "ACME-29",
|
|
217
|
+
commentId: "c1",
|
|
218
|
+
}),
|
|
219
|
+
);
|
|
220
|
+
} finally {
|
|
221
|
+
console.log = orig;
|
|
222
|
+
}
|
|
223
|
+
expect(deleted).toBe(true);
|
|
224
|
+
expect(logs.join("\n")).toContain("c1");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
179
227
|
|
|
180
228
|
describe("issueWorklogsList", () => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
229
|
+
it("lists worklogs with hours", async () => {
|
|
230
|
+
const { issueWorklogsList } = await import("@/commands/issue");
|
|
231
|
+
const logs: string[] = [];
|
|
232
|
+
const orig = console.log;
|
|
233
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
234
|
+
try {
|
|
235
|
+
await Effect.runPromise(
|
|
236
|
+
(issueWorklogsList as any).handler({ ref: "ACME-29" }),
|
|
237
|
+
);
|
|
238
|
+
} finally {
|
|
239
|
+
console.log = orig;
|
|
240
|
+
}
|
|
241
|
+
const output = logs.join("\n");
|
|
242
|
+
expect(output).toContain("w1");
|
|
243
|
+
expect(output).toContain("1.5h");
|
|
244
|
+
expect(output).toContain("Aaron");
|
|
245
|
+
expect(output).toContain("Code review");
|
|
246
|
+
});
|
|
197
247
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
248
|
+
it("shows 'No worklogs' when empty", async () => {
|
|
249
|
+
server.use(
|
|
250
|
+
http.get(
|
|
251
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/worklogs/`,
|
|
252
|
+
() => HttpResponse.json({ results: [] }),
|
|
253
|
+
),
|
|
254
|
+
);
|
|
255
|
+
const { issueWorklogsList } = await import("@/commands/issue");
|
|
256
|
+
const logs: string[] = [];
|
|
257
|
+
const orig = console.log;
|
|
258
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
259
|
+
try {
|
|
260
|
+
await Effect.runPromise(
|
|
261
|
+
(issueWorklogsList as any).handler({ ref: "ACME-29" }),
|
|
262
|
+
);
|
|
263
|
+
} finally {
|
|
264
|
+
console.log = orig;
|
|
265
|
+
}
|
|
266
|
+
expect(logs.join("\n")).toBe("No worklogs");
|
|
267
|
+
});
|
|
268
|
+
});
|
|
216
269
|
|
|
217
270
|
describe("issueWorklogsAdd", () => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
271
|
+
it("logs time without description", async () => {
|
|
272
|
+
server.use(
|
|
273
|
+
http.post(
|
|
274
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/worklogs/`,
|
|
275
|
+
async ({ request }) => {
|
|
276
|
+
const body = (await request.json()) as any;
|
|
277
|
+
return HttpResponse.json({
|
|
278
|
+
id: "w-new",
|
|
279
|
+
duration: body.duration,
|
|
280
|
+
created_at: "2025-01-15T10:00:00Z",
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
),
|
|
284
|
+
);
|
|
285
|
+
const { issueWorklogsAdd } = await import("@/commands/issue");
|
|
286
|
+
const logs: string[] = [];
|
|
287
|
+
const orig = console.log;
|
|
288
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
289
|
+
try {
|
|
290
|
+
await Effect.runPromise(
|
|
291
|
+
(issueWorklogsAdd as any).handler({
|
|
292
|
+
ref: "ACME-29",
|
|
293
|
+
duration: 60,
|
|
294
|
+
description: { _tag: "None" },
|
|
295
|
+
}),
|
|
296
|
+
);
|
|
297
|
+
} finally {
|
|
298
|
+
console.log = orig;
|
|
299
|
+
}
|
|
300
|
+
expect(logs.join("\n")).toContain("1.0h");
|
|
301
|
+
expect(logs.join("\n")).toContain("w-new");
|
|
302
|
+
});
|
|
242
303
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
304
|
+
it("logs time with description", async () => {
|
|
305
|
+
server.use(
|
|
306
|
+
http.post(
|
|
307
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/worklogs/`,
|
|
308
|
+
async ({ request }) => {
|
|
309
|
+
const body = (await request.json()) as any;
|
|
310
|
+
return HttpResponse.json({
|
|
311
|
+
id: "w-new2",
|
|
312
|
+
duration: body.duration,
|
|
313
|
+
description: body.description,
|
|
314
|
+
created_at: "2025-01-15T10:00:00Z",
|
|
315
|
+
});
|
|
316
|
+
},
|
|
317
|
+
),
|
|
318
|
+
);
|
|
319
|
+
const { issueWorklogsAdd } = await import("@/commands/issue");
|
|
320
|
+
const logs: string[] = [];
|
|
321
|
+
const orig = console.log;
|
|
322
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
323
|
+
try {
|
|
324
|
+
await Effect.runPromise(
|
|
325
|
+
(issueWorklogsAdd as any).handler({
|
|
326
|
+
ref: "ACME-29",
|
|
327
|
+
duration: 30,
|
|
328
|
+
description: { _tag: "Some", value: "standup" },
|
|
329
|
+
}),
|
|
330
|
+
);
|
|
331
|
+
} finally {
|
|
332
|
+
console.log = orig;
|
|
333
|
+
}
|
|
334
|
+
expect(logs.join("\n")).toContain("0.5h");
|
|
335
|
+
});
|
|
270
336
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
337
|
+
it("handles missing logged_by_detail in worklogs list", async () => {
|
|
338
|
+
server.use(
|
|
339
|
+
http.get(
|
|
340
|
+
`${BASE}/api/v1/workspaces/${WS}/projects/proj-acme/issues/i1/worklogs/`,
|
|
341
|
+
() =>
|
|
342
|
+
HttpResponse.json({
|
|
343
|
+
results: [
|
|
344
|
+
{ id: "w2", duration: 45, created_at: "2025-01-15T10:00:00Z" },
|
|
345
|
+
],
|
|
346
|
+
}),
|
|
347
|
+
),
|
|
348
|
+
);
|
|
349
|
+
const { issueWorklogsList } = await import("@/commands/issue");
|
|
350
|
+
const logs: string[] = [];
|
|
351
|
+
const orig = console.log;
|
|
352
|
+
console.log = (...args: unknown[]) => logs.push(args.join(" "));
|
|
353
|
+
try {
|
|
354
|
+
await Effect.runPromise(
|
|
355
|
+
(issueWorklogsList as any).handler({ ref: "ACME-29" }),
|
|
356
|
+
);
|
|
357
|
+
} finally {
|
|
358
|
+
console.log = orig;
|
|
359
|
+
}
|
|
360
|
+
expect(logs.join("\n")).toContain("?");
|
|
361
|
+
expect(logs.join("\n")).toContain("0.8h");
|
|
362
|
+
});
|
|
363
|
+
});
|