@lambdatest/smartui-cli 4.1.30 → 4.1.32

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 +234 -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"],
@@ -779,6 +784,26 @@ var ConfigSchema = {
779
784
  useLambdaInternal: {
780
785
  type: "boolean",
781
786
  errorMessage: "Invalid config; useLambdaInternal must be true/false"
787
+ },
788
+ useExtendedViewport: {
789
+ type: "boolean",
790
+ errorMessage: "Invalid config; useExtendedViewport must be true/false"
791
+ },
792
+ loadDomContent: {
793
+ type: "boolean",
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"
782
807
  }
783
808
  },
784
809
  anyOf: [
@@ -1036,6 +1061,22 @@ var SnapshotSchema = {
1036
1061
  timeout: {
1037
1062
  type: "number",
1038
1063
  errorMessage: "Invalid snapshot options; timeout must be a number"
1064
+ },
1065
+ useExtendedViewport: {
1066
+ type: "boolean",
1067
+ errorMessage: "Invalid snapshot options; useExtendedViewport must be a boolean"
1068
+ },
1069
+ approvalThreshold: {
1070
+ type: "number",
1071
+ minimum: 0,
1072
+ maximum: 100,
1073
+ errorMessage: "Invalid snapshot options; approvalThreshold must be a number between 0 and 100"
1074
+ },
1075
+ rejectionThreshold: {
1076
+ type: "number",
1077
+ minimum: 0,
1078
+ maximum: 100,
1079
+ errorMessage: "Invalid snapshot options; rejectionThreshold must be a number between 0 and 100"
1039
1080
  }
1040
1081
  },
1041
1082
  additionalProperties: false
@@ -1323,8 +1364,9 @@ var validateConfigForScheduled = (config) => {
1323
1364
  return true;
1324
1365
  };
1325
1366
  validateConfigForScheduled.errors = null;
1367
+ var util = __require("util");
1326
1368
  var lambdaTunnel = __require("@lambdatest/node-tunnel");
1327
- util.promisify(setTimeout);
1369
+ util$1.promisify(setTimeout);
1328
1370
  var tunnelInstance;
1329
1371
  function delDir(dir) {
1330
1372
  if (fs5__default.default.existsSync(dir)) {
@@ -1514,9 +1556,9 @@ function startPolling(ctx, build_id, baseline, projectToken) {
1514
1556
  try {
1515
1557
  let resp;
1516
1558
  if (build_id) {
1517
- resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken);
1559
+ resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken, "");
1518
1560
  } else if (ctx.build && ctx.build.id) {
1519
- resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "");
1561
+ resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "", "");
1520
1562
  } else {
1521
1563
  return;
1522
1564
  }
@@ -1588,11 +1630,12 @@ function startPingPolling(ctx) {
1588
1630
  } catch (error) {
1589
1631
  ctx.log.error(`Error during initial ping: ${error.message}`);
1590
1632
  }
1633
+ let sourceCommand = ctx.sourceCommand ? ctx.sourceCommand : "";
1591
1634
  pingIntervalId = setInterval(() => __async(this, null, function* () {
1592
1635
  try {
1593
- ctx.log.debug("Sending ping to server...");
1636
+ ctx.log.debug("Sending ping to server... " + sourceCommand);
1594
1637
  yield ctx.client.ping(ctx.build.id, ctx.log);
1595
- ctx.log.debug("Ping sent successfully.");
1638
+ ctx.log.debug("Ping sent successfully. " + sourceCommand);
1596
1639
  } catch (error) {
1597
1640
  ctx.log.error(`Error during ping polling: ${error.message}`);
1598
1641
  }
@@ -1642,6 +1685,9 @@ function startTunnelBinary(ctx) {
1642
1685
  tunnelArguments.tunnelName = randomTunnelName;
1643
1686
  ctx.config.tunnel.tunnelName = randomTunnelName;
1644
1687
  }
1688
+ if (tunnelConfig == null ? void 0 : tunnelConfig.environment) {
1689
+ tunnelArguments.environment = tunnelConfig.environment;
1690
+ }
1645
1691
  ctx.log.debug(`tunnel config ${JSON.stringify(tunnelArguments)}`);
1646
1692
  if (((_a = ctx.config.tunnel) == null ? void 0 : _a.type) === "auto") {
1647
1693
  tunnelInstance = new lambdaTunnel();
@@ -1652,50 +1698,59 @@ function startTunnelBinary(ctx) {
1652
1698
  }
1653
1699
  });
1654
1700
  }
1655
- function startPollingForTunnel(ctx, build_id, baseline, projectToken) {
1701
+ var isTunnelPolling = null;
1702
+ function startPollingForTunnel(ctx, build_id, baseline, projectToken, buildName) {
1656
1703
  return __async(this, null, function* () {
1704
+ if (isTunnelPolling) {
1705
+ ctx.log.debug("Tunnel polling is already active. Skipping for build_id: " + build_id);
1706
+ return;
1707
+ }
1657
1708
  const intervalId = setInterval(() => __async(this, null, function* () {
1658
1709
  try {
1659
1710
  let resp;
1660
- if (build_id) ; else if (ctx.build && ctx.build.id) {
1661
- resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "");
1711
+ if (build_id) {
1712
+ resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken, buildName);
1713
+ } else if (ctx.build && ctx.build.id) {
1714
+ resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "", "");
1662
1715
  } else {
1716
+ ctx.log.debug("No build information available for polling tunnel status.");
1717
+ clearInterval(intervalId);
1718
+ yield stopTunnelHelper(ctx);
1663
1719
  return;
1664
1720
  }
1721
+ ctx.log.debug(" resp from polling for tunnel status: " + JSON.stringify(resp));
1665
1722
  if (!resp.build) {
1666
1723
  ctx.log.info("Error: Build data is null.");
1667
1724
  clearInterval(intervalId);
1668
- const tunnelRunningStatus = yield tunnelInstance.isRunning();
1669
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1670
- const status = yield tunnelInstance.stop();
1671
- ctx.log.debug("Tunnel is Stopped ? " + status);
1725
+ yield stopTunnelHelper(ctx);
1672
1726
  return;
1673
1727
  }
1674
1728
  if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1675
1729
  clearInterval(intervalId);
1676
- const tunnelRunningStatus = yield tunnelInstance.isRunning();
1677
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1678
- const status = yield tunnelInstance.stop();
1679
- ctx.log.debug("Tunnel is Stopped ? " + status);
1730
+ yield stopTunnelHelper(ctx);
1731
+ return;
1680
1732
  }
1681
1733
  } catch (error) {
1682
- if (error.message.includes("ENOTFOUND")) {
1734
+ if (error == null ? void 0 : error.message.includes("ENOTFOUND")) {
1683
1735
  ctx.log.error("Error: Network error occurred while fetching build status while polling. Please check your connection and try again.");
1684
1736
  clearInterval(intervalId);
1685
1737
  } else {
1686
- ctx.log.error(`Error fetching build status while polling: ${error.message}`);
1738
+ ctx.log.debug(util.inspect(error, { showHidden: false, depth: null }));
1739
+ ctx.log.error(`Error fetching build status while polling: ${JSON.stringify(error)}`);
1687
1740
  }
1688
1741
  clearInterval(intervalId);
1689
1742
  }
1690
1743
  }), 5e3);
1744
+ isTunnelPolling = intervalId;
1691
1745
  });
1692
1746
  }
1693
1747
  function stopTunnelHelper(ctx) {
1694
1748
  return __async(this, null, function* () {
1749
+ ctx.log.debug("stop-tunnel:: Stopping the tunnel now");
1695
1750
  const tunnelRunningStatus = yield tunnelInstance.isRunning();
1696
- ctx.log.debug("Running status of tunnel before stopping ? " + tunnelRunningStatus);
1751
+ ctx.log.debug("stop-tunnel:: Running status of tunnel before stopping ? " + tunnelRunningStatus);
1697
1752
  const status = yield tunnelInstance.stop();
1698
- ctx.log.debug("Tunnel is Stopped ? " + status);
1753
+ ctx.log.debug("stop-tunnel:: Tunnel is Stopped ? " + status);
1699
1754
  });
1700
1755
  }
1701
1756
  function calculateVariantCount(config) {
@@ -1924,23 +1979,28 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1924
1979
  reply.code(200).send({ data: { dom: SMARTUI_DOM } });
1925
1980
  });
1926
1981
  server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
1927
- var _a, _b, _c, _d, _e;
1982
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1928
1983
  let replyCode;
1929
1984
  let replyBody;
1930
1985
  try {
1931
1986
  let { snapshot, testType } = request.body;
1932
1987
  if (!validateSnapshot(snapshot))
1933
1988
  throw new Error(validateSnapshot.errors[0].message);
1934
- const sessionId = (_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.sessionId;
1989
+ 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) {
1990
+ 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)) {
1991
+ throw new Error(`Invalid snapshot options; rejectionThreshold (${snapshot.options.rejectionThreshold}) must be greater than approvalThreshold (${snapshot.options.approvalThreshold})`);
1992
+ }
1993
+ }
1994
+ const sessionId = (_e = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _e.sessionId;
1935
1995
  let capsBuildId = "";
1936
- const contextId = (_b = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _b.contextId;
1996
+ const contextId = (_f = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _f.contextId;
1937
1997
  if (sessionId) {
1938
- if ((_c = ctx.sessionCapabilitiesMap) == null ? void 0 : _c.has(sessionId)) {
1998
+ if ((_g = ctx.sessionCapabilitiesMap) == null ? void 0 : _g.has(sessionId)) {
1939
1999
  const cachedCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
1940
2000
  capsBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
1941
2001
  } else {
1942
2002
  try {
1943
- let fetchedCapabilitiesResp = yield ctx.client.getSmartUICapabilities(sessionId, ctx.config, ctx.git, ctx.log);
2003
+ let fetchedCapabilitiesResp = yield ctx.client.getSmartUICapabilities(sessionId, ctx.config, ctx.git, ctx.log, ctx.isStartExec);
1944
2004
  capsBuildId = (fetchedCapabilitiesResp == null ? void 0 : fetchedCapabilitiesResp.buildId) || "";
1945
2005
  ctx.log.debug(`fetch caps for sessionId: ${sessionId} are ${JSON.stringify(fetchedCapabilitiesResp)}`);
1946
2006
  if (capsBuildId) {
@@ -1966,9 +2026,9 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1966
2026
  ctx.log.debug(`Marking contextId as captured and added to queue: ${contextId}`);
1967
2027
  }
1968
2028
  if (contextId) {
1969
- (_d = ctx.snapshotQueue) == null ? void 0 : _d.enqueueFront(snapshot);
2029
+ (_h = ctx.snapshotQueue) == null ? void 0 : _h.enqueueFront(snapshot);
1970
2030
  } else {
1971
- (_e = ctx.snapshotQueue) == null ? void 0 : _e.enqueue(snapshot);
2031
+ (_i = ctx.snapshotQueue) == null ? void 0 : _i.enqueue(snapshot);
1972
2032
  }
1973
2033
  ctx.isSnapshotCaptured = true;
1974
2034
  replyCode = 200;
@@ -1981,10 +2041,11 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1981
2041
  return reply.code(replyCode).send(replyBody);
1982
2042
  }));
1983
2043
  server.post("/stop", opts, (_, reply) => __async(void 0, null, function* () {
1984
- var _a, _b, _c;
2044
+ var _a, _b, _c, _d;
1985
2045
  let replyCode;
1986
2046
  let replyBody;
1987
2047
  try {
2048
+ ctx.log.info("Received stop command. Finalizing build ...");
1988
2049
  if (ctx.config.delayedUpload) {
1989
2050
  ctx.log.debug("started after processing because of delayedUpload");
1990
2051
  (_a = ctx.snapshotQueue) == null ? void 0 : _a.startProcessingfunc();
@@ -1998,6 +2059,8 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1998
2059
  }
1999
2060
  }, 1e3);
2000
2061
  });
2062
+ let buildUrls = `build url: ${ctx.build.url}
2063
+ `;
2001
2064
  for (const [sessionId, capabilities] of ctx.sessionCapabilitiesMap.entries()) {
2002
2065
  try {
2003
2066
  const buildId = (capabilities == null ? void 0 : capabilities.buildId) || "";
@@ -2005,8 +2068,12 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2005
2068
  const totalSnapshots = (capabilities == null ? void 0 : capabilities.snapshotCount) || 0;
2006
2069
  const sessionBuildUrl = (capabilities == null ? void 0 : capabilities.buildURL) || "";
2007
2070
  const testId = (capabilities == null ? void 0 : capabilities.id) || "";
2071
+ ctx.log.debug(`Capabilities for sessionId ${sessionId}: ${JSON.stringify(capabilities)}`);
2008
2072
  if (buildId && projectToken) {
2009
2073
  yield ctx.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx.log);
2074
+ if (ctx.autoTunnelStarted) {
2075
+ yield startPollingForTunnel(ctx, buildId, false, projectToken, capabilities == null ? void 0 : capabilities.buildName);
2076
+ }
2010
2077
  }
2011
2078
  if (testId && buildId) {
2012
2079
  buildUrls += `TestId ${testId}: ${sessionBuildUrl}
@@ -2027,7 +2094,13 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2027
2094
  ctx.log.debug(`Skipping upload of CLI logs as useLambdaInternal is set`);
2028
2095
  }
2029
2096
  }
2030
- yield (_c = ctx.browser) == null ? void 0 : _c.close();
2097
+ if (ctx.tunnelDetails && ctx.tunnelDetails.tunnelHost != "" && ((_c = ctx.build) == null ? void 0 : _c.id)) {
2098
+ yield startPollingForTunnel(ctx, ctx.build.id, false, "", "");
2099
+ }
2100
+ if (ctx.autoTunnelStarted && isTunnelPolling === null) {
2101
+ yield stopTunnelHelper(ctx);
2102
+ }
2103
+ yield (_d = ctx.browser) == null ? void 0 : _d.close();
2031
2104
  if (ctx.server) {
2032
2105
  ctx.server.close();
2033
2106
  }
@@ -2043,6 +2116,7 @@ var server_default = (ctx) => __async(void 0, null, function* () {
2043
2116
  replyCode = 500;
2044
2117
  replyBody = { error: { message: error.message } };
2045
2118
  }
2119
+ ctx.log.info("Stop command processed. Tearing down server.");
2046
2120
  return reply.code(replyCode).send(replyBody);
2047
2121
  }));
2048
2122
  server.get("/ping", opts, (_, reply) => {
@@ -2283,7 +2357,7 @@ var authExec_default = (ctx) => {
2283
2357
  };
2284
2358
 
2285
2359
  // package.json
2286
- var version = "4.1.30";
2360
+ var version = "4.1.32";
2287
2361
  var package_default = {
2288
2362
  name: "@lambdatest/smartui-cli",
2289
2363
  version,
@@ -2335,6 +2409,9 @@ var package_default = {
2335
2409
  which: "^4.0.0",
2336
2410
  winston: "^3.10.0"
2337
2411
  },
2412
+ overrides: {
2413
+ "simple-swizzle": "0.2.2"
2414
+ },
2338
2415
  devDependencies: {
2339
2416
  typescript: "^5.3.2"
2340
2417
  }
@@ -2394,8 +2471,9 @@ var httpClient = class {
2394
2471
  this.axiosInstance.interceptors.response.use(
2395
2472
  (response) => response,
2396
2473
  (error) => __async(this, null, function* () {
2474
+ var _a;
2397
2475
  const { config } = error;
2398
- if (config && config.url === "/screenshot" && config.method === "post") {
2476
+ if (config && config.url === "/screenshot" && config.method === "post" && ((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status) !== 401) {
2399
2477
  if (!config.retryCount) {
2400
2478
  config.retryCount = 0;
2401
2479
  config.retry = 2;
@@ -2554,11 +2632,12 @@ var httpClient = class {
2554
2632
  }
2555
2633
  }, log2);
2556
2634
  }
2557
- getScreenshotData(buildId, baseline, log2, projectToken) {
2635
+ getScreenshotData(buildId, baseline, log2, projectToken, buildName) {
2636
+ log2.debug(`Fetching screenshot data for buildId: ${buildId} having buildName: ${buildName} with baseline: ${baseline}`);
2558
2637
  return this.request({
2559
2638
  url: "/screenshot",
2560
2639
  method: "GET",
2561
- params: { buildId, baseline },
2640
+ params: { buildId, baseline, buildName },
2562
2641
  headers: { projectToken }
2563
2642
  }, log2);
2564
2643
  }
@@ -2588,7 +2667,7 @@ var httpClient = class {
2588
2667
  }
2589
2668
  }, log2);
2590
2669
  }
2591
- getSmartUICapabilities(sessionId, config, git, log2) {
2670
+ getSmartUICapabilities(sessionId, config, git, log2, isStartExec) {
2592
2671
  return this.request({
2593
2672
  url: "/sessions/capabilities",
2594
2673
  method: "GET",
@@ -2597,7 +2676,8 @@ var httpClient = class {
2597
2676
  },
2598
2677
  data: {
2599
2678
  git,
2600
- config
2679
+ config,
2680
+ isStartExec
2601
2681
  },
2602
2682
  headers: {
2603
2683
  projectToken: "",
@@ -2646,24 +2726,31 @@ var httpClient = class {
2646
2726
  }
2647
2727
  }, ctx.log);
2648
2728
  }
2649
- processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors, variantCount, sync = false) {
2729
+ processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors, variantCount, sync = false, approvalThreshold, rejectionThreshold) {
2730
+ const requestData = {
2731
+ name: snapshot.name,
2732
+ url: snapshot.url,
2733
+ snapshotUuid,
2734
+ variantCount,
2735
+ test: {
2736
+ type: ctx.testType,
2737
+ source: "cli"
2738
+ },
2739
+ discoveryErrors,
2740
+ doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2741
+ sync
2742
+ };
2743
+ if (approvalThreshold !== void 0) {
2744
+ requestData.approvalThreshold = approvalThreshold;
2745
+ }
2746
+ if (rejectionThreshold !== void 0) {
2747
+ requestData.rejectionThreshold = rejectionThreshold;
2748
+ }
2650
2749
  return this.request({
2651
2750
  url: `/build/${ctx.build.id}/snapshot`,
2652
2751
  method: "POST",
2653
2752
  headers: { "Content-Type": "application/json" },
2654
- data: {
2655
- name: snapshot.name,
2656
- url: snapshot.url,
2657
- snapshotUuid,
2658
- variantCount,
2659
- test: {
2660
- type: ctx.testType,
2661
- source: "cli"
2662
- },
2663
- doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2664
- discoveryErrors,
2665
- sync
2666
- }
2753
+ data: requestData
2667
2754
  }, ctx.log);
2668
2755
  }
2669
2756
  processSnapshotCaps(ctx, snapshot, snapshotUuid, capsBuildId, capsProjectToken, discoveryErrors) {
@@ -3011,6 +3098,8 @@ var ctx_default = (options) => {
3011
3098
  let buildNameObj;
3012
3099
  let allowDuplicateSnapshotNames = false;
3013
3100
  let useLambdaInternal = false;
3101
+ let useExtendedViewport = false;
3102
+ let loadDomContent = false;
3014
3103
  try {
3015
3104
  if (options.config) {
3016
3105
  config = JSON.parse(fs5__default.default.readFileSync(options.config, "utf-8"));
@@ -3018,6 +3107,11 @@ var ctx_default = (options) => {
3018
3107
  config.web.viewports = config.web.resolutions;
3019
3108
  delete config.web.resolutions;
3020
3109
  }
3110
+ if (config.approvalThreshold && config.rejectionThreshold) {
3111
+ if (config.rejectionThreshold <= config.approvalThreshold) {
3112
+ throw new Error("Invalid config; rejectionThreshold must be greater than approvalThreshold");
3113
+ }
3114
+ }
3021
3115
  let validateConfigFn = options.scheduled ? validateConfigForScheduled : validateConfig;
3022
3116
  if (!validateConfigFn(config)) {
3023
3117
  throw new Error(validateConfigFn.errors[0].message);
@@ -3078,6 +3172,12 @@ var ctx_default = (options) => {
3078
3172
  if (config.useLambdaInternal) {
3079
3173
  useLambdaInternal = true;
3080
3174
  }
3175
+ if (config.useExtendedViewport) {
3176
+ useExtendedViewport = true;
3177
+ }
3178
+ if (config.loadDomContent) {
3179
+ loadDomContent = true;
3180
+ }
3081
3181
  if (config.waitForPageRender && config.waitForPageRender < 3e4) {
3082
3182
  config.waitForPageRender = 3e4;
3083
3183
  }
@@ -3106,7 +3206,11 @@ var ctx_default = (options) => {
3106
3206
  userAgent: config.userAgent || "",
3107
3207
  requestHeaders: config.requestHeaders || {},
3108
3208
  allowDuplicateSnapshotNames,
3109
- useLambdaInternal
3209
+ useLambdaInternal,
3210
+ useExtendedViewport,
3211
+ loadDomContent,
3212
+ approvalThreshold: config.approvalThreshold,
3213
+ rejectionThreshold: config.rejectionThreshold
3110
3214
  },
3111
3215
  uploadFilePath: "",
3112
3216
  webStaticConfig: [],
@@ -3282,7 +3386,6 @@ var createBuildExec_default = (ctx) => {
3282
3386
  return {
3283
3387
  title: `Creating SmartUI build`,
3284
3388
  task: (ctx2, task) => __async(void 0, null, function* () {
3285
- var _a, _b, _c;
3286
3389
  updateLogContext({ task: "createBuild" });
3287
3390
  try {
3288
3391
  if (ctx2.authenticatedInitially && !ctx2.config.skipBuildCreation) {
@@ -3310,17 +3413,17 @@ var createBuildExec_default = (ctx) => {
3310
3413
  }
3311
3414
  task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
3312
3415
  task.title = "SmartUI build created";
3416
+ if (ctx2.env.USE_REMOTE_DISCOVERY) {
3417
+ task.output += chalk__default.default.gray(`
3418
+ Using remote discovery for this build`);
3419
+ }
3313
3420
  } else {
3314
3421
  task.output = chalk__default.default.gray(`Empty PROJECT_TOKEN and PROJECT_NAME. Skipping Creation of Build!`);
3315
3422
  task.title = "Skipped SmartUI build creation";
3316
- if (ctx2.config.tunnel && ((_a = ctx2.config.tunnel) == null ? void 0 : _a.type) === "auto") {
3317
- yield stopTunnelHelper(ctx2);
3318
- }
3319
3423
  }
3320
- if (ctx2.config.tunnel && ((_b = ctx2.config.tunnel) == null ? void 0 : _b.type) === "auto") {
3321
- startPingPolling(ctx2);
3322
- if (ctx2.build && ctx2.build.id) {
3323
- startPollingForTunnel(ctx2, "", false, "");
3424
+ if (ctx2.autoTunnelStarted) {
3425
+ if (ctx2.build && ctx2.build.id && ctx2.sourceCommand != "exec-start") {
3426
+ startPingPolling(ctx2);
3324
3427
  }
3325
3428
  }
3326
3429
  if (ctx2.config.tunnel) {
@@ -3333,6 +3436,13 @@ var createBuildExec_default = (ctx) => {
3333
3436
  tunnelName: tunnelResp.data.tunnel_name
3334
3437
  };
3335
3438
  ctx2.log.debug(`Tunnel Details: ${JSON.stringify(ctx2.tunnelDetails)}`);
3439
+ if (process.env.USE_REMOTE_DISCOVERY === void 0) {
3440
+ ctx2.env.USE_REMOTE_DISCOVERY = true;
3441
+ process.env.USE_REMOTE_DISCOVERY = "true";
3442
+ task.output += chalk__default.default.gray(`
3443
+ Using remote discovery by default for this build`);
3444
+ }
3445
+ ctx2.log.debug(`USE_REMOTE_DISCOVERY is set to ${ctx2.env.USE_REMOTE_DISCOVERY}`);
3336
3446
  } else if (tunnelResp && tunnelResp.error) {
3337
3447
  if (tunnelResp.error.message) {
3338
3448
  if (tunnelResp.error.code && tunnelResp.error.code === 400) {
@@ -3345,7 +3455,7 @@ var createBuildExec_default = (ctx) => {
3345
3455
  }
3346
3456
  } catch (error) {
3347
3457
  ctx2.log.debug(error);
3348
- if (ctx2.config.tunnel && ((_c = ctx2.config.tunnel) == null ? void 0 : _c.type) === "auto") {
3458
+ if (ctx2.autoTunnelStarted) {
3349
3459
  yield stopTunnelHelper(ctx2);
3350
3460
  }
3351
3461
  task.output = chalk__default.default.gray(error.message);
@@ -3403,7 +3513,7 @@ var processSnapshot_default = (ctx) => {
3403
3513
  return {
3404
3514
  title: `Processing snapshots`,
3405
3515
  task: (ctx2, task) => __async(void 0, null, function* () {
3406
- var _a, _b;
3516
+ var _a, _b, _c, _d;
3407
3517
  try {
3408
3518
  if (ctx2.config.delayedUpload) {
3409
3519
  ctx2.log.debug("started after processing because of delayedUpload");
@@ -3412,12 +3522,12 @@ var processSnapshot_default = (ctx) => {
3412
3522
  yield new Promise((resolve) => {
3413
3523
  let output2 = "";
3414
3524
  const intervalId = setInterval(() => {
3415
- var _a2, _b2, _c;
3525
+ var _a2, _b2, _c2;
3416
3526
  if (((_a2 = ctx2.snapshotQueue) == null ? void 0 : _a2.isEmpty()) && !((_b2 = ctx2.snapshotQueue) == null ? void 0 : _b2.isProcessing())) {
3417
3527
  clearInterval(intervalId);
3418
3528
  resolve();
3419
3529
  } else {
3420
- task.title = `Processing snapshot ${(_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessingSnapshot()}`;
3530
+ task.title = `Processing snapshot ${(_c2 = ctx2.snapshotQueue) == null ? void 0 : _c2.getProcessingSnapshot()}`;
3421
3531
  }
3422
3532
  }, 500);
3423
3533
  });
@@ -3435,6 +3545,9 @@ ${snapshot.warnings.length ? chalk__default.default.gray(`[warning] ${snapshot.w
3435
3545
  }
3436
3546
  task.output = output;
3437
3547
  task.title = "Processed snapshots";
3548
+ if (((_d = (_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessedSnapshots()) == null ? void 0 : _d.length) === 0) {
3549
+ task.title = "No snapshots processed";
3550
+ }
3438
3551
  } catch (error) {
3439
3552
  ctx2.log.debug(error);
3440
3553
  task.output = chalk__default.default.gray(error.message);
@@ -3450,7 +3563,7 @@ var finalizeBuild_default = (ctx) => {
3450
3563
  return {
3451
3564
  title: `Finalizing build`,
3452
3565
  task: (ctx2, task) => __async(void 0, null, function* () {
3453
- var _a, _b;
3566
+ var _a, _b, _c;
3454
3567
  updateLogContext({ task: "finalizeBuild" });
3455
3568
  try {
3456
3569
  if (ctx2.build.id) {
@@ -3464,11 +3577,11 @@ var finalizeBuild_default = (ctx) => {
3464
3577
  task.output = chalk__default.default.gray(error.message);
3465
3578
  throw new Error("Finalize build failed");
3466
3579
  }
3467
- let buildUrls2 = `build url: ${ctx2.build.url}
3580
+ let buildUrls = `build url: ${ctx2.build.url}
3468
3581
  `;
3469
3582
  if (pingIntervalId !== null) {
3470
3583
  clearInterval(pingIntervalId);
3471
- ctx2.log.debug("Ping polling stopped immediately.");
3584
+ ctx2.log.debug("Ping polling stopped immediately from Finalize Build");
3472
3585
  }
3473
3586
  for (const [sessionId, capabilities] of ctx2.sessionCapabilitiesMap.entries()) {
3474
3587
  try {
@@ -3490,23 +3603,33 @@ var finalizeBuild_default = (ctx) => {
3490
3603
  ctx2.fetchResultsForBuild.push(buildId);
3491
3604
  }
3492
3605
  }
3606
+ ctx2.log.debug(`Capabilities for sessionId ${sessionId}: ${JSON.stringify(capabilities)}`);
3493
3607
  if (buildId && projectToken) {
3494
3608
  yield ctx2.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx2.log);
3609
+ if (ctx2.autoTunnelStarted) {
3610
+ yield startPollingForTunnel(ctx2, buildId, false, projectToken, capabilities == null ? void 0 : capabilities.buildName);
3611
+ }
3495
3612
  }
3496
3613
  if (testId && buildId) {
3497
- buildUrls2 += `TestId ${testId}: ${sessionBuildUrl}
3614
+ buildUrls += `TestId ${testId}: ${sessionBuildUrl}
3498
3615
  `;
3499
3616
  }
3500
3617
  } catch (error) {
3501
3618
  ctx2.log.debug(`Error finalizing build for session ${sessionId}: ${error.message}`);
3502
3619
  }
3503
3620
  }
3504
- task.output = chalk__default.default.gray(buildUrls2);
3621
+ task.output = chalk__default.default.gray(buildUrls);
3505
3622
  task.title = "Finalized build";
3623
+ if (ctx2.tunnelDetails && ctx2.tunnelDetails.tunnelHost != "" && ((_a = ctx2.build) == null ? void 0 : _a.id)) {
3624
+ yield startPollingForTunnel(ctx2, ctx2.build.id, false, "", "");
3625
+ }
3626
+ if (ctx2.autoTunnelStarted && isTunnelPolling === null) {
3627
+ yield stopTunnelHelper(ctx2);
3628
+ }
3506
3629
  try {
3507
- yield (_a = ctx2.browser) == null ? void 0 : _a.close();
3630
+ yield (_b = ctx2.browser) == null ? void 0 : _b.close();
3508
3631
  ctx2.log.debug(`Closed browser`);
3509
- yield (_b = ctx2.server) == null ? void 0 : _b.close();
3632
+ yield (_c = ctx2.server) == null ? void 0 : _c.close();
3510
3633
  ctx2.log.debug(`Closed server`);
3511
3634
  if (ctx2.isSnapshotCaptured) {
3512
3635
  let uploadCLILogsToS3 = ctx2.config.useLambdaInternal || uploadDomToS3ViaEnv2;
@@ -3572,6 +3695,9 @@ function prepareSnapshot(snapshot, ctx) {
3572
3695
  if (options.loadDomContent) {
3573
3696
  processedOptions.loadDomContent = true;
3574
3697
  }
3698
+ if (options.useExtendedViewport) {
3699
+ processedOptions.useExtendedViewport = true;
3700
+ }
3575
3701
  if (options.sessionId) {
3576
3702
  const sessionId = options.sessionId;
3577
3703
  processedOptions.sessionId = sessionId;
@@ -3657,6 +3783,12 @@ function prepareSnapshot(snapshot, ctx) {
3657
3783
  ctx.log.debug(`Tunnel address added to processedOptions: ${tunnelAddress}`);
3658
3784
  }
3659
3785
  }
3786
+ if (ctx.config.loadDomContent) {
3787
+ processedOptions.loadDomContent = true;
3788
+ }
3789
+ if (ctx.config.useExtendedViewport) {
3790
+ processedOptions.useExtendedViewport = true;
3791
+ }
3660
3792
  processedOptions.allowedAssets = ctx.config.allowedAssets;
3661
3793
  processedOptions.selectors = selectors;
3662
3794
  processedOptions.ignoreDOM = options == null ? void 0 : options.ignoreDOM;
@@ -4002,6 +4134,12 @@ function processSnapshot(snapshot, ctx) {
4002
4134
  ctx.log.debug(`Tunnel address added to processedOptions: ${tunnelAddress}`);
4003
4135
  }
4004
4136
  }
4137
+ if (ctx.config.loadDomContent) {
4138
+ processedOptions.loadDomContent = true;
4139
+ }
4140
+ if (ctx.config.useExtendedViewport) {
4141
+ processedOptions.useExtendedViewport = true;
4142
+ }
4005
4143
  let navigated = false;
4006
4144
  let previousDeviceType = null;
4007
4145
  let renderViewports;
@@ -4451,7 +4589,7 @@ var Queue = class {
4451
4589
  }
4452
4590
  processNext() {
4453
4591
  return __async(this, null, function* () {
4454
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
4592
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
4455
4593
  if (!this.isEmpty()) {
4456
4594
  let snapshot;
4457
4595
  if (this.ctx.config.delayedUpload) {
@@ -4540,7 +4678,7 @@ var Queue = class {
4540
4678
  useKafkaFlow: resp.data.useKafkaFlow || false
4541
4679
  };
4542
4680
  } else {
4543
- if (this.ctx.config.tunnel && ((_d = this.ctx.config.tunnel) == null ? void 0 : _d.type) === "auto") {
4681
+ if (this.ctx.autoTunnelStarted) {
4544
4682
  yield stopTunnelHelper(this.ctx);
4545
4683
  }
4546
4684
  throw new Error("SmartUI capabilities are missing in env variables or in driver capabilities");
@@ -4554,7 +4692,7 @@ var Queue = class {
4554
4692
  if (this.ctx.build && this.ctx.build.useKafkaFlow) {
4555
4693
  let snapshotUuid = uuid.v4();
4556
4694
  let snapshotUploadResponse;
4557
- 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))) {
4695
+ 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))) {
4558
4696
  snapshotUuid = snapshot.options.contextId;
4559
4697
  }
4560
4698
  let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv3;
@@ -4580,16 +4718,18 @@ var Queue = class {
4580
4718
  this.ctx.log.debug(`Closed browser context for snapshot ${snapshot.name}`);
4581
4719
  }
4582
4720
  }
4583
- if ((_g = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _g.contextId) {
4584
- (_i = this.ctx.contextToSnapshotMap) == null ? void 0 : _i.set((_h = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _h.contextId, 2);
4721
+ if ((_f = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _f.contextId) {
4722
+ (_h = this.ctx.contextToSnapshotMap) == null ? void 0 : _h.set((_g = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _g.contextId, 2);
4585
4723
  }
4586
4724
  this.processNext();
4587
4725
  } else {
4588
- 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);
4589
- 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))) {
4726
+ let approvalThreshold = ((_i = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _i.approvalThreshold) || this.ctx.config.approvalThreshold;
4727
+ let rejectionThreshold = ((_j = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _j.rejectionThreshold) || this.ctx.config.rejectionThreshold;
4728
+ 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);
4729
+ 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))) {
4590
4730
  this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 1);
4591
4731
  }
4592
- this.ctx.log.debug(`ContextId: ${(_m = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _m.contextId} status set to uploaded`);
4732
+ this.ctx.log.debug(`ContextId: ${(_n = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _n.contextId} status set to uploaded`);
4593
4733
  }
4594
4734
  } else {
4595
4735
  this.ctx.log.info(`Uploading snapshot to S3`);
@@ -4602,7 +4742,7 @@ var Queue = class {
4602
4742
  } catch (error) {
4603
4743
  this.ctx.log.debug(`snapshot failed; ${error}`);
4604
4744
  this.processedSnapshots.push({ name: snapshot == null ? void 0 : snapshot.name, error: error.message });
4605
- if (((_n = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _n.contextId) && this.ctx.contextToSnapshotMap) {
4745
+ if (((_o = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _o.contextId) && this.ctx.contextToSnapshotMap) {
4606
4746
  this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 2);
4607
4747
  }
4608
4748
  }
@@ -4643,6 +4783,7 @@ var startTunnel_default = (ctx) => {
4643
4783
  try {
4644
4784
  yield startTunnelBinary(ctx2);
4645
4785
  ctx2.isStartExec = true;
4786
+ ctx2.autoTunnelStarted = true;
4646
4787
  task.title = "Tunnel Started";
4647
4788
  task.output = chalk__default.default.gray("Tunnel started successfully");
4648
4789
  } catch (error) {
@@ -4673,6 +4814,7 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
4673
4814
  ctx.args.execCommand = execCommand;
4674
4815
  ctx.snapshotQueue = new Queue(ctx);
4675
4816
  ctx.totalSnapshots = 0;
4817
+ ctx.sourceCommand = "exec";
4676
4818
  let tasks = new listr2.Listr(
4677
4819
  [
4678
4820
  authExec_default(),
@@ -5489,7 +5631,8 @@ var uploadWebFigma_default = (ctx) => __async(void 0, null, function* () {
5489
5631
  web: webConfig,
5490
5632
  figma: figmaConfig,
5491
5633
  smartIgnore: ctx.config.smartIgnore,
5492
- git: ctx.git
5634
+ git: ctx.git,
5635
+ markBaseline: ctx.options.markBaseline
5493
5636
  };
5494
5637
  const responseData = yield ctx.client.processWebFigma(requestBody, ctx.log);
5495
5638
  ctx.log.debug("responseData : " + JSON.stringify(responseData));
@@ -5604,7 +5747,8 @@ var uploadAppFigma_default = (ctx) => __async(void 0, null, function* () {
5604
5747
  figma: figmaConfig,
5605
5748
  smartIgnore: ctx.config.smartIgnore,
5606
5749
  git: ctx.git,
5607
- platformType: "app"
5750
+ platformType: "app",
5751
+ markBaseline: ctx.options.markBaseline
5608
5752
  };
5609
5753
  const responseData = yield ctx.client.processWebFigma(requestBody, ctx.log);
5610
5754
  ctx.log.debug("responseData : " + JSON.stringify(responseData));
@@ -5813,6 +5957,7 @@ uploadAppFigmaCommand.name("upload-figma-app").description("Capture figma screen
5813
5957
  var command4 = new commander.Command();
5814
5958
  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() {
5815
5959
  return __async(this, null, function* () {
5960
+ var _a;
5816
5961
  const options = command4.optsWithGlobals();
5817
5962
  if (options.buildName === "") {
5818
5963
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
@@ -5822,11 +5967,13 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5822
5967
  ctx.snapshotQueue = new Queue(ctx);
5823
5968
  ctx.totalSnapshots = 0;
5824
5969
  ctx.isStartExec = true;
5970
+ ctx.sourceCommand = "exec-start";
5825
5971
  let tasks = new listr2.Listr(
5826
5972
  [
5827
5973
  authExec_default(),
5828
5974
  startServer_default(),
5829
5975
  getGitInfo_default(),
5976
+ ...ctx.config.tunnel && ((_a = ctx.config.tunnel) == null ? void 0 : _a.type) === "auto" ? [startTunnel_default()] : [],
5830
5977
  createBuildExec_default()
5831
5978
  ],
5832
5979
  {
@@ -5842,7 +5989,7 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5842
5989
  );
5843
5990
  try {
5844
5991
  yield tasks.run(ctx);
5845
- if (ctx.build && ctx.build.id) {
5992
+ if (ctx.build && ctx.build.id && !ctx.autoTunnelStarted) {
5846
5993
  startPingPolling(ctx);
5847
5994
  }
5848
5995
  if (ctx.options.fetchResults && ctx.build && ctx.build.id) {
@@ -5850,6 +5997,7 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5850
5997
  }
5851
5998
  } catch (error) {
5852
5999
  console.error("Error during server execution:", error);
6000
+ process.exit(1);
5853
6001
  }
5854
6002
  });
5855
6003
  });
@@ -5877,8 +6025,11 @@ command5.name("exec:stop").description("Stop the SmartUI server").action(functio
5877
6025
  console.log(chalk__default.default.red("Failed to stop server"));
5878
6026
  }
5879
6027
  } catch (error) {
5880
- if (error.code === "ECONNABORTED") {
6028
+ if (error && error.code === "ECONNABORTED") {
5881
6029
  console.error(chalk__default.default.red("Error: SmartUI server did not respond in 15 seconds"));
6030
+ }
6031
+ if (error && error.code === "ECONNREFUSED") {
6032
+ console.error(chalk__default.default.red("Error: Looks like smartui cli server is already stopped"));
5882
6033
  } else {
5883
6034
  console.error(chalk__default.default.red("Error while stopping server"));
5884
6035
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.30",
3
+ "version": "4.1.32",
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
  },