@lambdatest/smartui-cli 4.1.31 → 4.1.33

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 +228 -83
  2. package/package.json +4 -1
package/dist/index.cjs CHANGED
@@ -11,7 +11,7 @@ var fs5 = require('fs');
11
11
  var Ajv = require('ajv');
12
12
  var addErrors = require('ajv-errors');
13
13
  var test = require('@playwright/test');
14
- var util = require('util');
14
+ var util$1 = require('util');
15
15
  var winston = require('winston');
16
16
  var stringify = require('json-stringify-safe');
17
17
  var FormData = require('form-data');
@@ -751,6 +751,11 @@ var ConfigSchema = {
751
751
  logFile: {
752
752
  type: "string",
753
753
  errorMessage: "Invalid config; logFile should be a string value"
754
+ },
755
+ environment: {
756
+ type: "string",
757
+ enum: ["stage", "prod"],
758
+ errorMessage: "Invalid config; environment should be a string value either stage or prod"
754
759
  }
755
760
  },
756
761
  required: ["type"],
@@ -787,6 +792,18 @@ var ConfigSchema = {
787
792
  loadDomContent: {
788
793
  type: "boolean",
789
794
  errorMessage: "Invalid config; loadDomContent must be true/false"
795
+ },
796
+ approvalThreshold: {
797
+ type: "number",
798
+ minimum: 0,
799
+ maximum: 100,
800
+ errorMessage: "Invalid config; approvalThreshold must be a number"
801
+ },
802
+ rejectionThreshold: {
803
+ type: "number",
804
+ minimum: 0,
805
+ maximum: 100,
806
+ errorMessage: "Invalid config; rejectionThreshold must be a number"
790
807
  }
791
808
  },
792
809
  anyOf: [
@@ -836,6 +853,18 @@ var WebStaticConfigSchema = {
836
853
  type: "string",
837
854
  enum: ["load", "domcontentloaded"],
838
855
  errorMessage: "pageEvent can be load, domcontentloaded"
856
+ },
857
+ requestHeaders: {
858
+ type: "array",
859
+ items: {
860
+ type: "object",
861
+ minProperties: 1,
862
+ additionalProperties: { type: "string" }
863
+ },
864
+ uniqueItems: true,
865
+ errorMessage: {
866
+ uniqueItems: "Invalid config; duplicates in requestHeaders"
867
+ }
839
868
  }
840
869
  },
841
870
  required: ["name", "url"],
@@ -1048,6 +1077,18 @@ var SnapshotSchema = {
1048
1077
  useExtendedViewport: {
1049
1078
  type: "boolean",
1050
1079
  errorMessage: "Invalid snapshot options; useExtendedViewport must be a boolean"
1080
+ },
1081
+ approvalThreshold: {
1082
+ type: "number",
1083
+ minimum: 0,
1084
+ maximum: 100,
1085
+ errorMessage: "Invalid snapshot options; approvalThreshold must be a number between 0 and 100"
1086
+ },
1087
+ rejectionThreshold: {
1088
+ type: "number",
1089
+ minimum: 0,
1090
+ maximum: 100,
1091
+ errorMessage: "Invalid snapshot options; rejectionThreshold must be a number between 0 and 100"
1051
1092
  }
1052
1093
  },
1053
1094
  additionalProperties: false
@@ -1335,8 +1376,9 @@ var validateConfigForScheduled = (config) => {
1335
1376
  return true;
1336
1377
  };
1337
1378
  validateConfigForScheduled.errors = null;
1379
+ var util = __require("util");
1338
1380
  var lambdaTunnel = __require("@lambdatest/node-tunnel");
1339
- util.promisify(setTimeout);
1381
+ util$1.promisify(setTimeout);
1340
1382
  var tunnelInstance;
1341
1383
  function delDir(dir) {
1342
1384
  if (fs5__default.default.existsSync(dir)) {
@@ -1526,9 +1568,9 @@ function startPolling(ctx, build_id, baseline, projectToken) {
1526
1568
  try {
1527
1569
  let resp;
1528
1570
  if (build_id) {
1529
- resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken);
1571
+ resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken, "");
1530
1572
  } else if (ctx.build && ctx.build.id) {
1531
- resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "");
1573
+ resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "", "");
1532
1574
  } else {
1533
1575
  return;
1534
1576
  }
@@ -1600,11 +1642,12 @@ function startPingPolling(ctx) {
1600
1642
  } catch (error) {
1601
1643
  ctx.log.error(`Error during initial ping: ${error.message}`);
1602
1644
  }
1645
+ let sourceCommand = ctx.sourceCommand ? ctx.sourceCommand : "";
1603
1646
  pingIntervalId = setInterval(() => __async(this, null, function* () {
1604
1647
  try {
1605
- ctx.log.debug("Sending ping to server...");
1648
+ ctx.log.debug("Sending ping to server... " + sourceCommand);
1606
1649
  yield ctx.client.ping(ctx.build.id, ctx.log);
1607
- ctx.log.debug("Ping sent successfully.");
1650
+ ctx.log.debug("Ping sent successfully. " + sourceCommand);
1608
1651
  } catch (error) {
1609
1652
  ctx.log.error(`Error during ping polling: ${error.message}`);
1610
1653
  }
@@ -1654,6 +1697,9 @@ function startTunnelBinary(ctx) {
1654
1697
  tunnelArguments.tunnelName = randomTunnelName;
1655
1698
  ctx.config.tunnel.tunnelName = randomTunnelName;
1656
1699
  }
1700
+ if (tunnelConfig == null ? void 0 : tunnelConfig.environment) {
1701
+ tunnelArguments.environment = tunnelConfig.environment;
1702
+ }
1657
1703
  ctx.log.debug(`tunnel config ${JSON.stringify(tunnelArguments)}`);
1658
1704
  if (((_a = ctx.config.tunnel) == null ? void 0 : _a.type) === "auto") {
1659
1705
  tunnelInstance = new lambdaTunnel();
@@ -1664,50 +1710,59 @@ function startTunnelBinary(ctx) {
1664
1710
  }
1665
1711
  });
1666
1712
  }
1667
- function startPollingForTunnel(ctx, build_id, baseline, projectToken) {
1713
+ var isTunnelPolling = null;
1714
+ function startPollingForTunnel(ctx, build_id, baseline, projectToken, buildName) {
1668
1715
  return __async(this, null, function* () {
1716
+ if (isTunnelPolling) {
1717
+ ctx.log.debug("Tunnel polling is already active. Skipping for build_id: " + build_id);
1718
+ return;
1719
+ }
1669
1720
  const intervalId = setInterval(() => __async(this, null, function* () {
1670
1721
  try {
1671
1722
  let resp;
1672
- if (build_id) ; else if (ctx.build && ctx.build.id) {
1673
- resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "");
1723
+ if (build_id) {
1724
+ resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken, buildName);
1725
+ } else if (ctx.build && ctx.build.id) {
1726
+ resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "", "");
1674
1727
  } else {
1728
+ ctx.log.debug("No build information available for polling tunnel status.");
1729
+ clearInterval(intervalId);
1730
+ yield stopTunnelHelper(ctx);
1675
1731
  return;
1676
1732
  }
1733
+ ctx.log.debug(" resp from polling for tunnel status: " + JSON.stringify(resp));
1677
1734
  if (!resp.build) {
1678
1735
  ctx.log.info("Error: Build data is null.");
1679
1736
  clearInterval(intervalId);
1680
- const tunnelRunningStatus = yield tunnelInstance.isRunning();
1681
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1682
- const status = yield tunnelInstance.stop();
1683
- ctx.log.debug("Tunnel is Stopped ? " + status);
1737
+ yield stopTunnelHelper(ctx);
1684
1738
  return;
1685
1739
  }
1686
1740
  if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1687
1741
  clearInterval(intervalId);
1688
- const tunnelRunningStatus = yield tunnelInstance.isRunning();
1689
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1690
- const status = yield tunnelInstance.stop();
1691
- ctx.log.debug("Tunnel is Stopped ? " + status);
1742
+ yield stopTunnelHelper(ctx);
1743
+ return;
1692
1744
  }
1693
1745
  } catch (error) {
1694
- if (error.message.includes("ENOTFOUND")) {
1746
+ if (error == null ? void 0 : error.message.includes("ENOTFOUND")) {
1695
1747
  ctx.log.error("Error: Network error occurred while fetching build status while polling. Please check your connection and try again.");
1696
1748
  clearInterval(intervalId);
1697
1749
  } else {
1698
- ctx.log.error(`Error fetching build status while polling: ${error.message}`);
1750
+ ctx.log.debug(util.inspect(error, { showHidden: false, depth: null }));
1751
+ ctx.log.error(`Error fetching build status while polling: ${JSON.stringify(error)}`);
1699
1752
  }
1700
1753
  clearInterval(intervalId);
1701
1754
  }
1702
1755
  }), 5e3);
1756
+ isTunnelPolling = intervalId;
1703
1757
  });
1704
1758
  }
1705
1759
  function stopTunnelHelper(ctx) {
1706
1760
  return __async(this, null, function* () {
1761
+ ctx.log.debug("stop-tunnel:: Stopping the tunnel now");
1707
1762
  const tunnelRunningStatus = yield tunnelInstance.isRunning();
1708
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1763
+ ctx.log.debug("stop-tunnel:: Running status of tunnel before stopping ? " + tunnelRunningStatus);
1709
1764
  const status = yield tunnelInstance.stop();
1710
- ctx.log.debug("Tunnel is Stopped ? " + status);
1765
+ ctx.log.debug("stop-tunnel:: Tunnel is Stopped ? " + status);
1711
1766
  });
1712
1767
  }
1713
1768
  function calculateVariantCount(config) {
@@ -1936,23 +1991,28 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1936
1991
  reply.code(200).send({ data: { dom: SMARTUI_DOM } });
1937
1992
  });
1938
1993
  server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
1939
- var _a, _b, _c, _d, _e;
1994
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1940
1995
  let replyCode;
1941
1996
  let replyBody;
1942
1997
  try {
1943
1998
  let { snapshot, testType } = request.body;
1944
1999
  if (!validateSnapshot(snapshot))
1945
2000
  throw new Error(validateSnapshot.errors[0].message);
1946
- const sessionId = (_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.sessionId;
2001
+ if (((_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.approvalThreshold) !== void 0 && ((_b = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _b.rejectionThreshold) !== void 0) {
2002
+ if (((_c = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _c.rejectionThreshold) <= ((_d = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _d.approvalThreshold)) {
2003
+ throw new Error(`Invalid snapshot options; rejectionThreshold (${snapshot.options.rejectionThreshold}) must be greater than approvalThreshold (${snapshot.options.approvalThreshold})`);
2004
+ }
2005
+ }
2006
+ const sessionId = (_e = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _e.sessionId;
1947
2007
  let capsBuildId = "";
1948
- const contextId = (_b = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _b.contextId;
2008
+ const contextId = (_f = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _f.contextId;
1949
2009
  if (sessionId) {
1950
- if ((_c = ctx.sessionCapabilitiesMap) == null ? void 0 : _c.has(sessionId)) {
2010
+ if ((_g = ctx.sessionCapabilitiesMap) == null ? void 0 : _g.has(sessionId)) {
1951
2011
  const cachedCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
1952
2012
  capsBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
1953
2013
  } else {
1954
2014
  try {
1955
- let fetchedCapabilitiesResp = yield ctx.client.getSmartUICapabilities(sessionId, ctx.config, ctx.git, ctx.log);
2015
+ let fetchedCapabilitiesResp = yield ctx.client.getSmartUICapabilities(sessionId, ctx.config, ctx.git, ctx.log, ctx.isStartExec);
1956
2016
  capsBuildId = (fetchedCapabilitiesResp == null ? void 0 : fetchedCapabilitiesResp.buildId) || "";
1957
2017
  ctx.log.debug(`fetch caps for sessionId: ${sessionId} are ${JSON.stringify(fetchedCapabilitiesResp)}`);
1958
2018
  if (capsBuildId) {
@@ -1978,9 +2038,9 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1978
2038
  ctx.log.debug(`Marking contextId as captured and added to queue: ${contextId}`);
1979
2039
  }
1980
2040
  if (contextId) {
1981
- (_d = ctx.snapshotQueue) == null ? void 0 : _d.enqueueFront(snapshot);
2041
+ (_h = ctx.snapshotQueue) == null ? void 0 : _h.enqueueFront(snapshot);
1982
2042
  } else {
1983
- (_e = ctx.snapshotQueue) == null ? void 0 : _e.enqueue(snapshot);
2043
+ (_i = ctx.snapshotQueue) == null ? void 0 : _i.enqueue(snapshot);
1984
2044
  }
1985
2045
  ctx.isSnapshotCaptured = true;
1986
2046
  replyCode = 200;
@@ -1993,10 +2053,11 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1993
2053
  return reply.code(replyCode).send(replyBody);
1994
2054
  }));
1995
2055
  server.post("/stop", opts, (_, reply) => __async(void 0, null, function* () {
1996
- var _a, _b, _c;
2056
+ var _a, _b, _c, _d;
1997
2057
  let replyCode;
1998
2058
  let replyBody;
1999
2059
  try {
2060
+ ctx.log.info("Received stop command. Finalizing build ...");
2000
2061
  if (ctx.config.delayedUpload) {
2001
2062
  ctx.log.debug("started after processing because of delayedUpload");
2002
2063
  (_a = ctx.snapshotQueue) == null ? void 0 : _a.startProcessingfunc();
@@ -2010,6 +2071,8 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2010
2071
  }
2011
2072
  }, 1e3);
2012
2073
  });
2074
+ let buildUrls = `build url: ${ctx.build.url}
2075
+ `;
2013
2076
  for (const [sessionId, capabilities] of ctx.sessionCapabilitiesMap.entries()) {
2014
2077
  try {
2015
2078
  const buildId = (capabilities == null ? void 0 : capabilities.buildId) || "";
@@ -2017,8 +2080,12 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2017
2080
  const totalSnapshots = (capabilities == null ? void 0 : capabilities.snapshotCount) || 0;
2018
2081
  const sessionBuildUrl = (capabilities == null ? void 0 : capabilities.buildURL) || "";
2019
2082
  const testId = (capabilities == null ? void 0 : capabilities.id) || "";
2083
+ ctx.log.debug(`Capabilities for sessionId ${sessionId}: ${JSON.stringify(capabilities)}`);
2020
2084
  if (buildId && projectToken) {
2021
2085
  yield ctx.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx.log);
2086
+ if (ctx.autoTunnelStarted) {
2087
+ yield startPollingForTunnel(ctx, buildId, false, projectToken, capabilities == null ? void 0 : capabilities.buildName);
2088
+ }
2022
2089
  }
2023
2090
  if (testId && buildId) {
2024
2091
  buildUrls += `TestId ${testId}: ${sessionBuildUrl}
@@ -2039,7 +2106,13 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2039
2106
  ctx.log.debug(`Skipping upload of CLI logs as useLambdaInternal is set`);
2040
2107
  }
2041
2108
  }
2042
- yield (_c = ctx.browser) == null ? void 0 : _c.close();
2109
+ if (ctx.tunnelDetails && ctx.tunnelDetails.tunnelHost != "" && ((_c = ctx.build) == null ? void 0 : _c.id)) {
2110
+ yield startPollingForTunnel(ctx, ctx.build.id, false, "", "");
2111
+ }
2112
+ if (ctx.autoTunnelStarted && isTunnelPolling === null) {
2113
+ yield stopTunnelHelper(ctx);
2114
+ }
2115
+ yield (_d = ctx.browser) == null ? void 0 : _d.close();
2043
2116
  if (ctx.server) {
2044
2117
  ctx.server.close();
2045
2118
  }
@@ -2055,6 +2128,7 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2055
2128
  replyCode = 500;
2056
2129
  replyBody = { error: { message: error.message } };
2057
2130
  }
2131
+ ctx.log.info("Stop command processed. Tearing down server.");
2058
2132
  return reply.code(replyCode).send(replyBody);
2059
2133
  }));
2060
2134
  server.get("/ping", opts, (_, reply) => {
@@ -2295,7 +2369,7 @@ var authExec_default = (ctx) => {
2295
2369
  };
2296
2370
 
2297
2371
  // package.json
2298
- var version = "4.1.31";
2372
+ var version = "4.1.33";
2299
2373
  var package_default = {
2300
2374
  name: "@lambdatest/smartui-cli",
2301
2375
  version,
@@ -2347,6 +2421,9 @@ var package_default = {
2347
2421
  which: "^4.0.0",
2348
2422
  winston: "^3.10.0"
2349
2423
  },
2424
+ overrides: {
2425
+ "simple-swizzle": "0.2.2"
2426
+ },
2350
2427
  devDependencies: {
2351
2428
  typescript: "^5.3.2"
2352
2429
  }
@@ -2406,8 +2483,9 @@ var httpClient = class {
2406
2483
  this.axiosInstance.interceptors.response.use(
2407
2484
  (response) => response,
2408
2485
  (error) => __async(this, null, function* () {
2486
+ var _a;
2409
2487
  const { config } = error;
2410
- if (config && config.url === "/screenshot" && config.method === "post") {
2488
+ if (config && config.url === "/screenshot" && config.method === "post" && ((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status) !== 401) {
2411
2489
  if (!config.retryCount) {
2412
2490
  config.retryCount = 0;
2413
2491
  config.retry = 2;
@@ -2566,11 +2644,12 @@ var httpClient = class {
2566
2644
  }
2567
2645
  }, log2);
2568
2646
  }
2569
- getScreenshotData(buildId, baseline, log2, projectToken) {
2647
+ getScreenshotData(buildId, baseline, log2, projectToken, buildName) {
2648
+ log2.debug(`Fetching screenshot data for buildId: ${buildId} having buildName: ${buildName} with baseline: ${baseline}`);
2570
2649
  return this.request({
2571
2650
  url: "/screenshot",
2572
2651
  method: "GET",
2573
- params: { buildId, baseline },
2652
+ params: { buildId, baseline, buildName },
2574
2653
  headers: { projectToken }
2575
2654
  }, log2);
2576
2655
  }
@@ -2600,7 +2679,7 @@ var httpClient = class {
2600
2679
  }
2601
2680
  }, log2);
2602
2681
  }
2603
- getSmartUICapabilities(sessionId, config, git, log2) {
2682
+ getSmartUICapabilities(sessionId, config, git, log2, isStartExec) {
2604
2683
  return this.request({
2605
2684
  url: "/sessions/capabilities",
2606
2685
  method: "GET",
@@ -2609,7 +2688,8 @@ var httpClient = class {
2609
2688
  },
2610
2689
  data: {
2611
2690
  git,
2612
- config
2691
+ config,
2692
+ isStartExec
2613
2693
  },
2614
2694
  headers: {
2615
2695
  projectToken: "",
@@ -2658,24 +2738,31 @@ var httpClient = class {
2658
2738
  }
2659
2739
  }, ctx.log);
2660
2740
  }
2661
- processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors, variantCount, sync = false) {
2741
+ processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors, variantCount, sync = false, approvalThreshold, rejectionThreshold) {
2742
+ const requestData = {
2743
+ name: snapshot.name,
2744
+ url: snapshot.url,
2745
+ snapshotUuid,
2746
+ variantCount,
2747
+ test: {
2748
+ type: ctx.testType,
2749
+ source: "cli"
2750
+ },
2751
+ discoveryErrors,
2752
+ doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2753
+ sync
2754
+ };
2755
+ if (approvalThreshold !== void 0) {
2756
+ requestData.approvalThreshold = approvalThreshold;
2757
+ }
2758
+ if (rejectionThreshold !== void 0) {
2759
+ requestData.rejectionThreshold = rejectionThreshold;
2760
+ }
2662
2761
  return this.request({
2663
2762
  url: `/build/${ctx.build.id}/snapshot`,
2664
2763
  method: "POST",
2665
2764
  headers: { "Content-Type": "application/json" },
2666
- data: {
2667
- name: snapshot.name,
2668
- url: snapshot.url,
2669
- snapshotUuid,
2670
- variantCount,
2671
- test: {
2672
- type: ctx.testType,
2673
- source: "cli"
2674
- },
2675
- doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2676
- discoveryErrors,
2677
- sync
2678
- }
2765
+ data: requestData
2679
2766
  }, ctx.log);
2680
2767
  }
2681
2768
  processSnapshotCaps(ctx, snapshot, snapshotUuid, capsBuildId, capsProjectToken, discoveryErrors) {
@@ -3032,6 +3119,11 @@ var ctx_default = (options) => {
3032
3119
  config.web.viewports = config.web.resolutions;
3033
3120
  delete config.web.resolutions;
3034
3121
  }
3122
+ if (config.approvalThreshold && config.rejectionThreshold) {
3123
+ if (config.rejectionThreshold <= config.approvalThreshold) {
3124
+ throw new Error("Invalid config; rejectionThreshold must be greater than approvalThreshold");
3125
+ }
3126
+ }
3035
3127
  let validateConfigFn = options.scheduled ? validateConfigForScheduled : validateConfig;
3036
3128
  if (!validateConfigFn(config)) {
3037
3129
  throw new Error(validateConfigFn.errors[0].message);
@@ -3128,7 +3220,9 @@ var ctx_default = (options) => {
3128
3220
  allowDuplicateSnapshotNames,
3129
3221
  useLambdaInternal,
3130
3222
  useExtendedViewport,
3131
- loadDomContent
3223
+ loadDomContent,
3224
+ approvalThreshold: config.approvalThreshold,
3225
+ rejectionThreshold: config.rejectionThreshold
3132
3226
  },
3133
3227
  uploadFilePath: "",
3134
3228
  webStaticConfig: [],
@@ -3304,7 +3398,6 @@ var createBuildExec_default = (ctx) => {
3304
3398
  return {
3305
3399
  title: `Creating SmartUI build`,
3306
3400
  task: (ctx2, task) => __async(void 0, null, function* () {
3307
- var _a, _b, _c;
3308
3401
  updateLogContext({ task: "createBuild" });
3309
3402
  try {
3310
3403
  if (ctx2.authenticatedInitially && !ctx2.config.skipBuildCreation) {
@@ -3332,17 +3425,17 @@ var createBuildExec_default = (ctx) => {
3332
3425
  }
3333
3426
  task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
3334
3427
  task.title = "SmartUI build created";
3428
+ if (ctx2.env.USE_REMOTE_DISCOVERY) {
3429
+ task.output += chalk__default.default.gray(`
3430
+ Using remote discovery for this build`);
3431
+ }
3335
3432
  } else {
3336
3433
  task.output = chalk__default.default.gray(`Empty PROJECT_TOKEN and PROJECT_NAME. Skipping Creation of Build!`);
3337
3434
  task.title = "Skipped SmartUI build creation";
3338
- if (ctx2.config.tunnel && ((_a = ctx2.config.tunnel) == null ? void 0 : _a.type) === "auto") {
3339
- yield stopTunnelHelper(ctx2);
3340
- }
3341
3435
  }
3342
- if (ctx2.config.tunnel && ((_b = ctx2.config.tunnel) == null ? void 0 : _b.type) === "auto") {
3343
- startPingPolling(ctx2);
3344
- if (ctx2.build && ctx2.build.id) {
3345
- startPollingForTunnel(ctx2, "", false, "");
3436
+ if (ctx2.autoTunnelStarted) {
3437
+ if (ctx2.build && ctx2.build.id && ctx2.sourceCommand != "exec-start") {
3438
+ startPingPolling(ctx2);
3346
3439
  }
3347
3440
  }
3348
3441
  if (ctx2.config.tunnel) {
@@ -3355,6 +3448,13 @@ var createBuildExec_default = (ctx) => {
3355
3448
  tunnelName: tunnelResp.data.tunnel_name
3356
3449
  };
3357
3450
  ctx2.log.debug(`Tunnel Details: ${JSON.stringify(ctx2.tunnelDetails)}`);
3451
+ if (process.env.USE_REMOTE_DISCOVERY === void 0) {
3452
+ ctx2.env.USE_REMOTE_DISCOVERY = true;
3453
+ process.env.USE_REMOTE_DISCOVERY = "true";
3454
+ task.output += chalk__default.default.gray(`
3455
+ Using remote discovery by default for this build`);
3456
+ }
3457
+ ctx2.log.debug(`USE_REMOTE_DISCOVERY is set to ${ctx2.env.USE_REMOTE_DISCOVERY}`);
3358
3458
  } else if (tunnelResp && tunnelResp.error) {
3359
3459
  if (tunnelResp.error.message) {
3360
3460
  if (tunnelResp.error.code && tunnelResp.error.code === 400) {
@@ -3367,7 +3467,7 @@ var createBuildExec_default = (ctx) => {
3367
3467
  }
3368
3468
  } catch (error) {
3369
3469
  ctx2.log.debug(error);
3370
- if (ctx2.config.tunnel && ((_c = ctx2.config.tunnel) == null ? void 0 : _c.type) === "auto") {
3470
+ if (ctx2.autoTunnelStarted) {
3371
3471
  yield stopTunnelHelper(ctx2);
3372
3472
  }
3373
3473
  task.output = chalk__default.default.gray(error.message);
@@ -3425,7 +3525,7 @@ var processSnapshot_default = (ctx) => {
3425
3525
  return {
3426
3526
  title: `Processing snapshots`,
3427
3527
  task: (ctx2, task) => __async(void 0, null, function* () {
3428
- var _a, _b;
3528
+ var _a, _b, _c, _d;
3429
3529
  try {
3430
3530
  if (ctx2.config.delayedUpload) {
3431
3531
  ctx2.log.debug("started after processing because of delayedUpload");
@@ -3434,12 +3534,12 @@ var processSnapshot_default = (ctx) => {
3434
3534
  yield new Promise((resolve) => {
3435
3535
  let output2 = "";
3436
3536
  const intervalId = setInterval(() => {
3437
- var _a2, _b2, _c;
3537
+ var _a2, _b2, _c2;
3438
3538
  if (((_a2 = ctx2.snapshotQueue) == null ? void 0 : _a2.isEmpty()) && !((_b2 = ctx2.snapshotQueue) == null ? void 0 : _b2.isProcessing())) {
3439
3539
  clearInterval(intervalId);
3440
3540
  resolve();
3441
3541
  } else {
3442
- task.title = `Processing snapshot ${(_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessingSnapshot()}`;
3542
+ task.title = `Processing snapshot ${(_c2 = ctx2.snapshotQueue) == null ? void 0 : _c2.getProcessingSnapshot()}`;
3443
3543
  }
3444
3544
  }, 500);
3445
3545
  });
@@ -3457,6 +3557,9 @@ ${snapshot.warnings.length ? chalk__default.default.gray(`[warning] ${snapshot.w
3457
3557
  }
3458
3558
  task.output = output;
3459
3559
  task.title = "Processed snapshots";
3560
+ if (((_d = (_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessedSnapshots()) == null ? void 0 : _d.length) === 0) {
3561
+ task.title = "No snapshots processed";
3562
+ }
3460
3563
  } catch (error) {
3461
3564
  ctx2.log.debug(error);
3462
3565
  task.output = chalk__default.default.gray(error.message);
@@ -3472,7 +3575,7 @@ var finalizeBuild_default = (ctx) => {
3472
3575
  return {
3473
3576
  title: `Finalizing build`,
3474
3577
  task: (ctx2, task) => __async(void 0, null, function* () {
3475
- var _a, _b;
3578
+ var _a, _b, _c;
3476
3579
  updateLogContext({ task: "finalizeBuild" });
3477
3580
  try {
3478
3581
  if (ctx2.build.id) {
@@ -3486,11 +3589,11 @@ var finalizeBuild_default = (ctx) => {
3486
3589
  task.output = chalk__default.default.gray(error.message);
3487
3590
  throw new Error("Finalize build failed");
3488
3591
  }
3489
- let buildUrls2 = `build url: ${ctx2.build.url}
3592
+ let buildUrls = `build url: ${ctx2.build.url}
3490
3593
  `;
3491
3594
  if (pingIntervalId !== null) {
3492
3595
  clearInterval(pingIntervalId);
3493
- ctx2.log.debug("Ping polling stopped immediately.");
3596
+ ctx2.log.debug("Ping polling stopped immediately from Finalize Build");
3494
3597
  }
3495
3598
  for (const [sessionId, capabilities] of ctx2.sessionCapabilitiesMap.entries()) {
3496
3599
  try {
@@ -3512,23 +3615,33 @@ var finalizeBuild_default = (ctx) => {
3512
3615
  ctx2.fetchResultsForBuild.push(buildId);
3513
3616
  }
3514
3617
  }
3618
+ ctx2.log.debug(`Capabilities for sessionId ${sessionId}: ${JSON.stringify(capabilities)}`);
3515
3619
  if (buildId && projectToken) {
3516
3620
  yield ctx2.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx2.log);
3621
+ if (ctx2.autoTunnelStarted) {
3622
+ yield startPollingForTunnel(ctx2, buildId, false, projectToken, capabilities == null ? void 0 : capabilities.buildName);
3623
+ }
3517
3624
  }
3518
3625
  if (testId && buildId) {
3519
- buildUrls2 += `TestId ${testId}: ${sessionBuildUrl}
3626
+ buildUrls += `TestId ${testId}: ${sessionBuildUrl}
3520
3627
  `;
3521
3628
  }
3522
3629
  } catch (error) {
3523
3630
  ctx2.log.debug(`Error finalizing build for session ${sessionId}: ${error.message}`);
3524
3631
  }
3525
3632
  }
3526
- task.output = chalk__default.default.gray(buildUrls2);
3633
+ task.output = chalk__default.default.gray(buildUrls);
3527
3634
  task.title = "Finalized build";
3635
+ if (ctx2.tunnelDetails && ctx2.tunnelDetails.tunnelHost != "" && ((_a = ctx2.build) == null ? void 0 : _a.id)) {
3636
+ yield startPollingForTunnel(ctx2, ctx2.build.id, false, "", "");
3637
+ }
3638
+ if (ctx2.autoTunnelStarted && isTunnelPolling === null) {
3639
+ yield stopTunnelHelper(ctx2);
3640
+ }
3528
3641
  try {
3529
- yield (_a = ctx2.browser) == null ? void 0 : _a.close();
3642
+ yield (_b = ctx2.browser) == null ? void 0 : _b.close();
3530
3643
  ctx2.log.debug(`Closed browser`);
3531
- yield (_b = ctx2.server) == null ? void 0 : _b.close();
3644
+ yield (_c = ctx2.server) == null ? void 0 : _c.close();
3532
3645
  ctx2.log.debug(`Closed server`);
3533
3646
  if (ctx2.isSnapshotCaptured) {
3534
3647
  let uploadCLILogsToS3 = ctx2.config.useLambdaInternal || uploadDomToS3ViaEnv2;
@@ -4488,7 +4601,7 @@ var Queue = class {
4488
4601
  }
4489
4602
  processNext() {
4490
4603
  return __async(this, null, function* () {
4491
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
4604
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
4492
4605
  if (!this.isEmpty()) {
4493
4606
  let snapshot;
4494
4607
  if (this.ctx.config.delayedUpload) {
@@ -4577,7 +4690,7 @@ var Queue = class {
4577
4690
  useKafkaFlow: resp.data.useKafkaFlow || false
4578
4691
  };
4579
4692
  } else {
4580
- if (this.ctx.config.tunnel && ((_d = this.ctx.config.tunnel) == null ? void 0 : _d.type) === "auto") {
4693
+ if (this.ctx.autoTunnelStarted) {
4581
4694
  yield stopTunnelHelper(this.ctx);
4582
4695
  }
4583
4696
  throw new Error("SmartUI capabilities are missing in env variables or in driver capabilities");
@@ -4591,7 +4704,7 @@ var Queue = class {
4591
4704
  if (this.ctx.build && this.ctx.build.useKafkaFlow) {
4592
4705
  let snapshotUuid = uuid.v4();
4593
4706
  let snapshotUploadResponse;
4594
- if (((_e = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _e.contextId) && ((_f = this.ctx.contextToSnapshotMap) == null ? void 0 : _f.has(snapshot.options.contextId))) {
4707
+ if (((_d = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _d.contextId) && ((_e = this.ctx.contextToSnapshotMap) == null ? void 0 : _e.has(snapshot.options.contextId))) {
4595
4708
  snapshotUuid = snapshot.options.contextId;
4596
4709
  }
4597
4710
  let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv3;
@@ -4617,16 +4730,18 @@ var Queue = class {
4617
4730
  this.ctx.log.debug(`Closed browser context for snapshot ${snapshot.name}`);
4618
4731
  }
4619
4732
  }
4620
- if ((_g = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _g.contextId) {
4621
- (_i = this.ctx.contextToSnapshotMap) == null ? void 0 : _i.set((_h = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _h.contextId, 2);
4733
+ if ((_f = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _f.contextId) {
4734
+ (_h = this.ctx.contextToSnapshotMap) == null ? void 0 : _h.set((_g = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _g.contextId, 2);
4622
4735
  }
4623
4736
  this.processNext();
4624
4737
  } else {
4625
- yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid, discoveryErrors, calculateVariantCountFromSnapshot(processedSnapshot, this.ctx.config), (_j = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _j.sync);
4626
- if (((_k = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _k.contextId) && ((_l = this.ctx.contextToSnapshotMap) == null ? void 0 : _l.has(snapshot.options.contextId))) {
4738
+ let approvalThreshold = ((_i = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _i.approvalThreshold) || this.ctx.config.approvalThreshold;
4739
+ let rejectionThreshold = ((_j = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _j.rejectionThreshold) || this.ctx.config.rejectionThreshold;
4740
+ yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid, discoveryErrors, calculateVariantCountFromSnapshot(processedSnapshot, this.ctx.config), (_k = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _k.sync, approvalThreshold, rejectionThreshold);
4741
+ if (((_l = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _l.contextId) && ((_m = this.ctx.contextToSnapshotMap) == null ? void 0 : _m.has(snapshot.options.contextId))) {
4627
4742
  this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 1);
4628
4743
  }
4629
- this.ctx.log.debug(`ContextId: ${(_m = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _m.contextId} status set to uploaded`);
4744
+ this.ctx.log.debug(`ContextId: ${(_n = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _n.contextId} status set to uploaded`);
4630
4745
  }
4631
4746
  } else {
4632
4747
  this.ctx.log.info(`Uploading snapshot to S3`);
@@ -4639,7 +4754,7 @@ var Queue = class {
4639
4754
  } catch (error) {
4640
4755
  this.ctx.log.debug(`snapshot failed; ${error}`);
4641
4756
  this.processedSnapshots.push({ name: snapshot == null ? void 0 : snapshot.name, error: error.message });
4642
- if (((_n = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _n.contextId) && this.ctx.contextToSnapshotMap) {
4757
+ if (((_o = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _o.contextId) && this.ctx.contextToSnapshotMap) {
4643
4758
  this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 2);
4644
4759
  }
4645
4760
  }
@@ -4680,6 +4795,7 @@ var startTunnel_default = (ctx) => {
4680
4795
  try {
4681
4796
  yield startTunnelBinary(ctx2);
4682
4797
  ctx2.isStartExec = true;
4798
+ ctx2.autoTunnelStarted = true;
4683
4799
  task.title = "Tunnel Started";
4684
4800
  task.output = chalk__default.default.gray("Tunnel started successfully");
4685
4801
  } catch (error) {
@@ -4710,6 +4826,7 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
4710
4826
  ctx.args.execCommand = execCommand;
4711
4827
  ctx.snapshotQueue = new Queue(ctx);
4712
4828
  ctx.totalSnapshots = 0;
4829
+ ctx.sourceCommand = "exec";
4713
4830
  let tasks = new listr2.Listr(
4714
4831
  [
4715
4832
  authExec_default(),
@@ -4986,6 +5103,25 @@ function captureScreenshotsForConfig(ctx, browsers, urlConfig, browserName, rend
4986
5103
  const browser = browsers[browserName];
4987
5104
  context = yield browser == null ? void 0 : browser.newContext(contextOptions);
4988
5105
  page = yield context == null ? void 0 : context.newPage();
5106
+ const headersObject = {};
5107
+ if (ctx.config.requestHeaders && Array.isArray(ctx.config.requestHeaders)) {
5108
+ ctx.config.requestHeaders.forEach((headerObj) => {
5109
+ Object.entries(headerObj).forEach(([key, value]) => {
5110
+ headersObject[key] = value;
5111
+ });
5112
+ });
5113
+ }
5114
+ if (urlConfig.requestHeaders && Array.isArray(urlConfig.requestHeaders)) {
5115
+ urlConfig.requestHeaders.forEach((headerObj) => {
5116
+ Object.entries(headerObj).forEach(([key, value]) => {
5117
+ headersObject[key] = value;
5118
+ });
5119
+ });
5120
+ }
5121
+ ctx.log.debug(`Combined headers: ${JSON.stringify(headersObject)}`);
5122
+ if (Object.keys(headersObject).length > 0) {
5123
+ yield page.setExtraHTTPHeaders(headersObject);
5124
+ }
4989
5125
  yield page == null ? void 0 : page.goto(url.trim(), pageOptions);
4990
5126
  yield executeDocumentScripts(ctx, page, "afterNavigation", afterNavigationScript);
4991
5127
  for (let { viewport, viewportString, fullPage } of renderViewports) {
@@ -5526,7 +5662,8 @@ var uploadWebFigma_default = (ctx) => __async(void 0, null, function* () {
5526
5662
  web: webConfig,
5527
5663
  figma: figmaConfig,
5528
5664
  smartIgnore: ctx.config.smartIgnore,
5529
- git: ctx.git
5665
+ git: ctx.git,
5666
+ markBaseline: ctx.options.markBaseline
5530
5667
  };
5531
5668
  const responseData = yield ctx.client.processWebFigma(requestBody, ctx.log);
5532
5669
  ctx.log.debug("responseData : " + JSON.stringify(responseData));
@@ -5641,7 +5778,8 @@ var uploadAppFigma_default = (ctx) => __async(void 0, null, function* () {
5641
5778
  figma: figmaConfig,
5642
5779
  smartIgnore: ctx.config.smartIgnore,
5643
5780
  git: ctx.git,
5644
- platformType: "app"
5781
+ platformType: "app",
5782
+ markBaseline: ctx.options.markBaseline
5645
5783
  };
5646
5784
  const responseData = yield ctx.client.processWebFigma(requestBody, ctx.log);
5647
5785
  ctx.log.debug("responseData : " + JSON.stringify(responseData));
@@ -5850,6 +5988,7 @@ uploadAppFigmaCommand.name("upload-figma-app").description("Capture figma screen
5850
5988
  var command4 = new commander.Command();
5851
5989
  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() {
5852
5990
  return __async(this, null, function* () {
5991
+ var _a;
5853
5992
  const options = command4.optsWithGlobals();
5854
5993
  if (options.buildName === "") {
5855
5994
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
@@ -5859,11 +5998,13 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5859
5998
  ctx.snapshotQueue = new Queue(ctx);
5860
5999
  ctx.totalSnapshots = 0;
5861
6000
  ctx.isStartExec = true;
6001
+ ctx.sourceCommand = "exec-start";
5862
6002
  let tasks = new listr2.Listr(
5863
6003
  [
5864
6004
  authExec_default(),
5865
6005
  startServer_default(),
5866
6006
  getGitInfo_default(),
6007
+ ...ctx.config.tunnel && ((_a = ctx.config.tunnel) == null ? void 0 : _a.type) === "auto" ? [startTunnel_default()] : [],
5867
6008
  createBuildExec_default()
5868
6009
  ],
5869
6010
  {
@@ -5879,7 +6020,7 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5879
6020
  );
5880
6021
  try {
5881
6022
  yield tasks.run(ctx);
5882
- if (ctx.build && ctx.build.id) {
6023
+ if (ctx.build && ctx.build.id && !ctx.autoTunnelStarted) {
5883
6024
  startPingPolling(ctx);
5884
6025
  }
5885
6026
  if (ctx.options.fetchResults && ctx.build && ctx.build.id) {
@@ -5887,6 +6028,7 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5887
6028
  }
5888
6029
  } catch (error) {
5889
6030
  console.error("Error during server execution:", error);
6031
+ process.exit(1);
5890
6032
  }
5891
6033
  });
5892
6034
  });
@@ -5914,8 +6056,11 @@ command5.name("exec:stop").description("Stop the SmartUI server").action(functio
5914
6056
  console.log(chalk__default.default.red("Failed to stop server"));
5915
6057
  }
5916
6058
  } catch (error) {
5917
- if (error.code === "ECONNABORTED") {
6059
+ if (error && error.code === "ECONNABORTED") {
5918
6060
  console.error(chalk__default.default.red("Error: SmartUI server did not respond in 15 seconds"));
6061
+ }
6062
+ if (error && error.code === "ECONNREFUSED") {
6063
+ console.error(chalk__default.default.red("Error: Looks like smartui cli server is already stopped"));
5919
6064
  } else {
5920
6065
  console.error(chalk__default.default.red("Error while stopping server"));
5921
6066
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.31",
3
+ "version": "4.1.33",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"
@@ -43,6 +43,9 @@
43
43
  "which": "^4.0.0",
44
44
  "winston": "^3.10.0"
45
45
  },
46
+ "overrides": {
47
+ "simple-swizzle": "0.2.2"
48
+ },
46
49
  "devDependencies": {
47
50
  "typescript": "^5.3.2"
48
51
  },