@uipath/test-manager-tool 1.202.0-preview.136 → 1.202.0-preview.137

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 CHANGED
@@ -91,6 +91,7 @@ Success responses: `{ "Result": "Success", "Code": "...", "Data": ... }`. Errors
91
91
  | `uip tm testcases add` | Add test cases to a test set. |
92
92
  | `uip tm testcases remove` | Remove test cases from a test set. |
93
93
  | `uip tm testcases link-automation` | Link an Orchestrator package automation to a test case. |
94
+ | `uip tm testcases link-package` | Create and link a test case for every test in an Orchestrator package, in one call. |
94
95
  | `uip tm testcases unlink-automation` | Unlink the automation from a test case. |
95
96
  | `uip tm testcases list-automations` | List test entry points available in an Orchestrator folder. |
96
97
  | `uip tm testcases list-result-history` | List result history for a specific test case. |
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  Command,
4
4
  metadata,
5
5
  registerCommands
6
- } from "./tool-ff6s9vph.js";
6
+ } from "./tool-vg7ewhsa.js";
7
7
  import"./tool-1de529jm.js";
8
8
 
9
9
  // src/index.ts
@@ -11179,7 +11179,7 @@ var require_lib3 = __commonJS(function(exports, module) {
11179
11179
  var package_default = {
11180
11180
  name: "@uipath/test-manager-tool",
11181
11181
  license: "MIT",
11182
- version: "1.202.0-preview.136",
11182
+ version: "1.202.0-preview.137",
11183
11183
  description: "Manage test cases, test sets, executions, and results.",
11184
11184
  private: false,
11185
11185
  repository: {
@@ -13527,6 +13527,14 @@ var RETRY_HINTS = [
13527
13527
  "RetryAfter30Seconds",
13528
13528
  "RetryAfter60Seconds"
13529
13529
  ];
13530
+ var CLI_ERROR_CODE_VALUES = new Set(CLI_ERROR_CODES);
13531
+ var RETRY_HINT_VALUES = new Set(RETRY_HINTS);
13532
+ function isCliErrorCode(value) {
13533
+ return typeof value === "string" && CLI_ERROR_CODE_VALUES.has(value);
13534
+ }
13535
+ function isRetryHint(value) {
13536
+ return typeof value === "string" && RETRY_HINT_VALUES.has(value);
13537
+ }
13530
13538
  var RESULTS = {
13531
13539
  Success: "Success",
13532
13540
  Failure: "Failure",
@@ -14346,8 +14354,6 @@ function emitInvocationRequest(name, success, properties) {
14346
14354
 
14347
14355
  // ../common/src/trackedAction.ts
14348
14356
  var pollSignalSlot = singleton("PollSignal");
14349
- var cliErrorCodeValues = new Set(CLI_ERROR_CODES);
14350
- var retryHintValues = new Set(RETRY_HINTS);
14351
14357
  var TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
14352
14358
  var processContext = {
14353
14359
  exit: (code) => {
@@ -14435,12 +14441,6 @@ function deriveCommandPath(cmd) {
14435
14441
  }
14436
14442
  return commandTelemetryName(parts);
14437
14443
  }
14438
- function isCliErrorCode(value) {
14439
- return typeof value === "string" && cliErrorCodeValues.has(value);
14440
- }
14441
- function isRetryHint(value) {
14442
- return typeof value === "string" && retryHintValues.has(value);
14443
- }
14444
14444
  function isErrorContext(value) {
14445
14445
  return value !== null && typeof value === "object";
14446
14446
  }
@@ -14833,6 +14833,11 @@ function instructionsFor(ctx, err) {
14833
14833
  }
14834
14834
  }
14835
14835
  }
14836
+ // ../common/src/guid.ts
14837
+ var GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14838
+ function isGuid(value) {
14839
+ return GUID_REGEX.test(value);
14840
+ }
14836
14841
  // ../common/src/host-global-options.ts
14837
14842
  var HOST_GLOBAL_OPTIONS_WITH_VALUE = [
14838
14843
  "--output",
@@ -23461,6 +23466,7 @@ function msToDuration2(ms) {
23461
23466
  function calcPassRate(passed, total) {
23462
23467
  return total > 0 ? Math.round(passed / total * 1000) / 10 : 0;
23463
23468
  }
23469
+ var DEFAULT_TEST_CASE_VERSION = "1.0.0";
23464
23470
  var TM_FORBIDDEN_MESSAGE = "Forbidden (403). Ensure the account has the required Test Manager permissions (TestExecution.Read, TestSet.Read, etc.).";
23465
23471
  var TM_LICENSED_USER_FORBIDDEN_MESSAGE = "Forbidden (403). This operation requires a Test Manager license. Contact your tenant admin to assign a license, or use a read-only command.";
23466
23472
  var TM_NOT_AVAILABLE_MESSAGE = "Test Manager is not enabled for this tenant.";
@@ -35860,6 +35866,189 @@ async function findTestCasesByLabels(testCasesApi, projectId, labels, maxMatches
35860
35866
  }
35861
35867
  }
35862
35868
 
35869
+ // src/utils/package-automation.ts
35870
+ function instructiveError(message, instructions, errorCode2, retry = "RetryWillNotFix") {
35871
+ const error = new Error(message);
35872
+ error.instructions = instructions;
35873
+ error.errorCode = errorCode2;
35874
+ error.retry = retry;
35875
+ return error;
35876
+ }
35877
+ function readInstructions(error) {
35878
+ const candidate = error;
35879
+ return typeof candidate?.instructions === "string" ? candidate.instructions : undefined;
35880
+ }
35881
+ function readClassification(error) {
35882
+ const candidate = error;
35883
+ return {
35884
+ errorCode: isCliErrorCode(candidate?.errorCode) ? candidate.errorCode : undefined,
35885
+ retry: isRetryHint(candidate?.retry) ? candidate.retry : undefined
35886
+ };
35887
+ }
35888
+ var ENTRY_POINT_PAGE_SIZE = 100;
35889
+ var ENTRY_POINT_MAX_PAGES = 50;
35890
+ async function resolveAutomationFolder(folderKey, tenant) {
35891
+ if (!isGuid(folderKey)) {
35892
+ throw instructiveError(`Folder key '${folderKey}' is not a UUID.`, "Pass the folder's Key from 'uip or folders list'.", "invalid_argument");
35893
+ }
35894
+ const foldersApi = await createApiClient(FoldersApi, { tenant });
35895
+ const result = await foldersApi.foldersGet({
35896
+ $filter: `Key eq ${folderKey}`,
35897
+ $top: 1
35898
+ });
35899
+ const folder = result.value?.[0];
35900
+ if (!folder?.displayName) {
35901
+ throw instructiveError(`Folder with key '${folderKey}' not found.`, "List the folders you can see with 'uip or folders list' and pass one of their Key values.", "not_found");
35902
+ }
35903
+ return {
35904
+ displayName: folder.displayName,
35905
+ linkFolderKey: folder.feedType === FolderDtoFeedTypeEnum.Processes ? null : folderKey
35906
+ };
35907
+ }
35908
+ function readEntryPointPage(response) {
35909
+ if (Array.isArray(response)) {
35910
+ return { items: response };
35911
+ }
35912
+ const record = response ?? {};
35913
+ const items = record.data ?? [];
35914
+ const paging = record.paging;
35915
+ const total = paging?.total ?? record.total;
35916
+ return { items, total };
35917
+ }
35918
+ function matchesPackageName(entryPoint, packageName) {
35919
+ return (entryPoint.packageName ?? "").toLowerCase() === packageName.toLowerCase();
35920
+ }
35921
+ async function fetchPackageEntryPoints(orchestratorApi, projectId, folderKey, search = "") {
35922
+ const all = [];
35923
+ for (let page = 0;; page++) {
35924
+ if (page >= ENTRY_POINT_MAX_PAGES) {
35925
+ throw instructiveError(`Folder exposes more than ${ENTRY_POINT_MAX_PAGES * ENTRY_POINT_PAGE_SIZE} test entry points.`, "Narrow the selection with --package-name or --test-name.", "invalid_argument");
35926
+ }
35927
+ const response = await orchestratorApi.orchestratorGetUniquePackageEntryPoints(toGetPackageEntryPointsRequest(projectId, folderKey ?? null, true, search, ENTRY_POINT_PAGE_SIZE, page * ENTRY_POINT_PAGE_SIZE));
35928
+ const { items, total } = readEntryPointPage(response);
35929
+ all.push(...items);
35930
+ if (all.length >= (total ?? all.length) || items.length < ENTRY_POINT_PAGE_SIZE) {
35931
+ break;
35932
+ }
35933
+ }
35934
+ return all;
35935
+ }
35936
+ var TEST_CASE_PAGE_SIZE = 200;
35937
+ var TEST_CASE_MAX_PAGES = 50;
35938
+ async function fetchTestCasesByName(testCasesApi, projectId) {
35939
+ const byName = new Map;
35940
+ for (let page = 0;; page++) {
35941
+ if (page >= TEST_CASE_MAX_PAGES) {
35942
+ throw instructiveError(`Project holds more than ${TEST_CASE_MAX_PAGES * TEST_CASE_PAGE_SIZE} test cases — too many to index for automation linking.`, "Link the automations from a smaller Test Manager project, or use 'uip tm testcases link-automation' per test.", "invalid_argument");
35943
+ }
35944
+ const response = await testCasesApi.testCasesGetTestCases({
35945
+ projectId,
35946
+ top: TEST_CASE_PAGE_SIZE,
35947
+ skip: page * TEST_CASE_PAGE_SIZE,
35948
+ orderby: "name asc"
35949
+ });
35950
+ const items = response.data ?? [];
35951
+ for (const testCase of items) {
35952
+ const key = (testCase.name ?? "").toLowerCase();
35953
+ if (!key || byName.has(key))
35954
+ continue;
35955
+ byName.set(key, {
35956
+ id: testCase.id ?? "",
35957
+ objKey: testCase.objKey ?? ""
35958
+ });
35959
+ }
35960
+ const total = response.paging?.total ?? byName.size;
35961
+ if ((page + 1) * TEST_CASE_PAGE_SIZE >= total || items.length < TEST_CASE_PAGE_SIZE) {
35962
+ break;
35963
+ }
35964
+ }
35965
+ return byName;
35966
+ }
35967
+ async function linkPackageEntryPoints(testCasesApi, input) {
35968
+ const { projectId, entryPoints, folder, dryRun: dryRun2 } = input;
35969
+ assertDistinctEntryPointNames(entryPoints);
35970
+ const byName = await fetchTestCasesByName(testCasesApi, projectId);
35971
+ const rows = [];
35972
+ for (const entryPoint of entryPoints) {
35973
+ const testName = entryPoint.name ?? "";
35974
+ const existing = byName.get(testName.toLowerCase());
35975
+ if (dryRun2) {
35976
+ rows.push(toRow(entryPoint, existing, existing ? "WouldReuse" : "WouldCreate"));
35977
+ continue;
35978
+ }
35979
+ const [failure, linked] = await catchError(createAndLink(testCasesApi, {
35980
+ projectId,
35981
+ entryPoint,
35982
+ existing,
35983
+ folder
35984
+ }));
35985
+ if (failure) {
35986
+ throw wrapLinkFailure(failure, testName, rows.length, entryPoints.length);
35987
+ }
35988
+ byName.set(testName.toLowerCase(), linked.testCase);
35989
+ rows.push(toRow(entryPoint, linked.testCase, linked.action));
35990
+ }
35991
+ return rows;
35992
+ }
35993
+ function wrapLinkFailure(failure, testName, done, total) {
35994
+ const original = failure;
35995
+ const wrapped = new Error(`Linked ${done} of ${total} tests, then failed on '${testName}': ${failure.message}`, { cause: failure });
35996
+ if (original.status !== undefined)
35997
+ wrapped.status = original.status;
35998
+ if (original.response !== undefined)
35999
+ wrapped.response = original.response;
36000
+ wrapped.instructions = "Run the same command again — test cases that already exist are reused, so it picks up where it stopped.";
36001
+ return wrapped;
36002
+ }
36003
+ function toRow(entryPoint, testCase, action) {
36004
+ return {
36005
+ TestName: entryPoint.name ?? "",
36006
+ PackageName: entryPoint.packageName ?? "",
36007
+ PackageVersion: entryPoint.packageAppVersion ?? "",
36008
+ TestCaseKey: testCase?.objKey ?? "",
36009
+ TestCaseId: testCase?.id ?? "",
36010
+ Action: action
36011
+ };
36012
+ }
36013
+ function assertDistinctEntryPointNames(entryPoints) {
36014
+ const seen = new Set;
36015
+ const collisions = new Set;
36016
+ for (const entryPoint of entryPoints) {
36017
+ const key = (entryPoint.name ?? "").toLowerCase();
36018
+ if (seen.has(key))
36019
+ collisions.add(entryPoint.name ?? "");
36020
+ seen.add(key);
36021
+ }
36022
+ if (collisions.size > 0) {
36023
+ throw instructiveError(`Test names appear in more than one package: ${[...collisions].join(", ")}. A test case can hold one automation, so linking both would overwrite the first.`, "Pass --package-name to pick which package's tests to link, or --test-name to link the ones that do not collide.", "invalid_argument");
36024
+ }
36025
+ }
36026
+ async function createAndLink(testCasesApi, input) {
36027
+ const { projectId, entryPoint, existing, folder } = input;
36028
+ const testName = entryPoint.name ?? "";
36029
+ let testCase = existing;
36030
+ if (!testCase) {
36031
+ const created = await testCasesApi.testCasesCreate({
36032
+ projectId,
36033
+ uiPathTestManagementHubTestManagementAbstractionsDTOsCreateTestCaseRequest: {
36034
+ name: testName,
36035
+ description: "",
36036
+ projectId,
36037
+ version: DEFAULT_TEST_CASE_VERSION
36038
+ }
36039
+ });
36040
+ testCase = { id: created.id ?? "", objKey: created.objKey ?? "" };
36041
+ }
36042
+ await testCasesApi.testCasesUpdateTestCasePackageAutomation(toUpdatePackageAutomationRequest(testCase.id, projectId, {
36043
+ packageEntryPointUniqueId: entryPoint.packageEntryPointId ?? null,
36044
+ packageIdentifier: entryPoint.packageName ?? null,
36045
+ packageEntryPointName: testName,
36046
+ folderKey: folder.linkFolderKey,
36047
+ packageSourceName: folder.displayName
36048
+ }));
36049
+ return { testCase, action: existing ? "Reused" : "Created" };
36050
+ }
36051
+
35863
36052
  // src/utils/step-input.ts
35864
36053
  function hasScalarStep(options) {
35865
36054
  return options.description !== undefined || options.expectedResult !== undefined || options.actionType !== undefined || options.clipboardData !== undefined || options.orderNo !== undefined;
@@ -36060,6 +36249,67 @@ var TESTCASE_LINK_AUTOMATION_EXAMPLES = [
36060
36249
  }
36061
36250
  }
36062
36251
  ];
36252
+ var TESTCASE_LINK_PACKAGE_EXAMPLES = [
36253
+ {
36254
+ Description: "Create and link a test case for every test in one Orchestrator package",
36255
+ Command: "uip tm testcases link-package --project-key DEMO --folder-key f0f0f0f0-0000-0000-0000-000000000001 --package-name InvoiceTests",
36256
+ Output: {
36257
+ Code: "TestCaseLinkPackage",
36258
+ Data: [
36259
+ {
36260
+ TestName: "SmokeTest",
36261
+ PackageName: "InvoiceTests",
36262
+ PackageVersion: "1.0.2",
36263
+ TestCaseKey: "DEMO:7",
36264
+ TestCaseId: "a1b2c3d4-0000-0000-0000-000000000007",
36265
+ Action: "Created"
36266
+ },
36267
+ {
36268
+ TestName: "RegressionTest",
36269
+ PackageName: "InvoiceTests",
36270
+ PackageVersion: "1.0.2",
36271
+ TestCaseKey: "DEMO:3",
36272
+ TestCaseId: "a1b2c3d4-0000-0000-0000-000000000003",
36273
+ Action: "Reused"
36274
+ }
36275
+ ]
36276
+ }
36277
+ },
36278
+ {
36279
+ Description: "Preview what would be created and linked, without writing",
36280
+ Command: "uip tm testcases link-package --project-key DEMO --folder-key f0f0f0f0-0000-0000-0000-000000000001 --package-name InvoiceTests --dry-run",
36281
+ Output: {
36282
+ Code: "TestCaseLinkPackageDryRun",
36283
+ Data: [
36284
+ {
36285
+ TestName: "SmokeTest",
36286
+ PackageName: "InvoiceTests",
36287
+ PackageVersion: "1.0.2",
36288
+ TestCaseKey: "",
36289
+ TestCaseId: "",
36290
+ Action: "WouldCreate"
36291
+ }
36292
+ ]
36293
+ }
36294
+ },
36295
+ {
36296
+ Description: "Link only two named tests out of the package",
36297
+ Command: "uip tm testcases link-package --project-key DEMO --folder-key f0f0f0f0-0000-0000-0000-000000000001 --package-name InvoiceTests --test-name SmokeTest RegressionTest",
36298
+ Output: {
36299
+ Code: "TestCaseLinkPackage",
36300
+ Data: [
36301
+ {
36302
+ TestName: "SmokeTest",
36303
+ PackageName: "InvoiceTests",
36304
+ PackageVersion: "1.0.2",
36305
+ TestCaseKey: "DEMO:7",
36306
+ TestCaseId: "a1b2c3d4-0000-0000-0000-000000000007",
36307
+ Action: "Reused"
36308
+ }
36309
+ ]
36310
+ }
36311
+ }
36312
+ ];
36063
36313
  var TESTCASE_UPDATE_EXAMPLES = [
36064
36314
  {
36065
36315
  Description: "Rename a test case",
@@ -36401,9 +36651,39 @@ async function emitTmFailure2(error) {
36401
36651
  });
36402
36652
  processContext.exit(1);
36403
36653
  }
36654
+ async function linkPackage(tmConfig, projectId, options) {
36655
+ const folder = await resolveAutomationFolder(options.folderKey, options.tenant);
36656
+ const entryPoints = await fetchPackageEntryPoints(new OrchestratorApi(tmConfig), projectId, options.folderKey);
36657
+ const selected = selectEntryPoints(entryPoints, options);
36658
+ if (selected.length === 0) {
36659
+ throw new Error(describeEmptySelection(options));
36660
+ }
36661
+ return linkPackageEntryPoints(new TestCasesApi(tmConfig), {
36662
+ projectId,
36663
+ entryPoints: selected,
36664
+ folder,
36665
+ dryRun: options.dryRun === true
36666
+ });
36667
+ }
36668
+ function selectEntryPoints(entryPoints, options) {
36669
+ const wantedTests = options.testName?.map((name) => name.toLowerCase());
36670
+ return entryPoints.filter((entryPoint) => {
36671
+ if (options.packageName !== undefined && !matchesPackageName(entryPoint, options.packageName)) {
36672
+ return false;
36673
+ }
36674
+ return wantedTests === undefined || wantedTests.includes((entryPoint.name ?? "").toLowerCase());
36675
+ });
36676
+ }
36677
+ function describeEmptySelection(options) {
36678
+ const scope = [
36679
+ options.packageName ? `package '${options.packageName}'` : undefined,
36680
+ options.testName?.length ? `tests '${options.testName.join("', '")}'` : undefined
36681
+ ].filter((part) => part !== undefined).join(" and ");
36682
+ return scope ? `No test entry points found for ${scope} in folder '${options.folderKey}'.` : `No test entry points found in folder '${options.folderKey}'.`;
36683
+ }
36404
36684
  var registerTestcaseCommand = (program2) => {
36405
36685
  const testcaseCmd = program2.command("testcases").description("Manage Test Manager test cases");
36406
- testcaseCmd.command("create").description("Create a new test case in a Test Manager project.").requiredOption("--project-key <key>", "Test Manager project key (e.g. DEMO)").requiredOption("--name <name>", "Name of the test case").option("--description <text>", "Description for the test case").option("--version <version>", "Version of the test case", "1.0.0").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--log-level <level>", "Log verbosity: debug, info, warn, error", "Information").examples(TESTCASE_CREATE_EXAMPLES).trackedAction(processContext, async (options) => {
36686
+ testcaseCmd.command("create").description("Create a new test case in a Test Manager project.").requiredOption("--project-key <key>", "Test Manager project key (e.g. DEMO)").requiredOption("--name <name>", "Name of the test case").option("--description <text>", "Description for the test case").option("--version <version>", "Version of the test case", DEFAULT_TEST_CASE_VERSION).addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--log-level <level>", "Log verbosity: debug, info, warn, error", "Information").examples(TESTCASE_CREATE_EXAMPLES).trackedAction(processContext, async (options) => {
36407
36687
  const [authError, ctx] = await catchError(initializeContextWithProject(options));
36408
36688
  if (authError) {
36409
36689
  OutputFormatter.error({
@@ -36649,11 +36929,15 @@ var registerTestcaseCommand = (program2) => {
36649
36929
  top: 50
36650
36930
  }));
36651
36931
  if (resolveError) {
36652
- const { message, details } = await extractErrorDetails2(resolveError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
36932
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(resolveError, {
36933
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
36934
+ });
36653
36935
  OutputFormatter.error({
36654
- Result: RESULTS.Failure,
36936
+ Result: result,
36937
+ ErrorCode: errorCode2,
36655
36938
  Message: message,
36656
- Instructions: details
36939
+ Instructions: details,
36940
+ Retry: retry
36657
36941
  });
36658
36942
  processContext.exit(1);
36659
36943
  return;
@@ -36669,15 +36953,30 @@ var registerTestcaseCommand = (program2) => {
36669
36953
  processContext.exit(1);
36670
36954
  return;
36671
36955
  }
36956
+ if (!isGuid(options.folderKey)) {
36957
+ OutputFormatter.error({
36958
+ Result: RESULTS.Failure,
36959
+ ErrorCode: "invalid_argument",
36960
+ Message: `Folder key '${options.folderKey}' is not a UUID.`,
36961
+ Instructions: "Pass the folder's Key from 'uip or folders list'.",
36962
+ Retry: "RetryWillNotFix"
36963
+ });
36964
+ processContext.exit(1);
36965
+ return;
36966
+ }
36672
36967
  const [folderApiError, foldersApi] = await catchError(createApiClient(FoldersApi, {
36673
36968
  tenant: options.tenant
36674
36969
  }));
36675
36970
  if (folderApiError) {
36676
- const { message, details } = await extractErrorDetails2(folderApiError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
36971
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(folderApiError, {
36972
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
36973
+ });
36677
36974
  OutputFormatter.error({
36678
- Result: RESULTS.Failure,
36975
+ Result: result,
36976
+ ErrorCode: errorCode2,
36679
36977
  Message: message,
36680
- Instructions: details
36978
+ Instructions: details,
36979
+ Retry: retry
36681
36980
  });
36682
36981
  processContext.exit(1);
36683
36982
  return;
@@ -36687,11 +36986,15 @@ var registerTestcaseCommand = (program2) => {
36687
36986
  $top: 1
36688
36987
  }));
36689
36988
  if (foldersError) {
36690
- const { message, details } = await extractErrorDetails2(foldersError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
36989
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(foldersError, {
36990
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
36991
+ });
36691
36992
  OutputFormatter.error({
36692
- Result: RESULTS.Failure,
36993
+ Result: result,
36994
+ ErrorCode: errorCode2,
36693
36995
  Message: message,
36694
- Instructions: details
36996
+ Instructions: details,
36997
+ Retry: retry
36695
36998
  });
36696
36999
  processContext.exit(1);
36697
37000
  return;
@@ -36700,7 +37003,10 @@ var registerTestcaseCommand = (program2) => {
36700
37003
  if (!folderMatch?.displayName) {
36701
37004
  OutputFormatter.error({
36702
37005
  Result: RESULTS.Failure,
36703
- Message: `Folder with key '${options.folderKey}' not found.`
37006
+ ErrorCode: "not_found",
37007
+ Message: `Folder with key '${options.folderKey}' not found.`,
37008
+ Instructions: "List the folders you can see with 'uip or folders list' and pass one of their Key values.",
37009
+ Retry: "RetryWillNotFix"
36704
37010
  });
36705
37011
  processContext.exit(1);
36706
37012
  return;
@@ -36708,11 +37014,15 @@ var registerTestcaseCommand = (program2) => {
36708
37014
  const folderDisplayName = folderMatch.displayName;
36709
37015
  const [epError, entryPointsPage] = await catchError(orchestratorApi.orchestratorGetUniquePackageEntryPoints(toGetPackageEntryPointsRequest(projectId, options.folderKey, true, options.testName, 100, 0)));
36710
37016
  if (epError) {
36711
- const { message, details } = await extractErrorDetails2(epError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
37017
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(epError, {
37018
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
37019
+ });
36712
37020
  OutputFormatter.error({
36713
- Result: RESULTS.Failure,
37021
+ Result: result,
37022
+ ErrorCode: errorCode2,
36714
37023
  Message: message,
36715
- Instructions: details
37024
+ Instructions: details,
37025
+ Retry: retry
36716
37026
  });
36717
37027
  processContext.exit(1);
36718
37028
  return;
@@ -36734,11 +37044,15 @@ var registerTestcaseCommand = (program2) => {
36734
37044
  packageSourceName: folderDisplayName
36735
37045
  })));
36736
37046
  if (updateError) {
36737
- const { message, details } = await extractErrorDetails2(updateError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
37047
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(updateError, {
37048
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
37049
+ });
36738
37050
  OutputFormatter.error({
36739
- Result: RESULTS.Failure,
37051
+ Result: result,
37052
+ ErrorCode: errorCode2,
36740
37053
  Message: message,
36741
- Instructions: details
37054
+ Instructions: details,
37055
+ Retry: retry
36742
37056
  });
36743
37057
  processContext.exit(1);
36744
37058
  return;
@@ -36751,6 +37065,38 @@ var registerTestcaseCommand = (program2) => {
36751
37065
  Result: "Linked"
36752
37066
  }));
36753
37067
  });
37068
+ testcaseCmd.command("link-package").description("Create and link a test case for every test in an Orchestrator package, in one call.").requiredOption("--project-key <key>", "Test Manager project key (e.g. DEMO)").requiredOption("--folder-key <uuid>", "Orchestrator folder key UUID (from 'uip or folders list')").option("--package-name <name>", "Only link tests from this package (case-insensitive exact match). Omit to link every test the folder exposes.").option("--test-name <name...>", "Only link these tests (case-insensitive). Omit to link all of them.").option("--dry-run", "Preview which test cases would be created, reused and linked, without writing anything.").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--log-level <level>", "Log verbosity: debug, info, warn, error", "Information").examples(TESTCASE_LINK_PACKAGE_EXAMPLES).trackedAction(processContext, async (options) => {
37069
+ const [authError, ctx] = await catchError(initializeContextWithProject(options));
37070
+ if (authError) {
37071
+ OutputFormatter.error({
37072
+ Result: RESULTS.Failure,
37073
+ Message: authError.message,
37074
+ Instructions: instructionsFor("auth")
37075
+ });
37076
+ processContext.exit(1);
37077
+ return;
37078
+ }
37079
+ if (!ctx)
37080
+ return;
37081
+ const { tmConfig, projectId } = ctx;
37082
+ const [error, rows] = await catchError(linkPackage(tmConfig, projectId, options));
37083
+ if (error) {
37084
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(error, {
37085
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
37086
+ });
37087
+ const stated = readClassification(error);
37088
+ OutputFormatter.error({
37089
+ Result: result,
37090
+ ErrorCode: stated.errorCode ?? errorCode2,
37091
+ Message: message,
37092
+ Instructions: readInstructions(error) ?? (details && details !== message ? details : `Run 'uip tm testcases list-automations --project-key ${options.projectKey} --folder-key ${options.folderKey}' to see the tests this folder exposes.`),
37093
+ Retry: stated.retry ?? retry
37094
+ });
37095
+ processContext.exit(1);
37096
+ return;
37097
+ }
37098
+ OutputFormatter.success(new SuccessOutput(options.dryRun ? "TestCaseLinkPackageDryRun" : "TestCaseLinkPackage", rows));
37099
+ });
36754
37100
  testcaseCmd.command("update").description("Update a test case's name, description, or pre/post-condition.").requiredOption("--project-key <key>", "Test Manager project key (e.g. DEMO)").requiredOption("--test-case-key <key>", "Test case key (e.g. DEMO:1)").option("--name <name>", "New test case name").option("--description <text>", "New test case description").option("--pre-condition <text>", "New precondition (what must be true before running the test)").option("--post-condition <text>", "New postcondition (what should be true after running the test)").addOption(createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>")).option("--log-level <level>", "Log verbosity: debug, info, warn, error", "Information").examples(TESTCASE_UPDATE_EXAMPLES).trackedAction(processContext, async (options) => {
36755
37101
  const operations = [];
36756
37102
  if (options.name !== undefined)
@@ -36977,32 +37323,22 @@ var registerTestcaseCommand = (program2) => {
36977
37323
  if (!ctx)
36978
37324
  return;
36979
37325
  const { tmConfig, projectId } = ctx;
36980
- const orchestratorApi = new OrchestratorApi(tmConfig);
36981
- const all = [];
36982
- const top = 100;
36983
- let skip = 0;
36984
- while (true) {
36985
- const [epError, entryPointsPage] = await catchError(orchestratorApi.orchestratorGetUniquePackageEntryPoints(toGetPackageEntryPointsRequest(projectId, options.folderKey ?? null, true, "", top, skip)));
36986
- if (epError) {
36987
- const { message, details } = await extractErrorDetails2(epError, { forbiddenMessage: TM_FORBIDDEN_MESSAGE });
36988
- OutputFormatter.error({
36989
- Result: RESULTS.Failure,
36990
- Message: message,
36991
- Instructions: details
36992
- });
36993
- processContext.exit(1);
36994
- return;
36995
- }
36996
- const data = entryPointsPage;
36997
- const items = data.data ?? data ?? [];
36998
- all.push(...items);
36999
- const paging = data.paging;
37000
- const total = paging?.total ?? data.total ?? items.length;
37001
- skip += top;
37002
- if (skip >= total || items.length < top)
37003
- break;
37326
+ const [epError, all] = await catchError(fetchPackageEntryPoints(new OrchestratorApi(tmConfig), projectId, options.folderKey));
37327
+ if (epError) {
37328
+ const { result, errorCode: errorCode2, message, retry, details } = await extractErrorDetails2(epError, {
37329
+ forbiddenMessage: TM_FORBIDDEN_MESSAGE
37330
+ });
37331
+ OutputFormatter.error({
37332
+ Result: result,
37333
+ ErrorCode: errorCode2,
37334
+ Message: message,
37335
+ Instructions: details,
37336
+ Retry: retry
37337
+ });
37338
+ processContext.exit(1);
37339
+ return;
37004
37340
  }
37005
- const filtered = options.packageName ? all.filter((ep) => ep.packageName?.toLowerCase() === options.packageName.toLowerCase()) : all;
37341
+ const filtered = options.packageName ? all.filter((ep) => matchesPackageName(ep, options.packageName)) : all;
37006
37342
  const rows = filtered.map((ep) => ({
37007
37343
  PackageName: ep.packageName ?? "",
37008
37344
  TestName: ep.name ?? "",
@@ -38951,4 +39287,4 @@ var registerCommands = async (program2) => {
38951
39287
 
38952
39288
  export { Command, metadata, registerCommands };
38953
39289
 
38954
- //# debugId=FAABCEF58521CEA164756E2164756E21
39290
+ //# debugId=D5D78FA549BBB2CB64756E2164756E21
package/dist/tool.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  metadata,
3
3
  registerCommands
4
- } from "./tool-ff6s9vph.js";
4
+ } from "./tool-vg7ewhsa.js";
5
5
  import"./tool-1de529jm.js";
6
6
  export {
7
7
  metadata,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/test-manager-tool",
3
3
  "license": "MIT",
4
- "version": "1.202.0-preview.136",
4
+ "version": "1.202.0-preview.137",
5
5
  "description": "Manage test cases, test sets, executions, and results.",
6
6
  "private": false,
7
7
  "repository": {
@@ -26,5 +26,5 @@
26
26
  "files": [
27
27
  "dist"
28
28
  ],
29
- "gitHead": "f6270de2c7c04f4c43b2f5187b0c3d3c314c2610"
29
+ "gitHead": "bbb20a6d3501afc3435a92af9ae2e9f7ab2e34f6"
30
30
  }