@uipath/data-fabric-tool 1.1.0 → 1.195.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/dist/tool.js +1638 -1164
- package/package.json +16 -24
- package/src/commands/choice-sets.spec.ts +538 -83
- package/src/commands/choice-sets.ts +550 -146
- package/src/commands/entities.spec.ts +58 -145
- package/src/commands/entities.ts +160 -367
- package/src/commands/files.spec.ts +18 -32
- package/src/commands/files.ts +33 -89
- package/src/commands/records.spec.ts +102 -207
- package/src/commands/records.ts +112 -328
- package/src/tool.ts +5 -1
- package/src/utils/output.spec.ts +78 -0
- package/src/utils/output.ts +51 -0
- package/src/utils/sdk-client.spec.ts +59 -0
- package/src/utils/sdk-client.ts +23 -0
- package/src/utils/pagination.ts +0 -10
|
@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
3
3
|
|
|
4
4
|
vi.mock("../utils/sdk-client", () => ({
|
|
5
5
|
createDataFabricClient: vi.fn(),
|
|
6
|
+
connectOrFail: vi.fn(),
|
|
6
7
|
}));
|
|
7
8
|
|
|
8
9
|
vi.mock("@uipath/common", async (importOriginal) => {
|
|
@@ -17,8 +18,11 @@ vi.mock("@uipath/common", async (importOriginal) => {
|
|
|
17
18
|
});
|
|
18
19
|
|
|
19
20
|
import { OutputFormatter } from "@uipath/common";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
21
|
+
import { connectOrFail } from "../utils/sdk-client";
|
|
22
|
+
import {
|
|
23
|
+
registerChoiceSetsCommand,
|
|
24
|
+
registerChoiceSetValuesCommand,
|
|
25
|
+
} from "./choice-sets";
|
|
22
26
|
|
|
23
27
|
function buildProgram(): Command {
|
|
24
28
|
const program = new Command();
|
|
@@ -27,6 +31,13 @@ function buildProgram(): Command {
|
|
|
27
31
|
return program;
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
function buildValuesProgram(): Command {
|
|
35
|
+
const program = new Command();
|
|
36
|
+
program.name("test").exitOverride();
|
|
37
|
+
registerChoiceSetValuesCommand(program);
|
|
38
|
+
return program;
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
function mockSdk(overrides: Record<string, unknown> = {}) {
|
|
31
42
|
const sdk = {
|
|
32
43
|
entities: {
|
|
@@ -36,11 +47,27 @@ function mockSdk(overrides: Record<string, unknown> = {}) {
|
|
|
36
47
|
items: [],
|
|
37
48
|
totalCount: 0,
|
|
38
49
|
}),
|
|
50
|
+
create: vi.fn().mockResolvedValue("new-choice-set-id"),
|
|
51
|
+
updateById: vi.fn().mockResolvedValue(undefined),
|
|
52
|
+
deleteById: vi.fn().mockResolvedValue(undefined),
|
|
53
|
+
insertValueById: vi.fn().mockResolvedValue({
|
|
54
|
+
id: "v-new",
|
|
55
|
+
name: "travel",
|
|
56
|
+
displayName: "Travel",
|
|
57
|
+
numberId: 1,
|
|
58
|
+
}),
|
|
59
|
+
updateValueById: vi.fn().mockResolvedValue({
|
|
60
|
+
id: "v-1",
|
|
61
|
+
name: "travel",
|
|
62
|
+
displayName: "Business Travel",
|
|
63
|
+
numberId: 1,
|
|
64
|
+
}),
|
|
65
|
+
deleteValuesById: vi.fn().mockResolvedValue(undefined),
|
|
39
66
|
...overrides,
|
|
40
67
|
},
|
|
41
68
|
},
|
|
42
69
|
};
|
|
43
|
-
vi.mocked(
|
|
70
|
+
vi.mocked(connectOrFail).mockResolvedValue(sdk as never);
|
|
44
71
|
return sdk;
|
|
45
72
|
}
|
|
46
73
|
|
|
@@ -50,18 +77,21 @@ describe("choice-sets list", () => {
|
|
|
50
77
|
process.exitCode = undefined;
|
|
51
78
|
});
|
|
52
79
|
|
|
53
|
-
it("should register the choice-sets command with list and
|
|
80
|
+
it("should register the choice-sets command with list, list-values, create, update, and delete subcommands", () => {
|
|
54
81
|
const program = buildProgram();
|
|
55
82
|
const cmd = program.commands.find((c) => c.name() === "choice-sets");
|
|
56
83
|
expect(cmd).toBeDefined();
|
|
57
84
|
const subNames = cmd?.commands.map((c) => c.name()) ?? [];
|
|
58
85
|
expect(subNames).toContain("list");
|
|
59
|
-
expect(subNames).toContain("
|
|
86
|
+
expect(subNames).toContain("list-values");
|
|
87
|
+
expect(subNames).toContain("create");
|
|
88
|
+
expect(subNames).toContain("update");
|
|
89
|
+
expect(subNames).toContain("delete");
|
|
60
90
|
});
|
|
61
91
|
|
|
62
|
-
it("should list choice sets
|
|
92
|
+
it("should list choice sets and return the verbatim SDK response", async () => {
|
|
63
93
|
const sdk = mockSdk();
|
|
64
|
-
|
|
94
|
+
const rawList = [
|
|
65
95
|
{
|
|
66
96
|
id: "cs-uuid-1",
|
|
67
97
|
name: "ExpenseTypes",
|
|
@@ -72,8 +102,11 @@ describe("choice-sets list", () => {
|
|
|
72
102
|
updatedBy: "u-2",
|
|
73
103
|
createdTime: "2026-01-01T00:00:00Z",
|
|
74
104
|
updatedTime: "2026-01-02T00:00:00Z",
|
|
75
|
-
}
|
|
76
|
-
]
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
vi.mocked(sdk.entities.choicesets.getAll).mockResolvedValue(
|
|
108
|
+
rawList as never,
|
|
109
|
+
);
|
|
77
110
|
|
|
78
111
|
const program = buildProgram();
|
|
79
112
|
await program.parseAsync(["node", "test", "choice-sets", "list"]);
|
|
@@ -82,13 +115,7 @@ describe("choice-sets list", () => {
|
|
|
82
115
|
expect.objectContaining({
|
|
83
116
|
Result: "Success",
|
|
84
117
|
Code: "ChoiceSetList",
|
|
85
|
-
Data:
|
|
86
|
-
expect.objectContaining({
|
|
87
|
-
ID: "cs-uuid-1",
|
|
88
|
-
Name: "ExpenseTypes",
|
|
89
|
-
DisplayName: "Expense Types",
|
|
90
|
-
}),
|
|
91
|
-
]),
|
|
118
|
+
Data: rawList,
|
|
92
119
|
}),
|
|
93
120
|
);
|
|
94
121
|
});
|
|
@@ -122,31 +149,25 @@ describe("choice-sets list", () => {
|
|
|
122
149
|
expect(process.exitCode).toBe(1);
|
|
123
150
|
});
|
|
124
151
|
|
|
125
|
-
it("should
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
);
|
|
152
|
+
it("should not proceed with list when the client connection fails", async () => {
|
|
153
|
+
const sdk = mockSdk();
|
|
154
|
+
vi.mocked(connectOrFail).mockResolvedValue(undefined);
|
|
129
155
|
const program = buildProgram();
|
|
130
156
|
await program.parseAsync(["node", "test", "choice-sets", "list"]);
|
|
131
|
-
expect(
|
|
132
|
-
|
|
133
|
-
Result: "Failure",
|
|
134
|
-
Message: "Error connecting to Data Fabric",
|
|
135
|
-
}),
|
|
136
|
-
);
|
|
137
|
-
expect(process.exitCode).toBe(1);
|
|
157
|
+
expect(sdk.entities.choicesets.getAll).not.toHaveBeenCalled();
|
|
158
|
+
expect(OutputFormatter.success).not.toHaveBeenCalled();
|
|
138
159
|
});
|
|
139
160
|
});
|
|
140
161
|
|
|
141
|
-
describe("choice-sets
|
|
162
|
+
describe("choice-sets list-values", () => {
|
|
142
163
|
beforeEach(() => {
|
|
143
164
|
vi.resetAllMocks();
|
|
144
165
|
process.exitCode = undefined;
|
|
145
166
|
});
|
|
146
167
|
|
|
147
|
-
it("should get values for a choice set", async () => {
|
|
168
|
+
it("should get values for a choice set and return the verbatim SDK response", async () => {
|
|
148
169
|
const sdk = mockSdk();
|
|
149
|
-
|
|
170
|
+
const rawResponse = {
|
|
150
171
|
items: [
|
|
151
172
|
{
|
|
152
173
|
id: "v-1",
|
|
@@ -159,14 +180,17 @@ describe("choice-sets get", () => {
|
|
|
159
180
|
],
|
|
160
181
|
totalCount: 1,
|
|
161
182
|
hasNextPage: false,
|
|
162
|
-
}
|
|
183
|
+
};
|
|
184
|
+
vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue(
|
|
185
|
+
rawResponse as never,
|
|
186
|
+
);
|
|
163
187
|
|
|
164
188
|
const program = buildProgram();
|
|
165
189
|
await program.parseAsync([
|
|
166
190
|
"node",
|
|
167
191
|
"test",
|
|
168
192
|
"choice-sets",
|
|
169
|
-
"
|
|
193
|
+
"list-values",
|
|
170
194
|
"cs-1",
|
|
171
195
|
]);
|
|
172
196
|
|
|
@@ -177,43 +201,28 @@ describe("choice-sets get", () => {
|
|
|
177
201
|
expect.objectContaining({
|
|
178
202
|
Result: "Success",
|
|
179
203
|
Code: "ChoiceSetValues",
|
|
180
|
-
Data:
|
|
181
|
-
TotalCount: 1,
|
|
182
|
-
Values: expect.arrayContaining([
|
|
183
|
-
expect.objectContaining({
|
|
184
|
-
Id: "v-1",
|
|
185
|
-
Name: "travel",
|
|
186
|
-
DisplayName: "Travel",
|
|
187
|
-
NumberId: 1,
|
|
188
|
-
}),
|
|
189
|
-
]),
|
|
190
|
-
HasNextPage: false,
|
|
191
|
-
}),
|
|
204
|
+
Data: rawResponse,
|
|
192
205
|
}),
|
|
193
206
|
);
|
|
194
207
|
});
|
|
195
208
|
|
|
196
|
-
it("should pass cursor to choicesets.getById and
|
|
209
|
+
it("should pass cursor to choicesets.getById and return the raw response", async () => {
|
|
197
210
|
const sdk = mockSdk();
|
|
198
|
-
|
|
199
|
-
items: [
|
|
200
|
-
{
|
|
201
|
-
id: "v-1",
|
|
202
|
-
name: "n",
|
|
203
|
-
displayName: "N",
|
|
204
|
-
numberId: 1,
|
|
205
|
-
},
|
|
206
|
-
],
|
|
211
|
+
const rawResponse = {
|
|
212
|
+
items: [{ id: "v-1", name: "n", displayName: "N", numberId: 1 }],
|
|
207
213
|
totalCount: 100,
|
|
208
214
|
hasNextPage: true,
|
|
209
215
|
nextCursor: "next-cur",
|
|
210
|
-
}
|
|
216
|
+
};
|
|
217
|
+
vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue(
|
|
218
|
+
rawResponse as never,
|
|
219
|
+
);
|
|
211
220
|
const program = buildProgram();
|
|
212
221
|
await program.parseAsync([
|
|
213
222
|
"node",
|
|
214
223
|
"test",
|
|
215
224
|
"choice-sets",
|
|
216
|
-
"
|
|
225
|
+
"list-values",
|
|
217
226
|
"cs-1",
|
|
218
227
|
"--cursor",
|
|
219
228
|
"prev",
|
|
@@ -227,8 +236,8 @@ describe("choice-sets get", () => {
|
|
|
227
236
|
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
228
237
|
expect.objectContaining({
|
|
229
238
|
Data: expect.objectContaining({
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
hasNextPage: true,
|
|
240
|
+
nextCursor: "next-cur",
|
|
232
241
|
}),
|
|
233
242
|
}),
|
|
234
243
|
);
|
|
@@ -246,7 +255,7 @@ describe("choice-sets get", () => {
|
|
|
246
255
|
"node",
|
|
247
256
|
"test",
|
|
248
257
|
"choice-sets",
|
|
249
|
-
"
|
|
258
|
+
"list-values",
|
|
250
259
|
"cs-1",
|
|
251
260
|
"--offset",
|
|
252
261
|
"20",
|
|
@@ -266,7 +275,7 @@ describe("choice-sets get", () => {
|
|
|
266
275
|
"node",
|
|
267
276
|
"test",
|
|
268
277
|
"choice-sets",
|
|
269
|
-
"
|
|
278
|
+
"list-values",
|
|
270
279
|
"cs-1",
|
|
271
280
|
"--offset",
|
|
272
281
|
"10",
|
|
@@ -289,7 +298,7 @@ describe("choice-sets get", () => {
|
|
|
289
298
|
"node",
|
|
290
299
|
"test",
|
|
291
300
|
"choice-sets",
|
|
292
|
-
"
|
|
301
|
+
"list-values",
|
|
293
302
|
"cs-1",
|
|
294
303
|
"--limit",
|
|
295
304
|
"0",
|
|
@@ -310,7 +319,7 @@ describe("choice-sets get", () => {
|
|
|
310
319
|
"node",
|
|
311
320
|
"test",
|
|
312
321
|
"choice-sets",
|
|
313
|
-
"
|
|
322
|
+
"list-values",
|
|
314
323
|
"cs-1",
|
|
315
324
|
"--offset",
|
|
316
325
|
"-1",
|
|
@@ -334,7 +343,7 @@ describe("choice-sets get", () => {
|
|
|
334
343
|
"node",
|
|
335
344
|
"test",
|
|
336
345
|
"choice-sets",
|
|
337
|
-
"
|
|
346
|
+
"list-values",
|
|
338
347
|
"missing",
|
|
339
348
|
]);
|
|
340
349
|
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
@@ -346,49 +355,495 @@ describe("choice-sets get", () => {
|
|
|
346
355
|
expect(process.exitCode).toBe(1);
|
|
347
356
|
});
|
|
348
357
|
|
|
349
|
-
it("should
|
|
350
|
-
|
|
351
|
-
|
|
358
|
+
it("should not proceed with get when the client connection fails", async () => {
|
|
359
|
+
const sdk = mockSdk();
|
|
360
|
+
vi.mocked(connectOrFail).mockResolvedValue(undefined);
|
|
361
|
+
const program = buildProgram();
|
|
362
|
+
await program.parseAsync([
|
|
363
|
+
"node",
|
|
364
|
+
"test",
|
|
365
|
+
"choice-sets",
|
|
366
|
+
"list-values",
|
|
367
|
+
"cs-1",
|
|
368
|
+
]);
|
|
369
|
+
expect(sdk.entities.choicesets.getById).not.toHaveBeenCalled();
|
|
370
|
+
expect(OutputFormatter.success).not.toHaveBeenCalled();
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
describe("choice-sets create", () => {
|
|
375
|
+
beforeEach(() => {
|
|
376
|
+
vi.resetAllMocks();
|
|
377
|
+
process.exitCode = undefined;
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("should create a choice set with options and return the ID", async () => {
|
|
381
|
+
const sdk = mockSdk();
|
|
382
|
+
const program = buildProgram();
|
|
383
|
+
await program.parseAsync([
|
|
384
|
+
"node",
|
|
385
|
+
"test",
|
|
386
|
+
"choice-sets",
|
|
387
|
+
"create",
|
|
388
|
+
"ExpenseTypes",
|
|
389
|
+
"--display-name",
|
|
390
|
+
"Expense Types",
|
|
391
|
+
"--description",
|
|
392
|
+
"Categories",
|
|
393
|
+
"--folder-key",
|
|
394
|
+
"folder-1",
|
|
395
|
+
]);
|
|
396
|
+
|
|
397
|
+
expect(sdk.entities.choicesets.create).toHaveBeenCalledWith(
|
|
398
|
+
"ExpenseTypes",
|
|
399
|
+
{
|
|
400
|
+
displayName: "Expense Types",
|
|
401
|
+
description: "Categories",
|
|
402
|
+
folderKey: "folder-1",
|
|
403
|
+
},
|
|
404
|
+
);
|
|
405
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
406
|
+
expect.objectContaining({
|
|
407
|
+
Result: "Success",
|
|
408
|
+
Code: "ChoiceSetCreated",
|
|
409
|
+
Data: { ID: "new-choice-set-id" },
|
|
410
|
+
}),
|
|
411
|
+
);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it("should create a choice set with no options (undefined opts)", async () => {
|
|
415
|
+
const sdk = mockSdk();
|
|
416
|
+
const program = buildProgram();
|
|
417
|
+
await program.parseAsync([
|
|
418
|
+
"node",
|
|
419
|
+
"test",
|
|
420
|
+
"choice-sets",
|
|
421
|
+
"create",
|
|
422
|
+
"ExpenseTypes",
|
|
423
|
+
]);
|
|
424
|
+
expect(sdk.entities.choicesets.create).toHaveBeenCalledWith(
|
|
425
|
+
"ExpenseTypes",
|
|
426
|
+
undefined,
|
|
427
|
+
);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should output error when create fails", async () => {
|
|
431
|
+
const sdk = mockSdk();
|
|
432
|
+
vi.mocked(sdk.entities.choicesets.create).mockRejectedValue(
|
|
433
|
+
new Error("conflict"),
|
|
434
|
+
);
|
|
435
|
+
const program = buildProgram();
|
|
436
|
+
await program.parseAsync([
|
|
437
|
+
"node",
|
|
438
|
+
"test",
|
|
439
|
+
"choice-sets",
|
|
440
|
+
"create",
|
|
441
|
+
"X",
|
|
442
|
+
]);
|
|
443
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
444
|
+
expect.objectContaining({
|
|
445
|
+
Result: "Failure",
|
|
446
|
+
Message: "Error creating choice set",
|
|
447
|
+
}),
|
|
448
|
+
);
|
|
449
|
+
expect(process.exitCode).toBe(1);
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
describe("choice-sets update", () => {
|
|
454
|
+
beforeEach(() => {
|
|
455
|
+
vi.resetAllMocks();
|
|
456
|
+
process.exitCode = undefined;
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it("should update a choice set's metadata", async () => {
|
|
460
|
+
const sdk = mockSdk();
|
|
461
|
+
const program = buildProgram();
|
|
462
|
+
await program.parseAsync([
|
|
463
|
+
"node",
|
|
464
|
+
"test",
|
|
465
|
+
"choice-sets",
|
|
466
|
+
"update",
|
|
467
|
+
"cs-1",
|
|
468
|
+
"--display-name",
|
|
469
|
+
"New Name",
|
|
470
|
+
]);
|
|
471
|
+
expect(sdk.entities.choicesets.updateById).toHaveBeenCalledWith(
|
|
472
|
+
"cs-1",
|
|
473
|
+
{
|
|
474
|
+
displayName: "New Name",
|
|
475
|
+
},
|
|
352
476
|
);
|
|
477
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
478
|
+
expect.objectContaining({
|
|
479
|
+
Result: "Success",
|
|
480
|
+
Code: "ChoiceSetUpdated",
|
|
481
|
+
Data: { ID: "cs-1" },
|
|
482
|
+
}),
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it("should error when no update fields are provided", async () => {
|
|
487
|
+
const sdk = mockSdk();
|
|
353
488
|
const program = buildProgram();
|
|
354
489
|
await program.parseAsync([
|
|
355
490
|
"node",
|
|
356
491
|
"test",
|
|
357
492
|
"choice-sets",
|
|
358
|
-
"
|
|
493
|
+
"update",
|
|
359
494
|
"cs-1",
|
|
360
495
|
]);
|
|
496
|
+
expect(sdk.entities.choicesets.updateById).not.toHaveBeenCalled();
|
|
361
497
|
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
362
498
|
expect.objectContaining({
|
|
363
499
|
Result: "Failure",
|
|
364
|
-
Message: "
|
|
500
|
+
Message: "No update fields provided",
|
|
365
501
|
}),
|
|
366
502
|
);
|
|
367
503
|
expect(process.exitCode).toBe(1);
|
|
368
504
|
});
|
|
369
505
|
|
|
370
|
-
it("should
|
|
506
|
+
it("should output error when update fails", async () => {
|
|
371
507
|
const sdk = mockSdk();
|
|
372
|
-
vi.mocked(sdk.entities.choicesets.
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
hasNextPage: true,
|
|
376
|
-
nextCursor: { value: "cursor-as-object" } as unknown as string,
|
|
377
|
-
});
|
|
508
|
+
vi.mocked(sdk.entities.choicesets.updateById).mockRejectedValue(
|
|
509
|
+
new Error("404"),
|
|
510
|
+
);
|
|
378
511
|
const program = buildProgram();
|
|
379
512
|
await program.parseAsync([
|
|
380
513
|
"node",
|
|
381
514
|
"test",
|
|
382
515
|
"choice-sets",
|
|
383
|
-
"
|
|
516
|
+
"update",
|
|
517
|
+
"missing",
|
|
518
|
+
"--description",
|
|
519
|
+
"x",
|
|
520
|
+
]);
|
|
521
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
522
|
+
expect.objectContaining({
|
|
523
|
+
Result: "Failure",
|
|
524
|
+
Message: "Error updating choice set 'missing'",
|
|
525
|
+
}),
|
|
526
|
+
);
|
|
527
|
+
expect(process.exitCode).toBe(1);
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
describe("choice-sets delete", () => {
|
|
532
|
+
beforeEach(() => {
|
|
533
|
+
vi.resetAllMocks();
|
|
534
|
+
process.exitCode = undefined;
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it("should delete a choice set with --confirm and --reason", async () => {
|
|
538
|
+
const sdk = mockSdk();
|
|
539
|
+
const program = buildProgram();
|
|
540
|
+
await program.parseAsync([
|
|
541
|
+
"node",
|
|
542
|
+
"test",
|
|
543
|
+
"choice-sets",
|
|
544
|
+
"delete",
|
|
384
545
|
"cs-1",
|
|
385
|
-
"--
|
|
386
|
-
"
|
|
546
|
+
"--confirm",
|
|
547
|
+
"--reason",
|
|
548
|
+
"cleanup",
|
|
387
549
|
]);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
550
|
+
expect(sdk.entities.choicesets.deleteById).toHaveBeenCalledWith("cs-1");
|
|
551
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
552
|
+
expect.objectContaining({
|
|
553
|
+
Result: "Success",
|
|
554
|
+
Code: "ChoiceSetDeleted",
|
|
555
|
+
Data: { ID: "cs-1", Reason: "cleanup" },
|
|
556
|
+
}),
|
|
557
|
+
);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it("should require --confirm", async () => {
|
|
561
|
+
const sdk = mockSdk();
|
|
562
|
+
const program = buildProgram();
|
|
563
|
+
await program.parseAsync([
|
|
564
|
+
"node",
|
|
565
|
+
"test",
|
|
566
|
+
"choice-sets",
|
|
567
|
+
"delete",
|
|
568
|
+
"cs-1",
|
|
569
|
+
"--reason",
|
|
570
|
+
"cleanup",
|
|
571
|
+
]);
|
|
572
|
+
expect(sdk.entities.choicesets.deleteById).not.toHaveBeenCalled();
|
|
573
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
574
|
+
expect.objectContaining({
|
|
575
|
+
Result: "Failure",
|
|
576
|
+
Message: "Confirmation required for destructive operation",
|
|
577
|
+
}),
|
|
578
|
+
);
|
|
579
|
+
expect(process.exitCode).toBe(1);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
it("should require --reason", async () => {
|
|
583
|
+
const sdk = mockSdk();
|
|
584
|
+
const program = buildProgram();
|
|
585
|
+
await program.parseAsync([
|
|
586
|
+
"node",
|
|
587
|
+
"test",
|
|
588
|
+
"choice-sets",
|
|
589
|
+
"delete",
|
|
590
|
+
"cs-1",
|
|
591
|
+
"--confirm",
|
|
592
|
+
]);
|
|
593
|
+
expect(sdk.entities.choicesets.deleteById).not.toHaveBeenCalled();
|
|
594
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
595
|
+
expect.objectContaining({
|
|
596
|
+
Result: "Failure",
|
|
597
|
+
Message: "Reason required for destructive operation",
|
|
598
|
+
}),
|
|
599
|
+
);
|
|
600
|
+
expect(process.exitCode).toBe(1);
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
describe("choice-set-values", () => {
|
|
605
|
+
beforeEach(() => {
|
|
606
|
+
vi.resetAllMocks();
|
|
607
|
+
process.exitCode = undefined;
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it("should register the choice-set-values command with create, update, and delete subcommands", () => {
|
|
611
|
+
const program = buildValuesProgram();
|
|
612
|
+
const cmd = program.commands.find(
|
|
613
|
+
(c) => c.name() === "choice-set-values",
|
|
614
|
+
);
|
|
615
|
+
expect(cmd).toBeDefined();
|
|
616
|
+
const subNames = cmd?.commands.map((c) => c.name()) ?? [];
|
|
617
|
+
expect(subNames).toContain("create");
|
|
618
|
+
expect(subNames).toContain("update");
|
|
619
|
+
expect(subNames).toContain("delete");
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it("should create a value and project the response", async () => {
|
|
623
|
+
const sdk = mockSdk();
|
|
624
|
+
const program = buildValuesProgram();
|
|
625
|
+
await program.parseAsync([
|
|
626
|
+
"node",
|
|
627
|
+
"test",
|
|
628
|
+
"choice-set-values",
|
|
629
|
+
"create",
|
|
630
|
+
"cs-1",
|
|
631
|
+
"travel",
|
|
632
|
+
"--display-name",
|
|
633
|
+
"Travel",
|
|
634
|
+
]);
|
|
635
|
+
expect(sdk.entities.choicesets.insertValueById).toHaveBeenCalledWith(
|
|
636
|
+
"cs-1",
|
|
637
|
+
"travel",
|
|
638
|
+
{ displayName: "Travel" },
|
|
639
|
+
);
|
|
640
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
641
|
+
expect.objectContaining({
|
|
642
|
+
Result: "Success",
|
|
643
|
+
Code: "ChoiceSetValueCreated",
|
|
644
|
+
Data: expect.objectContaining({
|
|
645
|
+
id: "v-new",
|
|
646
|
+
name: "travel",
|
|
647
|
+
displayName: "Travel",
|
|
648
|
+
numberId: 1,
|
|
649
|
+
}),
|
|
650
|
+
}),
|
|
651
|
+
);
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it("should create a value with no display name (undefined opts)", async () => {
|
|
655
|
+
const sdk = mockSdk();
|
|
656
|
+
const program = buildValuesProgram();
|
|
657
|
+
await program.parseAsync([
|
|
658
|
+
"node",
|
|
659
|
+
"test",
|
|
660
|
+
"choice-set-values",
|
|
661
|
+
"create",
|
|
662
|
+
"cs-1",
|
|
663
|
+
"travel",
|
|
664
|
+
]);
|
|
665
|
+
expect(sdk.entities.choicesets.insertValueById).toHaveBeenCalledWith(
|
|
666
|
+
"cs-1",
|
|
667
|
+
"travel",
|
|
668
|
+
undefined,
|
|
669
|
+
);
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
it("should output error when value create fails", async () => {
|
|
673
|
+
const sdk = mockSdk();
|
|
674
|
+
vi.mocked(sdk.entities.choicesets.insertValueById).mockRejectedValue(
|
|
675
|
+
new Error("conflict"),
|
|
676
|
+
);
|
|
677
|
+
const program = buildValuesProgram();
|
|
678
|
+
await program.parseAsync([
|
|
679
|
+
"node",
|
|
680
|
+
"test",
|
|
681
|
+
"choice-set-values",
|
|
682
|
+
"create",
|
|
683
|
+
"cs-1",
|
|
684
|
+
"travel",
|
|
685
|
+
]);
|
|
686
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
687
|
+
expect.objectContaining({
|
|
688
|
+
Result: "Failure",
|
|
689
|
+
Message: "Error creating value in choice set 'cs-1'",
|
|
690
|
+
}),
|
|
691
|
+
);
|
|
692
|
+
expect(process.exitCode).toBe(1);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it("should update a value's display name", async () => {
|
|
696
|
+
const sdk = mockSdk();
|
|
697
|
+
const program = buildValuesProgram();
|
|
698
|
+
await program.parseAsync([
|
|
699
|
+
"node",
|
|
700
|
+
"test",
|
|
701
|
+
"choice-set-values",
|
|
702
|
+
"update",
|
|
703
|
+
"cs-1",
|
|
704
|
+
"v-1",
|
|
705
|
+
"Business Travel",
|
|
706
|
+
]);
|
|
707
|
+
expect(sdk.entities.choicesets.updateValueById).toHaveBeenCalledWith(
|
|
708
|
+
"cs-1",
|
|
709
|
+
"v-1",
|
|
710
|
+
"Business Travel",
|
|
711
|
+
);
|
|
712
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
713
|
+
expect.objectContaining({
|
|
714
|
+
Result: "Success",
|
|
715
|
+
Code: "ChoiceSetValueUpdated",
|
|
716
|
+
Data: expect.objectContaining({
|
|
717
|
+
id: "v-1",
|
|
718
|
+
displayName: "Business Travel",
|
|
719
|
+
}),
|
|
720
|
+
}),
|
|
721
|
+
);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it("should output error when value update fails", async () => {
|
|
725
|
+
const sdk = mockSdk();
|
|
726
|
+
vi.mocked(sdk.entities.choicesets.updateValueById).mockRejectedValue(
|
|
727
|
+
new Error("404"),
|
|
728
|
+
);
|
|
729
|
+
const program = buildValuesProgram();
|
|
730
|
+
await program.parseAsync([
|
|
731
|
+
"node",
|
|
732
|
+
"test",
|
|
733
|
+
"choice-set-values",
|
|
734
|
+
"update",
|
|
735
|
+
"cs-1",
|
|
736
|
+
"missing",
|
|
737
|
+
"X",
|
|
738
|
+
]);
|
|
739
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
740
|
+
expect.objectContaining({
|
|
741
|
+
Result: "Failure",
|
|
742
|
+
Message: "Error updating value 'missing' in choice set 'cs-1'",
|
|
743
|
+
}),
|
|
744
|
+
);
|
|
745
|
+
expect(process.exitCode).toBe(1);
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
it("should delete values from a comma-separated --ids list", async () => {
|
|
749
|
+
const sdk = mockSdk();
|
|
750
|
+
const program = buildValuesProgram();
|
|
751
|
+
await program.parseAsync([
|
|
752
|
+
"node",
|
|
753
|
+
"test",
|
|
754
|
+
"choice-set-values",
|
|
755
|
+
"delete",
|
|
756
|
+
"cs-1",
|
|
757
|
+
"--ids",
|
|
758
|
+
"v-1, v-2 ,v-3",
|
|
759
|
+
"--confirm",
|
|
760
|
+
"--reason",
|
|
761
|
+
"cleanup",
|
|
762
|
+
]);
|
|
763
|
+
expect(sdk.entities.choicesets.deleteValuesById).toHaveBeenCalledWith(
|
|
764
|
+
"cs-1",
|
|
765
|
+
["v-1", "v-2", "v-3"],
|
|
766
|
+
);
|
|
767
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
768
|
+
expect.objectContaining({
|
|
769
|
+
Result: "Success",
|
|
770
|
+
Code: "ChoiceSetValuesDeleted",
|
|
771
|
+
Data: {
|
|
772
|
+
ChoiceSetId: "cs-1",
|
|
773
|
+
DeletedIds: ["v-1", "v-2", "v-3"],
|
|
774
|
+
Reason: "cleanup",
|
|
775
|
+
},
|
|
776
|
+
}),
|
|
777
|
+
);
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
it("should error when --ids is missing or empty", async () => {
|
|
781
|
+
const sdk = mockSdk();
|
|
782
|
+
const program = buildValuesProgram();
|
|
783
|
+
await program.parseAsync([
|
|
784
|
+
"node",
|
|
785
|
+
"test",
|
|
786
|
+
"choice-set-values",
|
|
787
|
+
"delete",
|
|
788
|
+
"cs-1",
|
|
789
|
+
"--confirm",
|
|
790
|
+
"--reason",
|
|
791
|
+
"cleanup",
|
|
792
|
+
]);
|
|
793
|
+
expect(sdk.entities.choicesets.deleteValuesById).not.toHaveBeenCalled();
|
|
794
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
795
|
+
expect.objectContaining({
|
|
796
|
+
Result: "Failure",
|
|
797
|
+
Message: "No value IDs provided",
|
|
798
|
+
}),
|
|
799
|
+
);
|
|
800
|
+
expect(process.exitCode).toBe(1);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
it("should require --confirm for value delete", async () => {
|
|
804
|
+
const sdk = mockSdk();
|
|
805
|
+
const program = buildValuesProgram();
|
|
806
|
+
await program.parseAsync([
|
|
807
|
+
"node",
|
|
808
|
+
"test",
|
|
809
|
+
"choice-set-values",
|
|
810
|
+
"delete",
|
|
811
|
+
"cs-1",
|
|
812
|
+
"--ids",
|
|
813
|
+
"v-1",
|
|
814
|
+
"--reason",
|
|
815
|
+
"cleanup",
|
|
816
|
+
]);
|
|
817
|
+
expect(sdk.entities.choicesets.deleteValuesById).not.toHaveBeenCalled();
|
|
818
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
819
|
+
expect.objectContaining({
|
|
820
|
+
Result: "Failure",
|
|
821
|
+
Message: "Confirmation required for destructive operation",
|
|
822
|
+
}),
|
|
823
|
+
);
|
|
824
|
+
expect(process.exitCode).toBe(1);
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
it("should require --reason for value delete", async () => {
|
|
828
|
+
const sdk = mockSdk();
|
|
829
|
+
const program = buildValuesProgram();
|
|
830
|
+
await program.parseAsync([
|
|
831
|
+
"node",
|
|
832
|
+
"test",
|
|
833
|
+
"choice-set-values",
|
|
834
|
+
"delete",
|
|
835
|
+
"cs-1",
|
|
836
|
+
"--ids",
|
|
837
|
+
"v-1",
|
|
838
|
+
"--confirm",
|
|
839
|
+
]);
|
|
840
|
+
expect(sdk.entities.choicesets.deleteValuesById).not.toHaveBeenCalled();
|
|
841
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
842
|
+
expect.objectContaining({
|
|
843
|
+
Result: "Failure",
|
|
844
|
+
Message: "Reason required for destructive operation",
|
|
845
|
+
}),
|
|
846
|
+
);
|
|
847
|
+
expect(process.exitCode).toBe(1);
|
|
393
848
|
});
|
|
394
849
|
});
|