@lambdatest/smartui-cli 4.1.11-beta.0 → 4.1.12

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.
Files changed (2) hide show
  1. package/dist/index.cjs +792 -52
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -465,6 +465,33 @@ var constants_default = {
465
465
  }
466
466
  ]
467
467
  }
468
+ },
469
+ APP_FIGMA_CONFIG: {
470
+ mobile: [
471
+ {
472
+ "name": "Pixel 8",
473
+ "platform": ["android 14"]
474
+ },
475
+ {
476
+ "name": "iPhone 15",
477
+ "platform": ["ios 17"]
478
+ }
479
+ ],
480
+ figma: {
481
+ "depth": 2,
482
+ "configs": [
483
+ {
484
+ "figma_file_token": "<token>",
485
+ "figma_ids": ["id-1", "id-2"],
486
+ "screenshot_names": ["homepage", "about"]
487
+ },
488
+ {
489
+ "figma_file_token": "<token>",
490
+ "figma_ids": ["id-3", "id-4"],
491
+ "screenshot_names": ["xyz", "abc"]
492
+ }
493
+ ]
494
+ }
468
495
  }
469
496
  };
470
497
 
@@ -1084,11 +1111,126 @@ var FigmaWebConfigSchema = {
1084
1111
  "required": ["web", "figma"],
1085
1112
  additionalProperties: false
1086
1113
  };
1114
+ var FigmaAppConfigSchema = {
1115
+ type: "object",
1116
+ "properties": {
1117
+ "web": {
1118
+ "type": "object",
1119
+ "properties": {
1120
+ browsers: {
1121
+ type: "array",
1122
+ items: { type: "string", enum: [constants_default.CHROME, constants_default.FIREFOX, constants_default.SAFARI, constants_default.EDGE] },
1123
+ uniqueItems: true,
1124
+ maxItems: 4,
1125
+ errorMessage: `allowed browsers - ${constants_default.CHROME}, ${constants_default.FIREFOX}, ${constants_default.SAFARI}, ${constants_default.EDGE}`
1126
+ },
1127
+ "viewports": {
1128
+ "type": "array",
1129
+ "items": {
1130
+ "type": "array",
1131
+ "items": {
1132
+ "type": "integer",
1133
+ "minimum": 1
1134
+ },
1135
+ "minItems": 1
1136
+ }
1137
+ }
1138
+ },
1139
+ "required": ["browsers"]
1140
+ },
1141
+ "mobile": {
1142
+ "type": "array",
1143
+ "items": {
1144
+ "type": "object",
1145
+ "properties": {
1146
+ name: {
1147
+ type: "string",
1148
+ minLength: 1,
1149
+ enum: Object.keys(constants_default.SUPPORTED_MOBILE_DEVICES),
1150
+ errorMessage: "unsupported mobile device name"
1151
+ },
1152
+ "platform": {
1153
+ "type": "array",
1154
+ "items": {
1155
+ "type": "string"
1156
+ },
1157
+ uniqueItems: true
1158
+ },
1159
+ orientation: {
1160
+ type: "string",
1161
+ enum: [constants_default.MOBILE_ORIENTATION_PORTRAIT, constants_default.MOBILE_ORIENTATION_LANDSCAPE],
1162
+ errorMessage: `Invalid config; orientation must be ${constants_default.MOBILE_ORIENTATION_PORTRAIT}/${constants_default.MOBILE_ORIENTATION_LANDSCAPE}`
1163
+ }
1164
+ },
1165
+ "required": ["name"]
1166
+ },
1167
+ uniqueItems: true
1168
+ },
1169
+ "figma": {
1170
+ "type": "object",
1171
+ "properties": {
1172
+ depth: {
1173
+ type: "integer",
1174
+ minimum: 2,
1175
+ errorMessage: "Depth must be an integer and greater than 1"
1176
+ },
1177
+ "configs": {
1178
+ "type": "array",
1179
+ "items": {
1180
+ "type": "object",
1181
+ "properties": {
1182
+ "figma_file_token": {
1183
+ "type": "string",
1184
+ minLength: 1,
1185
+ errorMessage: "figma_file_token is mandatory and cannot be empty"
1186
+ },
1187
+ "figma_ids": {
1188
+ "type": "array",
1189
+ "items": {
1190
+ "type": "string",
1191
+ minLength: 1,
1192
+ errorMessage: "Each ID in figma_ids must be a non-empty string"
1193
+ },
1194
+ minItems: 1,
1195
+ uniqueItems: true,
1196
+ errorMessage: {
1197
+ type: "figma_ids must be an array of strings",
1198
+ minItems: "figma_ids cannot be empty",
1199
+ uniqueItems: "figma_ids must contain unique values"
1200
+ }
1201
+ },
1202
+ "screenshot_names": {
1203
+ "type": "array",
1204
+ "items": {
1205
+ "type": "string"
1206
+ },
1207
+ uniqueItems: false
1208
+ }
1209
+ },
1210
+ "required": ["figma_file_token", "figma_ids"]
1211
+ },
1212
+ uniqueItems: true,
1213
+ errorMessage: {
1214
+ uniqueItems: "Each entry in the figma configs must be unique"
1215
+ }
1216
+ }
1217
+ },
1218
+ "required": ["configs"]
1219
+ },
1220
+ smartIgnore: {
1221
+ type: "boolean",
1222
+ errorMessage: "Invalid config; smartIgnore must be true/false"
1223
+ }
1224
+ },
1225
+ "required": ["mobile", "figma"],
1226
+ additionalProperties: false
1227
+ };
1087
1228
  var validateConfig = ajv.compile(ConfigSchema);
1088
1229
  var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
1089
1230
  var validateSnapshot = ajv.compile(SnapshotSchema);
1090
1231
  var validateFigmaDesignConfig = ajv.compile(FigmaDesignConfigSchema);
1091
1232
  var validateWebFigmaConfig = ajv.compile(FigmaWebConfigSchema);
1233
+ var validateAppFigmaConfig = ajv.compile(FigmaAppConfigSchema);
1092
1234
  var lambdaTunnel = __require("@lambdatest/node-tunnel");
1093
1235
  util.promisify(setTimeout);
1094
1236
  var tunnelInstance;
@@ -1595,7 +1737,9 @@ var env_default = () => {
1595
1737
  CURRENT_BRANCH,
1596
1738
  PROJECT_NAME,
1597
1739
  SMARTUI_API_PROXY,
1598
- SMARTUI_API_SKIP_CERTIFICATES
1740
+ SMARTUI_API_SKIP_CERTIFICATES,
1741
+ USE_REMOTE_DISCOVERY,
1742
+ SMART_GIT
1599
1743
  } = process.env;
1600
1744
  return {
1601
1745
  PROJECT_TOKEN,
@@ -1615,7 +1759,9 @@ var env_default = () => {
1615
1759
  SMARTUI_DO_NOT_USE_CAPTURED_COOKIES: SMARTUI_DO_NOT_USE_CAPTURED_COOKIES === "true",
1616
1760
  PROJECT_NAME,
1617
1761
  SMARTUI_API_PROXY,
1618
- SMARTUI_API_SKIP_CERTIFICATES: SMARTUI_API_SKIP_CERTIFICATES === "true"
1762
+ SMARTUI_API_SKIP_CERTIFICATES: SMARTUI_API_SKIP_CERTIFICATES === "true",
1763
+ USE_REMOTE_DISCOVERY: USE_REMOTE_DISCOVERY === "true",
1764
+ SMART_GIT: SMART_GIT === "true"
1619
1765
  };
1620
1766
  };
1621
1767
  var logContext = {};
@@ -1710,7 +1856,7 @@ var authExec_default = (ctx) => {
1710
1856
  };
1711
1857
 
1712
1858
  // package.json
1713
- var version = "4.1.11-beta.0";
1859
+ var version = "4.1.12";
1714
1860
  var package_default = {
1715
1861
  name: "@lambdatest/smartui-cli",
1716
1862
  version,
@@ -1940,7 +2086,7 @@ var httpClient = class {
1940
2086
  }
1941
2087
  });
1942
2088
  }
1943
- createBuild(git, config, log2, buildName, isStartExec) {
2089
+ createBuild(git, config, log2, buildName, isStartExec, smartGit, markBaseline, baselineBuild) {
1944
2090
  return this.request({
1945
2091
  url: "/build",
1946
2092
  method: "POST",
@@ -1949,7 +2095,10 @@ var httpClient = class {
1949
2095
  config,
1950
2096
  buildName,
1951
2097
  isStartExec,
1952
- packageVersion: package_default.version
2098
+ packageVersion: package_default.version,
2099
+ smartGit,
2100
+ markBaseline,
2101
+ baselineBuild
1953
2102
  }
1954
2103
  }, log2);
1955
2104
  }
@@ -2058,7 +2207,7 @@ var httpClient = class {
2058
2207
  type: ctx.testType,
2059
2208
  source: "cli"
2060
2209
  },
2061
- async: false,
2210
+ doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2062
2211
  discoveryErrors
2063
2212
  }
2064
2213
  }, ctx.log);
@@ -2079,7 +2228,7 @@ var httpClient = class {
2079
2228
  type: ctx.testType,
2080
2229
  source: "cli"
2081
2230
  },
2082
- async: false,
2231
+ doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2083
2232
  discoveryErrors
2084
2233
  }
2085
2234
  }, ctx.log);
@@ -2267,6 +2416,20 @@ var httpClient = class {
2267
2416
  params: { buildId }
2268
2417
  }, log2);
2269
2418
  }
2419
+ fetchBuildInfo(requestData, ctx) {
2420
+ return this.request({
2421
+ url: `/fetchBuildInfo`,
2422
+ method: "GET",
2423
+ data: requestData
2424
+ }, ctx.log);
2425
+ }
2426
+ mergeBuildsByBuildId(requestData, ctx) {
2427
+ return this.request({
2428
+ url: `/mergeBuilds`,
2429
+ method: "POST",
2430
+ data: requestData
2431
+ }, ctx.log);
2432
+ }
2270
2433
  };
2271
2434
  var ctx_default = (options) => {
2272
2435
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
@@ -2288,6 +2451,7 @@ var ctx_default = (options) => {
2288
2451
  try {
2289
2452
  if (options.config) {
2290
2453
  config = JSON.parse(fs5__default.default.readFileSync(options.config, "utf-8"));
2454
+ logger_default.debug(`Config file ${options.config} loaded: ${JSON.stringify(config, null, 2)}`);
2291
2455
  if ((_a = config.web) == null ? void 0 : _a.resolutions) {
2292
2456
  config.web.viewports = config.web.resolutions;
2293
2457
  delete config.web.resolutions;
@@ -2295,6 +2459,8 @@ var ctx_default = (options) => {
2295
2459
  if (!validateConfig(config)) {
2296
2460
  throw new Error(validateConfig.errors[0].message);
2297
2461
  }
2462
+ } else {
2463
+ logger_default.info("## No config file provided. Using default config.");
2298
2464
  }
2299
2465
  port = parseInt(options.port || "49152", 10);
2300
2466
  if (isNaN(port) || port < 1 || port > 65535) {
@@ -2317,6 +2483,10 @@ var ctx_default = (options) => {
2317
2483
  fetchResultsFileObj = "";
2318
2484
  }
2319
2485
  buildNameObj = options.buildName || "";
2486
+ if (options.userName && options.accessKey) {
2487
+ env.LT_USERNAME = options.userName;
2488
+ env.LT_ACCESS_KEY = options.accessKey;
2489
+ }
2320
2490
  } catch (error) {
2321
2491
  console.log(`[smartui] Error: ${error.message}`);
2322
2492
  process.exit();
@@ -2395,7 +2565,9 @@ var ctx_default = (options) => {
2395
2565
  stripExtension: ignoreStripExtension,
2396
2566
  ignorePattern: ignoreFilePattern,
2397
2567
  fetchResults: fetchResultObj,
2398
- fetchResultsFileName: fetchResultsFileObj
2568
+ fetchResultsFileName: fetchResultsFileObj,
2569
+ baselineBranch: options.baselineBranch || "",
2570
+ baselineBuild: options.baselineBuild || ""
2399
2571
  },
2400
2572
  cliVersion: version,
2401
2573
  totalSnapshots: -1,
@@ -2405,13 +2577,21 @@ var ctx_default = (options) => {
2405
2577
  buildToSnapshotCountMap: /* @__PURE__ */ new Map(),
2406
2578
  fetchResultsForBuild: new Array(),
2407
2579
  orgId: 0,
2408
- userId: 0
2580
+ userId: 0,
2581
+ mergeBranchSource: "",
2582
+ mergeBranchTarget: "",
2583
+ mergeBuildSource: "",
2584
+ mergeBuildTarget: "",
2585
+ mergeBuildSourceId: "",
2586
+ mergeBuildTargetId: "",
2587
+ mergeByBranch: false,
2588
+ mergeByBuild: false
2409
2589
  };
2410
2590
  };
2411
- function executeCommand(command7) {
2591
+ function executeCommand(command9) {
2412
2592
  let dst = process.cwd();
2413
2593
  try {
2414
- return child_process.execSync(command7, {
2594
+ return child_process.execSync(command9, {
2415
2595
  cwd: dst,
2416
2596
  stdio: ["ignore"],
2417
2597
  encoding: "utf-8"
@@ -2429,31 +2609,45 @@ function isGitRepo() {
2429
2609
  }
2430
2610
  }
2431
2611
  var git_default = (ctx) => {
2612
+ if (ctx.env.SMART_GIT) {
2613
+ ctx.env.BASELINE_BRANCH = "";
2614
+ if (ctx.options.baselineBranch !== "") {
2615
+ ctx.env.SMART_GIT = false;
2616
+ }
2617
+ }
2432
2618
  if (ctx.env.SMARTUI_GIT_INFO_FILEPATH) {
2433
2619
  let gitInfo = JSON.parse(fs5__default.default.readFileSync(ctx.env.SMARTUI_GIT_INFO_FILEPATH, "utf-8"));
2620
+ if (ctx.options.markBaseline) {
2621
+ ctx.env.BASELINE_BRANCH = ctx.env.CURRENT_BRANCH || gitInfo.branch || "";
2622
+ ctx.env.SMART_GIT = false;
2623
+ }
2434
2624
  return {
2435
2625
  branch: ctx.env.CURRENT_BRANCH || gitInfo.branch || "",
2436
2626
  commitId: gitInfo.commit_id.slice(0, 6) || "",
2437
2627
  commitMessage: gitInfo.commit_body || "",
2438
2628
  commitAuthor: gitInfo.commit_author || "",
2439
2629
  githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${gitInfo.commit_id}` : "",
2440
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
2630
+ baselineBranch: ctx.options.baselineBranch || ctx.env.BASELINE_BRANCH || ""
2441
2631
  };
2442
2632
  } else {
2443
2633
  const splitCharacter = "<##>";
2444
2634
  const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
2445
- const command7 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
2446
- let res = executeCommand(command7).split(splitCharacter);
2635
+ const command9 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
2636
+ let res = executeCommand(command9).split(splitCharacter);
2447
2637
  var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
2448
2638
  var branch = ctx.env.CURRENT_BRANCH || branchAndTags[0];
2449
2639
  branchAndTags.slice(1);
2640
+ if (ctx.options.markBaseline) {
2641
+ ctx.env.BASELINE_BRANCH = branch || "";
2642
+ ctx.env.SMART_GIT = false;
2643
+ }
2450
2644
  return {
2451
2645
  branch: branch || "",
2452
2646
  commitId: res[0] || "",
2453
2647
  commitMessage: res[2] || "",
2454
2648
  commitAuthor: res[7] || "",
2455
2649
  githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${res[1]}` : "",
2456
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
2650
+ baselineBranch: ctx.options.baselineBranch || ctx.env.BASELINE_BRANCH || ""
2457
2651
  };
2458
2652
  }
2459
2653
  };
@@ -2488,14 +2682,21 @@ var createBuildExec_default = (ctx) => {
2488
2682
  updateLogContext({ task: "createBuild" });
2489
2683
  try {
2490
2684
  if (ctx2.authenticatedInitially && !ctx2.config.skipBuildCreation) {
2491
- let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
2492
- ctx2.build = {
2493
- id: resp.data.buildId,
2494
- name: resp.data.buildName,
2495
- url: resp.data.buildURL,
2496
- baseline: resp.data.baseline,
2497
- useKafkaFlow: resp.data.useKafkaFlow || false
2498
- };
2685
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec, ctx2.env.SMART_GIT, ctx2.options.markBaseline, ctx2.options.baselineBuild);
2686
+ if (resp && resp.data && resp.data.buildId) {
2687
+ ctx2.build = {
2688
+ id: resp.data.buildId,
2689
+ name: resp.data.buildName,
2690
+ url: resp.data.buildURL,
2691
+ baseline: resp.data.baseline,
2692
+ useKafkaFlow: resp.data.useKafkaFlow || false
2693
+ };
2694
+ } else if (resp && resp.error) {
2695
+ if (resp.error.message) {
2696
+ ctx2.log.error(`Error while creation of build: ${resp.error.message}`);
2697
+ throw new Error(`Error while creation of build: ${resp.error.message}`);
2698
+ }
2699
+ }
2499
2700
  if (ctx2.build.id === "") {
2500
2701
  ctx2.log.debug("Build creation failed: Build ID is empty");
2501
2702
  task.output = chalk__default.default.red("Build creation failed: Build ID is empty");
@@ -2709,6 +2910,145 @@ var ALLOWED_RESOURCES = ["document", "stylesheet", "image", "media", "font", "ot
2709
2910
  var ALLOWED_STATUSES = [200, 201];
2710
2911
  var REQUEST_TIMEOUT = 18e5;
2711
2912
  var MIN_VIEWPORT_HEIGHT = 1080;
2913
+ function prepareSnapshot(snapshot, ctx) {
2914
+ return __async(this, null, function* () {
2915
+ let processedOptions = {};
2916
+ processedOptions.cliEnableJavascript = ctx.config.cliEnableJavaScript;
2917
+ processedOptions.ignoreHTTPSErrors = ctx.config.ignoreHTTPSErrors;
2918
+ if (ctx.config.basicAuthorization) {
2919
+ processedOptions.basicAuthorization = ctx.config.basicAuthorization;
2920
+ }
2921
+ ctx.config.allowedHostnames.push(new URL(snapshot.url).hostname);
2922
+ processedOptions.allowedHostnames = ctx.config.allowedHostnames;
2923
+ processedOptions.skipCapturedCookies = ctx.env.SMARTUI_DO_NOT_USE_CAPTURED_COOKIES;
2924
+ if (ctx.env.HTTP_PROXY || ctx.env.HTTPS_PROXY)
2925
+ processedOptions.proxy = { server: ctx.env.HTTP_PROXY || ctx.env.HTTPS_PROXY };
2926
+ if (ctx.env.SMARTUI_HTTP_PROXY || ctx.env.SMARTUI_HTTPS_PROXY)
2927
+ processedOptions.proxy = { server: ctx.env.SMARTUI_HTTP_PROXY || ctx.env.SMARTUI_HTTPS_PROXY };
2928
+ let options = snapshot.options;
2929
+ let optionWarnings = /* @__PURE__ */ new Set();
2930
+ let selectors = [];
2931
+ let ignoreOrSelectDOM;
2932
+ if (options && Object.keys(options).length) {
2933
+ ctx.log.debug(`Snapshot options: ${JSON.stringify(options)}`);
2934
+ const isNotAllEmpty = (obj) => {
2935
+ var _a;
2936
+ for (let key in obj)
2937
+ if ((_a = obj[key]) == null ? void 0 : _a.length)
2938
+ return true;
2939
+ return false;
2940
+ };
2941
+ if (options.loadDomContent) {
2942
+ processedOptions.loadDomContent = true;
2943
+ }
2944
+ if (options.sessionId) {
2945
+ const sessionId = options.sessionId;
2946
+ processedOptions.sessionId = sessionId;
2947
+ if (ctx.sessionCapabilitiesMap && ctx.sessionCapabilitiesMap.has(sessionId)) {
2948
+ const sessionCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
2949
+ if (sessionCapabilities && sessionCapabilities.id) {
2950
+ processedOptions.testId = sessionCapabilities.id;
2951
+ }
2952
+ }
2953
+ }
2954
+ if (options.web && Object.keys(options.web).length) {
2955
+ processedOptions.web = {};
2956
+ if (options.web.viewports && options.web.viewports.length > 0) {
2957
+ processedOptions.web.viewports = options.web.viewports.filter(
2958
+ (viewport) => Array.isArray(viewport) && viewport.length > 0
2959
+ );
2960
+ }
2961
+ if (options.web.browsers && options.web.browsers.length > 0) {
2962
+ processedOptions.web.browsers = options.web.browsers;
2963
+ }
2964
+ }
2965
+ if (options.mobile && Object.keys(options.mobile).length) {
2966
+ processedOptions.mobile = {};
2967
+ if (options.mobile.devices && options.mobile.devices.length > 0) {
2968
+ processedOptions.mobile.devices = options.mobile.devices;
2969
+ }
2970
+ if (options.mobile.hasOwnProperty("fullPage") && typeof options.mobile.fullPage === "boolean") {
2971
+ processedOptions.mobile.fullPage = options.mobile.fullPage;
2972
+ } else {
2973
+ processedOptions.mobile.fullPage = true;
2974
+ }
2975
+ if (options.mobile.hasOwnProperty("orientation") && (options.mobile.orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT || options.mobile.orientation === constants_default.MOBILE_ORIENTATION_LANDSCAPE)) {
2976
+ processedOptions.mobile.orientation = options.mobile.orientation;
2977
+ } else {
2978
+ processedOptions.mobile.orientation = constants_default.MOBILE_ORIENTATION_PORTRAIT;
2979
+ }
2980
+ }
2981
+ if (options.element && Object.keys(options.element).length) {
2982
+ if (options.element.id)
2983
+ processedOptions.element = "#" + options.element.id;
2984
+ else if (options.element.class)
2985
+ processedOptions.element = "." + options.element.class;
2986
+ else if (options.element.cssSelector)
2987
+ processedOptions.element = options.element.cssSelector;
2988
+ else if (options.element.xpath)
2989
+ processedOptions.element = "xpath=" + options.element.xpath;
2990
+ } else if (options.ignoreDOM && Object.keys(options.ignoreDOM).length && isNotAllEmpty(options.ignoreDOM)) {
2991
+ processedOptions.ignoreBoxes = {};
2992
+ ignoreOrSelectDOM = "ignoreDOM";
2993
+ } else if (options.selectDOM && Object.keys(options.selectDOM).length && isNotAllEmpty(options.selectDOM)) {
2994
+ processedOptions.selectBoxes = {};
2995
+ ignoreOrSelectDOM = "selectDOM";
2996
+ }
2997
+ if (ignoreOrSelectDOM) {
2998
+ for (const [key, value] of Object.entries(options[ignoreOrSelectDOM])) {
2999
+ switch (key) {
3000
+ case "id":
3001
+ selectors.push(...value.map((e) => "#" + e));
3002
+ break;
3003
+ case "class":
3004
+ selectors.push(...value.map((e) => "." + e));
3005
+ break;
3006
+ case "xpath":
3007
+ selectors.push(...value.map((e) => "xpath=" + e));
3008
+ break;
3009
+ case "cssSelector":
3010
+ selectors.push(...value);
3011
+ break;
3012
+ }
3013
+ }
3014
+ }
3015
+ if (options.ignoreType) {
3016
+ processedOptions.ignoreType = options.ignoreType;
3017
+ }
3018
+ }
3019
+ if (ctx.config.tunnel) {
3020
+ if (ctx.tunnelDetails && ctx.tunnelDetails.tunnelPort != -1 && ctx.tunnelDetails.tunnelHost != "") {
3021
+ const tunnelAddress = `http://${ctx.tunnelDetails.tunnelHost}:${ctx.tunnelDetails.tunnelPort}`;
3022
+ processedOptions.tunnelAddress = tunnelAddress;
3023
+ ctx.log.debug(`Tunnel address added to processedOptions: ${tunnelAddress}`);
3024
+ }
3025
+ }
3026
+ processedOptions.allowedAssets = ctx.config.allowedAssets;
3027
+ processedOptions.selectors = selectors;
3028
+ processedOptions.ignoreDOM = options == null ? void 0 : options.ignoreDOM;
3029
+ processedOptions.selectDOM = options == null ? void 0 : options.selectDOM;
3030
+ ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
3031
+ let renderViewports;
3032
+ if (snapshot.options && snapshot.options.web || snapshot.options && snapshot.options.mobile) {
3033
+ renderViewports = getRenderViewportsForOptions(snapshot.options);
3034
+ } else {
3035
+ renderViewports = getRenderViewports(ctx);
3036
+ }
3037
+ processedOptions.doRemoteDiscovery = true;
3038
+ return {
3039
+ processedSnapshot: {
3040
+ name: snapshot.name,
3041
+ url: snapshot.url,
3042
+ dom: Buffer.from(snapshot.dom.html).toString("base64"),
3043
+ resources: {},
3044
+ options: processedOptions,
3045
+ cookies: Buffer.from(snapshot.dom.cookies).toString("base64"),
3046
+ renderViewports
3047
+ },
3048
+ warnings: [...optionWarnings, ...snapshot.dom.warnings]
3049
+ };
3050
+ });
3051
+ }
2712
3052
  function processSnapshot(snapshot, ctx) {
2713
3053
  return __async(this, null, function* () {
2714
3054
  var _a, _b;
@@ -2722,6 +3062,7 @@ function processSnapshot(snapshot, ctx) {
2722
3062
  snapshotUUID: "",
2723
3063
  browsers: {}
2724
3064
  };
3065
+ let processedOptions = {};
2725
3066
  let globalViewport = "";
2726
3067
  let globalBrowser = constants_default.CHROME;
2727
3068
  let launchOptions = {
@@ -2913,7 +3254,6 @@ function processSnapshot(snapshot, ctx) {
2913
3254
  }));
2914
3255
  let options = snapshot.options;
2915
3256
  let optionWarnings = /* @__PURE__ */ new Set();
2916
- let processedOptions = {};
2917
3257
  let selectors = [];
2918
3258
  let ignoreOrSelectDOM;
2919
3259
  let ignoreOrSelectBoxes;
@@ -3458,7 +3798,19 @@ var Queue = class {
3458
3798
  useCapsBuildId = true;
3459
3799
  }
3460
3800
  }
3461
- let { processedSnapshot, warnings, discoveryErrors } = yield processSnapshot(snapshot, this.ctx);
3801
+ let processedSnapshot, warnings, discoveryErrors;
3802
+ if (this.ctx.env.USE_REMOTE_DISCOVERY) {
3803
+ this.ctx.log.debug(`Using remote discovery`);
3804
+ let result = yield prepareSnapshot(snapshot, this.ctx);
3805
+ processedSnapshot = result.processedSnapshot;
3806
+ warnings = result.warnings;
3807
+ } else {
3808
+ this.ctx.log.debug(`Using local discovery`);
3809
+ let result = yield processSnapshot(snapshot, this.ctx);
3810
+ processedSnapshot = result.processedSnapshot;
3811
+ warnings = result.warnings;
3812
+ discoveryErrors = result.discoveryErrors;
3813
+ }
3462
3814
  if (useCapsBuildId) {
3463
3815
  if (useKafkaFlowCaps) {
3464
3816
  const snapshotUuid = uuid.v4();
@@ -3476,7 +3828,7 @@ var Queue = class {
3476
3828
  } else {
3477
3829
  if (!((_c = this.ctx.build) == null ? void 0 : _c.id)) {
3478
3830
  if (this.ctx.authenticatedInitially) {
3479
- let resp = yield this.ctx.client.createBuild(this.ctx.git, this.ctx.config, this.ctx.log, this.ctx.build.name);
3831
+ let resp = yield this.ctx.client.createBuild(this.ctx.git, this.ctx.config, this.ctx.log, this.ctx.build.name, false, false, false, "");
3480
3832
  this.ctx.build = {
3481
3833
  id: resp.data.buildId,
3482
3834
  name: resp.data.buildName,
@@ -3580,15 +3932,15 @@ var startTunnel_default = (ctx) => {
3580
3932
 
3581
3933
  // src/commander/exec.ts
3582
3934
  var command = new commander.Command();
3583
- command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").option("-P, --port <number>", "Port number for the server").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(execCommand, _, command7) {
3935
+ command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").option("-P, --port <number>", "Port number for the server").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(execCommand, _, command9) {
3584
3936
  return __async(this, null, function* () {
3585
3937
  var _a;
3586
- const options = command7.optsWithGlobals();
3938
+ const options = command9.optsWithGlobals();
3587
3939
  if (options.buildName === "") {
3588
3940
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
3589
3941
  process.exit(1);
3590
3942
  }
3591
- let ctx = ctx_default(command7.optsWithGlobals());
3943
+ let ctx = ctx_default(command9.optsWithGlobals());
3592
3944
  if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
3593
3945
  ctx.log.error(`Error: Command not found "${execCommand[0]}"`);
3594
3946
  return;
@@ -3692,7 +4044,7 @@ function createWebFigmaConfig(filepath) {
3692
4044
  console.log(`Created figma web config: ${filepath}`);
3693
4045
  }
3694
4046
  function verifyFigmaWebConfig(ctx) {
3695
- var _a;
4047
+ var _a, _b;
3696
4048
  if (ctx.env.FIGMA_TOKEN == "") {
3697
4049
  throw new Error("Missing FIGMA_TOKEN in Environment Variables");
3698
4050
  }
@@ -3717,17 +4069,44 @@ function verifyFigmaWebConfig(ctx) {
3717
4069
  if (new Set(screenshots).size !== screenshots.length) {
3718
4070
  throw new Error("Found duplicate screenshot names in figma config");
3719
4071
  }
3720
- return true;
4072
+ let mobileConfig = ((_b = ctx.config) == null ? void 0 : _b.mobile) || {};
4073
+ if (Array.isArray(mobileConfig)) {
4074
+ for (const config of mobileConfig) {
4075
+ const deviceName = config.name;
4076
+ if (constants_default.SUPPORTED_MOBILE_DEVICES[deviceName]) {
4077
+ const deviceData = constants_default.SUPPORTED_MOBILE_DEVICES[deviceName];
4078
+ config.width = deviceData.viewport.width;
4079
+ config.height = deviceData.viewport.height;
4080
+ }
4081
+ }
4082
+ }
3721
4083
  }
3722
4084
  function isValidArray(input) {
3723
4085
  return Array.isArray(input) && input.length > 0;
3724
4086
  }
4087
+ function createAppFigmaConfig(filepath) {
4088
+ filepath = filepath || ".smartui.json";
4089
+ let filetype = path2__default.default.extname(filepath);
4090
+ if (filetype != ".json") {
4091
+ console.log("Error: figma app config file must have .json extension");
4092
+ return;
4093
+ }
4094
+ if (fs5__default.default.existsSync(filepath)) {
4095
+ console.log(`Error: figma app config already exists: ${filepath}`);
4096
+ console.log(`To create a new figma app config, please specify the file name like: 'smartui config:create-figma-app <fileName>.json'`);
4097
+ return;
4098
+ }
4099
+ fs5__default.default.mkdirSync(path2__default.default.dirname(filepath), { recursive: true });
4100
+ fs5__default.default.writeFileSync(filepath, JSON.stringify(constants_default.APP_FIGMA_CONFIG, null, 2) + "\n");
4101
+ console.log(`Created figma app config: ${filepath}`);
4102
+ }
3725
4103
 
3726
4104
  // src/commander/config.ts
3727
4105
  var configWeb = new commander.Command();
3728
4106
  var configStatic = new commander.Command();
3729
4107
  var configFigma = new commander.Command();
3730
4108
  var configWebFigma = new commander.Command();
4109
+ var configAppFigma = new commander.Command();
3731
4110
  configWeb.name("config:create").description("Create SmartUI config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
3732
4111
  return __async(this, null, function* () {
3733
4112
  createConfig(filepath);
@@ -3748,6 +4127,11 @@ configWebFigma.name("config:create-figma-web").description("Create figma config
3748
4127
  createWebFigmaConfig(filepath);
3749
4128
  });
3750
4129
  });
4130
+ configAppFigma.name("config:create-figma-app").description("Create figma config file for mobile apps").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
4131
+ return __async(this, null, function* () {
4132
+ createAppFigmaConfig(filepath);
4133
+ });
4134
+ });
3751
4135
  var auth_default = (ctx) => {
3752
4136
  return {
3753
4137
  title: `Authenticating with SmartUI`,
@@ -3778,14 +4162,21 @@ var createBuild_default = (ctx) => {
3778
4162
  task: (ctx2, task) => __async(void 0, null, function* () {
3779
4163
  updateLogContext({ task: "createBuild" });
3780
4164
  try {
3781
- let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
3782
- ctx2.build = {
3783
- id: resp.data.buildId,
3784
- name: resp.data.buildName,
3785
- url: resp.data.buildURL,
3786
- baseline: resp.data.baseline,
3787
- useKafkaFlow: resp.data.useKafkaFlow || false
3788
- };
4165
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec, ctx2.env.SMART_GIT, ctx2.options.markBaseline, ctx2.options.baselineBuild);
4166
+ if (resp && resp.data && resp.data.buildId) {
4167
+ ctx2.build = {
4168
+ id: resp.data.buildId,
4169
+ name: resp.data.buildName,
4170
+ url: resp.data.buildURL,
4171
+ baseline: resp.data.baseline,
4172
+ useKafkaFlow: resp.data.useKafkaFlow || false
4173
+ };
4174
+ } else if (resp && resp.error) {
4175
+ if (resp.error.message) {
4176
+ ctx2.log.error(`Error while creation of build: ${resp.error.message}`);
4177
+ throw new Error(`Error while creation of build: ${resp.error.message}`);
4178
+ }
4179
+ }
3789
4180
  task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
3790
4181
  task.title = "SmartUI build created";
3791
4182
  } catch (error) {
@@ -4162,15 +4553,15 @@ var captureScreenshots_default = (ctx) => {
4162
4553
 
4163
4554
  // src/commander/capture.ts
4164
4555
  var command2 = new commander.Command();
4165
- command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("-C, --parallel [number]", "Specify the number of instances per browser", parseInt).option("-F, --force", "forcefully apply the specified parallel instances per browser").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(file, _, command7) {
4556
+ command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("-C, --parallel [number]", "Specify the number of instances per browser", parseInt).option("-F, --force", "forcefully apply the specified parallel instances per browser").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(file, _, command9) {
4166
4557
  return __async(this, null, function* () {
4167
4558
  var _a, _b;
4168
- const options = command7.optsWithGlobals();
4559
+ const options = command9.optsWithGlobals();
4169
4560
  if (options.buildName === "") {
4170
4561
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
4171
4562
  process.exit(1);
4172
4563
  }
4173
- let ctx = ctx_default(command7.optsWithGlobals());
4564
+ let ctx = ctx_default(command9.optsWithGlobals());
4174
4565
  ctx.isSnapshotCaptured = true;
4175
4566
  if (!fs5__default.default.existsSync(file)) {
4176
4567
  ctx.log.error(`Web Static Config file ${file} not found.`);
@@ -4255,14 +4646,14 @@ command3.name("upload").description("Upload screenshots from given directory").a
4255
4646
  return val.split(",").map((ext) => ext.trim().toLowerCase());
4256
4647
  }).option("-E, --removeExtensions", "Strips file extensions from snapshot names").option("-i, --ignoreDir <patterns>", "Comma-separated list of directories to ignore", (val) => {
4257
4648
  return val.split(",").map((pattern) => pattern.trim());
4258
- }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(directory, _, command7) {
4649
+ }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(directory, _, command9) {
4259
4650
  return __async(this, null, function* () {
4260
- const options = command7.optsWithGlobals();
4651
+ const options = command9.optsWithGlobals();
4261
4652
  if (options.buildName === "") {
4262
4653
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
4263
4654
  process.exit(1);
4264
4655
  }
4265
- let ctx = ctx_default(command7.optsWithGlobals());
4656
+ let ctx = ctx_default(command9.optsWithGlobals());
4266
4657
  ctx.isSnapshotCaptured = true;
4267
4658
  if (!fs5__default.default.existsSync(directory)) {
4268
4659
  console.log(`Error: The provided directory ${directory} not found.`);
@@ -4463,12 +4854,86 @@ var uploadWebFigma_default2 = (ctx) => {
4463
4854
  exitOnError: true
4464
4855
  };
4465
4856
  };
4857
+
4858
+ // src/lib/uploadAppFigma.ts
4859
+ var uploadAppFigma_default = (ctx) => __async(void 0, null, function* () {
4860
+ var _a, _b;
4861
+ const figmaConfig = ctx.config && ((_a = ctx.config) == null ? void 0 : _a.figma) || {};
4862
+ const mobileConfig = ctx.config && ((_b = ctx.config) == null ? void 0 : _b.mobile) || {};
4863
+ let results = "";
4864
+ const buildName = ctx.options.buildName;
4865
+ if (figmaConfig && figmaConfig.configs && figmaConfig.configs.length > 0) {
4866
+ const authToken = `Basic ${Buffer.from(`${ctx.env.LT_USERNAME}:${ctx.env.LT_ACCESS_KEY}`).toString("base64")}`;
4867
+ const requestBody = {
4868
+ figma_token: ctx.env.FIGMA_TOKEN,
4869
+ auth: authToken,
4870
+ build_name: buildName,
4871
+ mobile: mobileConfig,
4872
+ figma: figmaConfig,
4873
+ smartIgnore: ctx.config.smartIgnore,
4874
+ git: ctx.git,
4875
+ platformType: "app"
4876
+ };
4877
+ const responseData = yield ctx.client.processWebFigma(requestBody, ctx.log);
4878
+ ctx.log.debug("responseData : " + JSON.stringify(responseData));
4879
+ if (responseData && responseData.error && responseData.error.message) {
4880
+ throw new Error(responseData.error.message);
4881
+ }
4882
+ if (responseData.data.message == "success") {
4883
+ results = responseData.data.message;
4884
+ ctx.build = {
4885
+ id: responseData.data.buildId,
4886
+ url: responseData.data.buildURL || "https://smartui.lambdatestinternal.com",
4887
+ baseline: responseData.data.baseline ? responseData.data.baseline : false
4888
+ };
4889
+ }
4890
+ } else {
4891
+ throw new Error("No Figma configuration found in config file");
4892
+ }
4893
+ return results;
4894
+ });
4895
+
4896
+ // src/tasks/uploadAppFigma.ts
4897
+ var uploadAppFigma_default2 = (ctx) => {
4898
+ return {
4899
+ title: "Processing App Figma",
4900
+ task: (ctx2, task) => __async(void 0, null, function* () {
4901
+ try {
4902
+ ctx2.task = task;
4903
+ updateLogContext({ task: "upload-figma-app" });
4904
+ let results = yield uploadAppFigma_default(ctx2);
4905
+ if (results != "success") {
4906
+ throw new Error("Uploading App Figma Screenshot failed");
4907
+ }
4908
+ if (ctx2.build.id) {
4909
+ task.output = chalk__default.default.gray(`Build Id: ${ctx2.build.id}`);
4910
+ let figmaOutput = yield fetchFigma_default(ctx2);
4911
+ const jsonObject = JSON.parse(figmaOutput);
4912
+ let output = JSON.stringify(jsonObject, null, 2);
4913
+ task.output = task.output + "\n" + chalk__default.default.green(`${output}`);
4914
+ }
4915
+ if (ctx2.options.fetchResults) {
4916
+ startPolling(ctx2, "", false, "");
4917
+ }
4918
+ task.title = "App Figma images uploaded successfully to SmartUI";
4919
+ ctx2.log.debug(`App Figma processed: ${results}`);
4920
+ } catch (error) {
4921
+ ctx2.log.debug(error);
4922
+ task.output = chalk__default.default.gray(`${error.message}`);
4923
+ throw new Error("Uploading App Figma Screenshots failed");
4924
+ }
4925
+ }),
4926
+ rendererOptions: { persistentOutput: true },
4927
+ exitOnError: true
4928
+ };
4929
+ };
4466
4930
  var uploadFigma = new commander.Command();
4467
4931
  var uploadWebFigmaCommand = new commander.Command();
4468
- uploadFigma.name("upload-figma").description("Capture screenshots of static sites").argument("<file>", "figma design config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command7) {
4932
+ var uploadAppFigmaCommand = new commander.Command();
4933
+ uploadFigma.name("upload-figma").description("Capture screenshots of static sites").argument("<file>", "figma design config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command9) {
4469
4934
  return __async(this, null, function* () {
4470
4935
  var _a, _b;
4471
- let ctx = ctx_default(command7.optsWithGlobals());
4936
+ let ctx = ctx_default(command9.optsWithGlobals());
4472
4937
  ctx.isSnapshotCaptured = true;
4473
4938
  if (!fs5__default.default.existsSync(file)) {
4474
4939
  console.log(`Error: Figma Config file ${file} not found.`);
@@ -4507,10 +4972,10 @@ uploadFigma.name("upload-figma").description("Capture screenshots of static site
4507
4972
  }
4508
4973
  });
4509
4974
  });
4510
- uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots of static sites").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command7) {
4975
+ uploadWebFigmaCommand.name("upload-figma-web").description("Capture figma screenshots into CLI build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command9) {
4511
4976
  return __async(this, null, function* () {
4512
4977
  var _a;
4513
- let ctx = ctx_default(command7.optsWithGlobals());
4978
+ let ctx = ctx_default(command9.optsWithGlobals());
4514
4979
  if (!fs5__default.default.existsSync(file)) {
4515
4980
  console.log(`Error: figma-web config file ${file} not found.`);
4516
4981
  return;
@@ -4559,6 +5024,58 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots
4559
5024
  }
4560
5025
  });
4561
5026
  });
5027
+ uploadAppFigmaCommand.name("upload-figma-app").description("Capture figma screenshots into App Build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command9) {
5028
+ return __async(this, null, function* () {
5029
+ var _a;
5030
+ let ctx = ctx_default(command9.optsWithGlobals());
5031
+ if (!fs5__default.default.existsSync(file)) {
5032
+ console.log(`Error: figma-app config file ${file} not found.`);
5033
+ return;
5034
+ }
5035
+ try {
5036
+ ctx.config = JSON.parse(fs5__default.default.readFileSync(file, "utf8"));
5037
+ ctx.log.info(JSON.stringify(ctx.config));
5038
+ if (!validateAppFigmaConfig(ctx.config)) {
5039
+ ctx.log.debug(JSON.stringify(validateAppFigmaConfig.errors, null, 2));
5040
+ (_a = validateAppFigmaConfig.errors) == null ? void 0 : _a.forEach((error) => {
5041
+ if (error.keyword === "additionalProperties") {
5042
+ ctx.log.warn(`Additional property "${error.params.additionalProperty}" is not allowed.`);
5043
+ } else {
5044
+ const validationError = error.message;
5045
+ throw new Error(validationError || "Invalid figma-app config found in file : " + file);
5046
+ }
5047
+ });
5048
+ }
5049
+ verifyFigmaWebConfig(ctx);
5050
+ } catch (error) {
5051
+ ctx.log.error(chalk__default.default.red(`Invalid figma-app config; ${error.message}`));
5052
+ return;
5053
+ }
5054
+ let tasks = new listr2.Listr(
5055
+ [
5056
+ auth_default(),
5057
+ getGitInfo_default(),
5058
+ uploadAppFigma_default2(),
5059
+ finalizeBuild_default()
5060
+ ],
5061
+ {
5062
+ rendererOptions: {
5063
+ icon: {
5064
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: `\u2192`
5065
+ },
5066
+ color: {
5067
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
5068
+ }
5069
+ }
5070
+ }
5071
+ );
5072
+ try {
5073
+ yield tasks.run(ctx);
5074
+ } catch (error) {
5075
+ console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
5076
+ }
5077
+ });
5078
+ });
4562
5079
  var command4 = new commander.Command();
4563
5080
  command4.name("exec:start").description("Start SmartUI server").option("-P, --port <number>", "Port number for the server").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function() {
4564
5081
  return __async(this, null, function* () {
@@ -4661,11 +5178,234 @@ command6.name("exec:ping").description("Ping the SmartUI server to check if it i
4661
5178
  });
4662
5179
  });
4663
5180
  var ping_default = command6;
5181
+ var fetchBranchInfo_default = (ctx) => {
5182
+ return {
5183
+ title: `Fetching branch info`,
5184
+ task: (ctx2, task) => __async(void 0, null, function* () {
5185
+ updateLogContext({ task: "fetchBranchInfo" });
5186
+ try {
5187
+ if (ctx2.mergeBranchSource === ctx2.mergeBranchTarget) {
5188
+ ctx2.log.error(`Merging two similar branch is not possible`);
5189
+ throw new Error(`Merging two similar branch is not possible`);
5190
+ }
5191
+ const requestData = {
5192
+ source: ctx2.mergeBranchSource,
5193
+ target: ctx2.mergeBranchTarget,
5194
+ byBranch: ctx2.mergeByBranch,
5195
+ byBuild: ctx2.mergeByBuild
5196
+ };
5197
+ let resp = yield ctx2.client.fetchBuildInfo(requestData, ctx2);
5198
+ if (resp && resp.data && resp.data.source && resp.data.target) {
5199
+ ctx2.mergeBuildSourceId = resp.data.source;
5200
+ ctx2.mergeBuildTargetId = resp.data.target;
5201
+ ctx2.log.debug(`Merge Build source buildId: ${ctx2.mergeBuildSourceId} and target buildId: ${ctx2.mergeBuildTargetId}`);
5202
+ } else if (resp && resp.error) {
5203
+ if (resp.error.message) {
5204
+ ctx2.log.error(`Error while fetching branch Info: ${resp.error.message}`);
5205
+ throw new Error(`Error while fetching branch Info: ${resp.error.message}`);
5206
+ }
5207
+ }
5208
+ task.title = "Branch info fetched";
5209
+ task.output = chalk__default.default.gray(`Source buildId: ${ctx2.mergeBuildSourceId} and Target buildId: ${ctx2.mergeBuildTargetId}`);
5210
+ } catch (error) {
5211
+ ctx2.log.debug(error);
5212
+ task.output = chalk__default.default.gray(error.message);
5213
+ throw new Error("Branch info fetching failed");
5214
+ }
5215
+ }),
5216
+ rendererOptions: { persistentOutput: true }
5217
+ };
5218
+ };
5219
+ var mergeBuilds_default = (ctx) => {
5220
+ return {
5221
+ title: `Merging smartui builds`,
5222
+ task: (ctx2, task) => __async(void 0, null, function* () {
5223
+ updateLogContext({ task: "mergeBuilds" });
5224
+ try {
5225
+ let resp;
5226
+ if (ctx2.mergeByBranch) {
5227
+ ctx2.git.branch = ctx2.mergeBranchTarget;
5228
+ const requestData = {
5229
+ source: ctx2.mergeBuildSourceId,
5230
+ target: ctx2.mergeBuildTargetId,
5231
+ byBranch: ctx2.mergeByBranch,
5232
+ byBuildName: ctx2.mergeByBuild,
5233
+ sourceBranchName: ctx2.mergeBranchSource,
5234
+ targetBranchName: ctx2.mergeBranchTarget,
5235
+ sourceBuildName: "",
5236
+ targetBuildName: "",
5237
+ git: ctx2.git
5238
+ };
5239
+ resp = yield ctx2.client.mergeBuildsByBuildId(requestData, ctx2);
5240
+ } else {
5241
+ const requestData = {
5242
+ source: ctx2.mergeBuildSourceId,
5243
+ target: ctx2.mergeBuildTargetId,
5244
+ byBranch: ctx2.mergeByBranch,
5245
+ byBuildName: ctx2.mergeByBuild,
5246
+ sourceBranchName: "",
5247
+ targetBranchName: "",
5248
+ sourceBuildName: ctx2.mergeBuildSource,
5249
+ targetBuildName: ctx2.mergeBuildTarget,
5250
+ git: ctx2.git
5251
+ };
5252
+ resp = yield ctx2.client.mergeBuildsByBuildId(requestData, ctx2);
5253
+ }
5254
+ if (resp && resp.data && resp.data.message) {
5255
+ ctx2.log.debug(`${resp.data.message}`);
5256
+ } else {
5257
+ ctx2.log.error(`Error while initiating merging process: ${resp.error.message}`);
5258
+ throw new Error(`Error while initiating merging process: ${resp.error.message}`);
5259
+ }
5260
+ task.title = "Merging SmartUI builds initiated";
5261
+ task.output = chalk__default.default.gray(`${resp.data.message}`);
5262
+ } catch (error) {
5263
+ ctx2.log.debug(error);
5264
+ task.output = chalk__default.default.gray(error.message);
5265
+ throw new Error("Merging SmartUI build failed");
5266
+ }
5267
+ }),
5268
+ rendererOptions: { persistentOutput: true }
5269
+ };
5270
+ };
4664
5271
 
4665
- // src/commander/commander.ts
5272
+ // src/commander/mergeBranch.ts
5273
+ var command7 = new commander.Command();
5274
+ command7.name("branch").description("Merge a source branch into the target branch").requiredOption("--source <string>", "Source branch to merge").requiredOption("--target <string>", "Target branch to merge into").action(function(options) {
5275
+ return __async(this, null, function* () {
5276
+ const { source, target } = options;
5277
+ let ctx = ctx_default(command7.optsWithGlobals());
5278
+ if (!source || source.trim() === "") {
5279
+ ctx.log.error("Error: The --source option cannot be empty.");
5280
+ process.exit(1);
5281
+ }
5282
+ if (!target || target.trim() === "") {
5283
+ ctx.log.error("Error: The --target option cannot be empty.");
5284
+ process.exit(1);
5285
+ }
5286
+ ctx.log.debug(`Merging source branch '${source}' into branch branch '${target}'`);
5287
+ ctx.mergeBranchSource = source;
5288
+ ctx.mergeBranchTarget = target;
5289
+ ctx.mergeByBranch = true;
5290
+ let tasks = new listr2.Listr(
5291
+ [
5292
+ auth_default(),
5293
+ getGitInfo_default(),
5294
+ fetchBranchInfo_default(),
5295
+ mergeBuilds_default()
5296
+ ],
5297
+ {
5298
+ rendererOptions: {
5299
+ icon: {
5300
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: "\u2192"
5301
+ },
5302
+ color: {
5303
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
5304
+ }
5305
+ }
5306
+ }
5307
+ );
5308
+ try {
5309
+ yield tasks.run(ctx);
5310
+ } catch (error) {
5311
+ console.error("Error during merge operation:", error);
5312
+ }
5313
+ });
5314
+ });
5315
+ var mergeBranch_default = command7;
5316
+ var fetchBuildInfo_default = (ctx) => {
5317
+ return {
5318
+ title: `Fetching build info`,
5319
+ task: (ctx2, task) => __async(void 0, null, function* () {
5320
+ updateLogContext({ task: "fetchBuildInfo" });
5321
+ try {
5322
+ if (ctx2.mergeBuildSource === ctx2.mergeBuildTarget) {
5323
+ ctx2.log.error(`Merging two similar build is not possible`);
5324
+ throw new Error(`Merging two similar build is not possible`);
5325
+ }
5326
+ const requestData = {
5327
+ source: ctx2.mergeBuildSource,
5328
+ target: ctx2.mergeBuildTarget,
5329
+ byBranch: ctx2.mergeByBranch,
5330
+ byBuildName: ctx2.mergeByBuild
5331
+ };
5332
+ let resp = yield ctx2.client.fetchBuildInfo(requestData, ctx2);
5333
+ if (resp && resp.data && resp.data.source && resp.data.target) {
5334
+ ctx2.mergeBuildSourceId = resp.data.source;
5335
+ ctx2.mergeBuildTargetId = resp.data.target;
5336
+ ctx2.log.debug(`Merge Build source buildId: ${ctx2.mergeBuildSourceId} and target buildId: ${ctx2.mergeBuildTargetId}`);
5337
+ } else if (resp && resp.error) {
5338
+ if (resp.error.message) {
5339
+ ctx2.log.error(`Error while fetching buildInfo: ${resp.error.message}`);
5340
+ throw new Error(`Error while fetching buildInfo: ${resp.error.message}`);
5341
+ }
5342
+ }
5343
+ task.title = "Build info fetched";
5344
+ task.output = chalk__default.default.gray(`Source buildId: ${ctx2.mergeBuildSourceId} and Target buildId: ${ctx2.mergeBuildTargetId}`);
5345
+ } catch (error) {
5346
+ ctx2.log.debug(error);
5347
+ task.output = chalk__default.default.gray(error.message);
5348
+ throw new Error("Build info fetching failed");
5349
+ }
5350
+ }),
5351
+ rendererOptions: { persistentOutput: true }
5352
+ };
5353
+ };
5354
+
5355
+ // src/commander/mergeBuild.ts
5356
+ var command8 = new commander.Command();
5357
+ command8.name("build").description("Merge a source build into the target build").requiredOption("--source <string>", "Source build to merge").requiredOption("--target <string>", "Target build to merge into").action(function(options) {
5358
+ return __async(this, null, function* () {
5359
+ const { source, target } = options;
5360
+ let ctx = ctx_default(command8.optsWithGlobals());
5361
+ if (!source || source.trim() === "") {
5362
+ ctx.log.error("Error: The --source option cannot be empty.");
5363
+ process.exit(1);
5364
+ }
5365
+ if (!target || target.trim() === "") {
5366
+ ctx.log.error("Error: The --target option cannot be empty.");
5367
+ process.exit(1);
5368
+ }
5369
+ ctx.log.debug(`Merging source build '${source}' into target build '${target}'`);
5370
+ ctx.mergeBuildSource = source;
5371
+ ctx.mergeBuildTarget = target;
5372
+ ctx.mergeByBuild = true;
5373
+ let tasks = new listr2.Listr(
5374
+ [
5375
+ auth_default(),
5376
+ getGitInfo_default(),
5377
+ fetchBuildInfo_default(),
5378
+ mergeBuilds_default()
5379
+ ],
5380
+ {
5381
+ rendererOptions: {
5382
+ icon: {
5383
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: "\u2192"
5384
+ },
5385
+ color: {
5386
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
5387
+ }
5388
+ }
5389
+ }
5390
+ );
5391
+ try {
5392
+ yield tasks.run(ctx);
5393
+ } catch (error) {
5394
+ console.error("Error during merge operation:", error);
5395
+ }
5396
+ });
5397
+ });
5398
+ var mergeBuild_default = command8;
5399
+
5400
+ // src/commander/merge.ts
4666
5401
  var program = new commander.Command();
4667
- program.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(server_default2).addCommand(stopServer_default).addCommand(ping_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(uploadWebFigmaCommand);
4668
- var commander_default = program;
5402
+ program.name("merge").description("Merge a source branch into the target branch").addCommand(mergeBranch_default).addCommand(mergeBuild_default);
5403
+ var merge_default = program;
5404
+
5405
+ // src/commander/commander.ts
5406
+ var program2 = new commander.Command();
5407
+ program2.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").option("--markBaseline", "Mark this build baseline").option("--baselineBranch <string>", "Mark this build baseline").option("--baselineBuild <string>", "Mark this build baseline").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(server_default2).addCommand(stopServer_default).addCommand(merge_default).addCommand(ping_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(configAppFigma).addCommand(uploadWebFigmaCommand).addCommand(uploadAppFigmaCommand);
5408
+ var commander_default = program2;
4669
5409
  (function() {
4670
5410
  return __async(this, null, function* () {
4671
5411
  let client = new httpClient(env_default());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.11-beta.0",
3
+ "version": "4.1.12",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"