@uipath/data-fabric-tool 1.0.4 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/data-fabric-tool",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "Manage Data Fabric entities and records.",
5
5
  "type": "module",
6
6
  "main": "./dist/tool.js",
@@ -10,19 +10,11 @@
10
10
  "bin": {
11
11
  "data-fabric-tool": "./dist/index.js"
12
12
  },
13
- "scripts": {
14
- "build": "bun ../../tools/build-tool.ts",
15
- "package": "bun run build && bun pm pack",
16
- "test": "vitest run",
17
- "test:coverage": "vitest run --coverage",
18
- "lint": "biome check .",
19
- "lint:fix": "biome check --write ."
20
- },
21
13
  "devDependencies": {
22
14
  "commander": "^14.0.3",
23
- "@uipath/common": "1.0.4",
24
- "@uipath/auth": "1.0.4",
25
- "@uipath/filesystem": "1.0.4",
15
+ "@uipath/common": "1.1.0",
16
+ "@uipath/auth": "1.1.0",
17
+ "@uipath/filesystem": "1.1.0",
26
18
  "@uipath/uipath-typescript": "^1.3.7",
27
19
  "@types/node": "^25.5.2",
28
20
  "typescript": "^6.0.2"
@@ -30,5 +22,5 @@
30
22
  "publishConfig": {
31
23
  "registry": "https://registry.npmjs.org/"
32
24
  },
33
- "gitHead": "e496ee5b65951c8047259ab50d7d6a284eea58a9"
25
+ "gitHead": "06e8c8f566df4b87da4a008635483c62f64f33f0"
34
26
  }
@@ -0,0 +1,394 @@
1
+ import { Command } from "commander";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ vi.mock("../utils/sdk-client", () => ({
5
+ createDataFabricClient: vi.fn(),
6
+ }));
7
+
8
+ vi.mock("@uipath/common", async (importOriginal) => {
9
+ const actual = await importOriginal<typeof import("@uipath/common")>();
10
+ return {
11
+ ...actual,
12
+ OutputFormatter: {
13
+ success: vi.fn(),
14
+ error: vi.fn(),
15
+ },
16
+ };
17
+ });
18
+
19
+ import { OutputFormatter } from "@uipath/common";
20
+ import { createDataFabricClient } from "../utils/sdk-client";
21
+ import { registerChoiceSetsCommand } from "./choice-sets";
22
+
23
+ function buildProgram(): Command {
24
+ const program = new Command();
25
+ program.name("test").exitOverride();
26
+ registerChoiceSetsCommand(program);
27
+ return program;
28
+ }
29
+
30
+ function mockSdk(overrides: Record<string, unknown> = {}) {
31
+ const sdk = {
32
+ entities: {
33
+ choicesets: {
34
+ getAll: vi.fn().mockResolvedValue([]),
35
+ getById: vi.fn().mockResolvedValue({
36
+ items: [],
37
+ totalCount: 0,
38
+ }),
39
+ ...overrides,
40
+ },
41
+ },
42
+ };
43
+ vi.mocked(createDataFabricClient).mockResolvedValue(sdk as never);
44
+ return sdk;
45
+ }
46
+
47
+ describe("choice-sets list", () => {
48
+ beforeEach(() => {
49
+ vi.resetAllMocks();
50
+ process.exitCode = undefined;
51
+ });
52
+
53
+ it("should register the choice-sets command with list and get subcommands", () => {
54
+ const program = buildProgram();
55
+ const cmd = program.commands.find((c) => c.name() === "choice-sets");
56
+ expect(cmd).toBeDefined();
57
+ const subNames = cmd?.commands.map((c) => c.name()) ?? [];
58
+ expect(subNames).toContain("list");
59
+ expect(subNames).toContain("get");
60
+ });
61
+
62
+ it("should list choice sets successfully and expose the runtime ID", async () => {
63
+ const sdk = mockSdk();
64
+ vi.mocked(sdk.entities.choicesets.getAll).mockResolvedValue([
65
+ {
66
+ id: "cs-uuid-1",
67
+ name: "ExpenseTypes",
68
+ displayName: "Expense Types",
69
+ description: "Categories of expenses",
70
+ folderId: "f-1",
71
+ createdBy: "u-1",
72
+ updatedBy: "u-2",
73
+ createdTime: "2026-01-01T00:00:00Z",
74
+ updatedTime: "2026-01-02T00:00:00Z",
75
+ } as never,
76
+ ]);
77
+
78
+ const program = buildProgram();
79
+ await program.parseAsync(["node", "test", "choice-sets", "list"]);
80
+
81
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
82
+ expect.objectContaining({
83
+ Result: "Success",
84
+ Code: "ChoiceSetList",
85
+ Data: expect.arrayContaining([
86
+ expect.objectContaining({
87
+ ID: "cs-uuid-1",
88
+ Name: "ExpenseTypes",
89
+ DisplayName: "Expense Types",
90
+ }),
91
+ ]),
92
+ }),
93
+ );
94
+ });
95
+
96
+ it("should return empty list when no choice sets exist", async () => {
97
+ mockSdk();
98
+ const program = buildProgram();
99
+ await program.parseAsync(["node", "test", "choice-sets", "list"]);
100
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
101
+ expect.objectContaining({
102
+ Result: "Success",
103
+ Code: "ChoiceSetList",
104
+ Data: [],
105
+ }),
106
+ );
107
+ });
108
+
109
+ it("should output error when list fails", async () => {
110
+ const sdk = mockSdk();
111
+ vi.mocked(sdk.entities.choicesets.getAll).mockRejectedValue(
112
+ new Error("forbidden"),
113
+ );
114
+ const program = buildProgram();
115
+ await program.parseAsync(["node", "test", "choice-sets", "list"]);
116
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
117
+ expect.objectContaining({
118
+ Result: "Failure",
119
+ Message: "Error listing choice sets",
120
+ }),
121
+ );
122
+ expect(process.exitCode).toBe(1);
123
+ });
124
+
125
+ it("should error when SDK connection fails on list", async () => {
126
+ vi.mocked(createDataFabricClient).mockRejectedValue(
127
+ new Error("Not logged in"),
128
+ );
129
+ const program = buildProgram();
130
+ await program.parseAsync(["node", "test", "choice-sets", "list"]);
131
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
132
+ expect.objectContaining({
133
+ Result: "Failure",
134
+ Message: "Error connecting to Data Fabric",
135
+ }),
136
+ );
137
+ expect(process.exitCode).toBe(1);
138
+ });
139
+ });
140
+
141
+ describe("choice-sets get", () => {
142
+ beforeEach(() => {
143
+ vi.resetAllMocks();
144
+ process.exitCode = undefined;
145
+ });
146
+
147
+ it("should get values for a choice set", async () => {
148
+ const sdk = mockSdk();
149
+ vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue({
150
+ items: [
151
+ {
152
+ id: "v-1",
153
+ name: "travel",
154
+ displayName: "Travel",
155
+ numberId: 1,
156
+ createdTime: "2026-01-01T00:00:00Z",
157
+ updatedTime: "2026-01-02T00:00:00Z",
158
+ },
159
+ ],
160
+ totalCount: 1,
161
+ hasNextPage: false,
162
+ });
163
+
164
+ const program = buildProgram();
165
+ await program.parseAsync([
166
+ "node",
167
+ "test",
168
+ "choice-sets",
169
+ "get",
170
+ "cs-1",
171
+ ]);
172
+
173
+ expect(sdk.entities.choicesets.getById).toHaveBeenCalledWith("cs-1", {
174
+ pageSize: 50,
175
+ });
176
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
177
+ expect.objectContaining({
178
+ Result: "Success",
179
+ Code: "ChoiceSetValues",
180
+ Data: expect.objectContaining({
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
+ }),
192
+ }),
193
+ );
194
+ });
195
+
196
+ it("should pass cursor to choicesets.getById and include NextCursor", async () => {
197
+ const sdk = mockSdk();
198
+ vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue({
199
+ items: [
200
+ {
201
+ id: "v-1",
202
+ name: "n",
203
+ displayName: "N",
204
+ numberId: 1,
205
+ },
206
+ ],
207
+ totalCount: 100,
208
+ hasNextPage: true,
209
+ nextCursor: "next-cur",
210
+ });
211
+ const program = buildProgram();
212
+ await program.parseAsync([
213
+ "node",
214
+ "test",
215
+ "choice-sets",
216
+ "get",
217
+ "cs-1",
218
+ "--cursor",
219
+ "prev",
220
+ "--limit",
221
+ "10",
222
+ ]);
223
+ expect(sdk.entities.choicesets.getById).toHaveBeenCalledWith("cs-1", {
224
+ pageSize: 10,
225
+ cursor: { value: "prev" },
226
+ });
227
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
228
+ expect.objectContaining({
229
+ Data: expect.objectContaining({
230
+ HasNextPage: true,
231
+ NextCursor: "next-cur",
232
+ }),
233
+ }),
234
+ );
235
+ });
236
+
237
+ it("should pass jumpToPage to choicesets.getById when --offset is given", async () => {
238
+ const sdk = mockSdk();
239
+ vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue({
240
+ items: [],
241
+ totalCount: 100,
242
+ hasNextPage: false,
243
+ });
244
+ const program = buildProgram();
245
+ await program.parseAsync([
246
+ "node",
247
+ "test",
248
+ "choice-sets",
249
+ "get",
250
+ "cs-1",
251
+ "--offset",
252
+ "20",
253
+ "--limit",
254
+ "10",
255
+ ]);
256
+ expect(sdk.entities.choicesets.getById).toHaveBeenCalledWith("cs-1", {
257
+ pageSize: 10,
258
+ jumpToPage: 3,
259
+ });
260
+ });
261
+
262
+ it("should error when --offset and --cursor are both given", async () => {
263
+ mockSdk();
264
+ const program = buildProgram();
265
+ await program.parseAsync([
266
+ "node",
267
+ "test",
268
+ "choice-sets",
269
+ "get",
270
+ "cs-1",
271
+ "--offset",
272
+ "10",
273
+ "--cursor",
274
+ "x",
275
+ ]);
276
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
277
+ expect.objectContaining({
278
+ Result: "Failure",
279
+ Message: "--offset and --cursor are mutually exclusive",
280
+ }),
281
+ );
282
+ expect(process.exitCode).toBe(1);
283
+ });
284
+
285
+ it("should error when --limit is invalid", async () => {
286
+ mockSdk();
287
+ const program = buildProgram();
288
+ await program.parseAsync([
289
+ "node",
290
+ "test",
291
+ "choice-sets",
292
+ "get",
293
+ "cs-1",
294
+ "--limit",
295
+ "0",
296
+ ]);
297
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
298
+ expect.objectContaining({
299
+ Result: "Failure",
300
+ Message: "Invalid --limit value",
301
+ }),
302
+ );
303
+ expect(process.exitCode).toBe(1);
304
+ });
305
+
306
+ it("should error when --offset is negative", async () => {
307
+ mockSdk();
308
+ const program = buildProgram();
309
+ await program.parseAsync([
310
+ "node",
311
+ "test",
312
+ "choice-sets",
313
+ "get",
314
+ "cs-1",
315
+ "--offset",
316
+ "-1",
317
+ ]);
318
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
319
+ expect.objectContaining({
320
+ Result: "Failure",
321
+ Message: "Invalid --offset value",
322
+ }),
323
+ );
324
+ expect(process.exitCode).toBe(1);
325
+ });
326
+
327
+ it("should output error when get fails", async () => {
328
+ const sdk = mockSdk();
329
+ vi.mocked(sdk.entities.choicesets.getById).mockRejectedValue(
330
+ new Error("404"),
331
+ );
332
+ const program = buildProgram();
333
+ await program.parseAsync([
334
+ "node",
335
+ "test",
336
+ "choice-sets",
337
+ "get",
338
+ "missing",
339
+ ]);
340
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
341
+ expect.objectContaining({
342
+ Result: "Failure",
343
+ Message: "Error getting choice set 'missing'",
344
+ }),
345
+ );
346
+ expect(process.exitCode).toBe(1);
347
+ });
348
+
349
+ it("should error when SDK connection fails on get", async () => {
350
+ vi.mocked(createDataFabricClient).mockRejectedValue(
351
+ new Error("Not logged in"),
352
+ );
353
+ const program = buildProgram();
354
+ await program.parseAsync([
355
+ "node",
356
+ "test",
357
+ "choice-sets",
358
+ "get",
359
+ "cs-1",
360
+ ]);
361
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
362
+ expect.objectContaining({
363
+ Result: "Failure",
364
+ Message: "Error connecting to Data Fabric",
365
+ }),
366
+ );
367
+ expect(process.exitCode).toBe(1);
368
+ });
369
+
370
+ it("should normalise cursor object {value} to a plain string in NextCursor", async () => {
371
+ const sdk = mockSdk();
372
+ vi.mocked(sdk.entities.choicesets.getById).mockResolvedValue({
373
+ items: [{ id: "v-1", name: "n", displayName: "N", numberId: 1 }],
374
+ totalCount: 5,
375
+ hasNextPage: true,
376
+ nextCursor: { value: "cursor-as-object" } as unknown as string,
377
+ });
378
+ const program = buildProgram();
379
+ await program.parseAsync([
380
+ "node",
381
+ "test",
382
+ "choice-sets",
383
+ "get",
384
+ "cs-1",
385
+ "--limit",
386
+ "2",
387
+ ]);
388
+ const call = vi.mocked(OutputFormatter.success).mock.calls[0][0] as {
389
+ Data: { NextCursor: unknown };
390
+ };
391
+ expect(typeof call.Data.NextCursor).toBe("string");
392
+ expect(call.Data.NextCursor).toBe("cursor-as-object");
393
+ });
394
+ });