@lambdatest/smartui-cli 4.1.25 → 4.1.27

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 +205 -18
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1012,6 +1012,18 @@ var SnapshotSchema = {
1012
1012
  sessionId: {
1013
1013
  type: "string",
1014
1014
  errorMessage: "Invalid snapshot options; sessionId must be a string"
1015
+ },
1016
+ contextId: {
1017
+ type: "string",
1018
+ errorMessage: "Invalid snapshot options; contextId must be a string"
1019
+ },
1020
+ sync: {
1021
+ type: "boolean",
1022
+ errorMessage: "Invalid snapshot options; sync must be a boolean"
1023
+ },
1024
+ timeout: {
1025
+ type: "number",
1026
+ errorMessage: "Invalid snapshot options; timeout must be a number"
1015
1027
  }
1016
1028
  },
1017
1029
  additionalProperties: false
@@ -1674,8 +1686,39 @@ function stopTunnelHelper(ctx) {
1674
1686
  ctx.log.debug("Tunnel is Stopped ? " + status);
1675
1687
  });
1676
1688
  }
1689
+ function calculateVariantCount(config) {
1690
+ let variantCount = 0;
1691
+ if (config.web) {
1692
+ const browsers = config.web.browsers || [];
1693
+ const viewports = config.web.viewports || [];
1694
+ variantCount += browsers.length * viewports.length;
1695
+ }
1696
+ if (config.mobile) {
1697
+ const devices = config.mobile.devices || [];
1698
+ variantCount += devices.length;
1699
+ }
1700
+ return variantCount;
1701
+ }
1702
+ function calculateVariantCountFromSnapshot(snapshot, globalConfig) {
1703
+ var _a, _b;
1704
+ let variantCount = 0;
1705
+ if ((_a = snapshot.options) == null ? void 0 : _a.web) {
1706
+ const browsers = snapshot.options.web.browsers || [];
1707
+ const viewports = snapshot.options.web.viewports || [];
1708
+ variantCount += browsers.length * viewports.length;
1709
+ }
1710
+ if ((_b = snapshot.options) == null ? void 0 : _b.mobile) {
1711
+ const devices = snapshot.options.mobile.devices || [];
1712
+ variantCount += devices.length;
1713
+ }
1714
+ if (variantCount === 0 && globalConfig) {
1715
+ variantCount = calculateVariantCount(globalConfig);
1716
+ }
1717
+ return variantCount;
1718
+ }
1677
1719
 
1678
1720
  // src/lib/server.ts
1721
+ var uploadDomToS3ViaEnv = process.env.USE_LAMBDA_INTERNAL || false;
1679
1722
  var server_default = (ctx) => __async(void 0, null, function* () {
1680
1723
  const server = fastify__default.default({
1681
1724
  logger: {
@@ -1695,7 +1738,7 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1695
1738
  reply.code(200).send({ data: { dom: SMARTUI_DOM } });
1696
1739
  });
1697
1740
  server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
1698
- var _a, _b, _c;
1741
+ var _a, _b, _c, _d, _e;
1699
1742
  let replyCode;
1700
1743
  let replyBody;
1701
1744
  try {
@@ -1704,8 +1747,9 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1704
1747
  throw new Error(validateSnapshot.errors[0].message);
1705
1748
  const sessionId = (_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.sessionId;
1706
1749
  let capsBuildId = "";
1750
+ const contextId = (_b = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _b.contextId;
1707
1751
  if (sessionId) {
1708
- if ((_b = ctx.sessionCapabilitiesMap) == null ? void 0 : _b.has(sessionId)) {
1752
+ if ((_c = ctx.sessionCapabilitiesMap) == null ? void 0 : _c.has(sessionId)) {
1709
1753
  const cachedCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
1710
1754
  capsBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
1711
1755
  } else {
@@ -1728,7 +1772,19 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1728
1772
  }
1729
1773
  }
1730
1774
  ctx.testType = testType;
1731
- (_c = ctx.snapshotQueue) == null ? void 0 : _c.enqueue(snapshot);
1775
+ if (contextId && !ctx.contextToSnapshotMap) {
1776
+ ctx.contextToSnapshotMap = /* @__PURE__ */ new Map();
1777
+ ctx.log.debug(`Initialized empty context mapping map for contextId: ${contextId}`);
1778
+ }
1779
+ if (contextId && ctx.contextToSnapshotMap) {
1780
+ ctx.contextToSnapshotMap.set(contextId, 0);
1781
+ ctx.log.debug(`Marking contextId as captured and added to queue: ${contextId}`);
1782
+ }
1783
+ if (contextId) {
1784
+ (_d = ctx.snapshotQueue) == null ? void 0 : _d.enqueueFront(snapshot);
1785
+ } else {
1786
+ (_e = ctx.snapshotQueue) == null ? void 0 : _e.enqueue(snapshot);
1787
+ }
1732
1788
  ctx.isSnapshotCaptured = true;
1733
1789
  replyCode = 200;
1734
1790
  replyBody = { data: { message: "success", warnings: [] } };
@@ -1740,7 +1796,7 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1740
1796
  return reply.code(replyCode).send(replyBody);
1741
1797
  }));
1742
1798
  server.post("/stop", opts, (_, reply) => __async(void 0, null, function* () {
1743
- var _a, _b;
1799
+ var _a, _b, _c;
1744
1800
  let replyCode;
1745
1801
  let replyBody;
1746
1802
  try {
@@ -1762,8 +1818,14 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1762
1818
  if (ctx.server) {
1763
1819
  ctx.server.close();
1764
1820
  }
1765
- let resp = yield ctx.client.getS3PreSignedURL(ctx);
1766
- yield ctx.client.uploadLogs(ctx, resp.data.url);
1821
+ let uploadCLILogsToS3 = ((_c = ctx == null ? void 0 : ctx.config) == null ? void 0 : _c.useLambdaInternal) || uploadDomToS3ViaEnv;
1822
+ if (!uploadCLILogsToS3) {
1823
+ ctx.log.debug(`Log file to be uploaded`);
1824
+ let resp = yield ctx.client.getS3PreSignedURL(ctx);
1825
+ yield ctx.client.uploadLogs(ctx, resp.data.url);
1826
+ } else {
1827
+ ctx.log.debug(`Skipping upload of CLI logs as useLambdaInternal is set`);
1828
+ }
1767
1829
  if (pingIntervalId !== null) {
1768
1830
  clearInterval(pingIntervalId);
1769
1831
  ctx.log.debug("Ping polling stopped immediately.");
@@ -1781,6 +1843,93 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1781
1843
  server.get("/ping", opts, (_, reply) => {
1782
1844
  reply.code(200).send({ status: "Server is running", version: ctx.cliVersion });
1783
1845
  });
1846
+ server.get("/snapshot/status", opts, (request, reply) => __async(void 0, null, function* () {
1847
+ var _a;
1848
+ let replyCode;
1849
+ let replyBody;
1850
+ try {
1851
+ ctx.log.debug(`request.query : ${JSON.stringify(request.query)}`);
1852
+ const { contextId, pollTimeout, snapshotName } = request.query;
1853
+ if (!contextId || !snapshotName) {
1854
+ throw new Error("contextId and snapshotName are required parameters");
1855
+ }
1856
+ const timeoutDuration = pollTimeout * 1e3 || 3e4;
1857
+ if ((_a = ctx.contextToSnapshotMap) == null ? void 0 : _a.has(contextId)) {
1858
+ let contextStatus = ctx.contextToSnapshotMap.get(contextId);
1859
+ while (contextStatus == 0) {
1860
+ yield new Promise((resolve) => setTimeout(resolve, 5e3));
1861
+ contextStatus = ctx.contextToSnapshotMap.get(contextId);
1862
+ }
1863
+ if (contextStatus == 2) {
1864
+ throw new Error("Snapshot Failed");
1865
+ }
1866
+ ctx.log.debug("Snapshot uploaded successfully");
1867
+ let lastExternalResponse = null;
1868
+ const startTime = Date.now();
1869
+ while (true) {
1870
+ try {
1871
+ const externalResponse = yield ctx.client.getSnapshotStatus(
1872
+ snapshotName,
1873
+ contextId,
1874
+ ctx
1875
+ );
1876
+ lastExternalResponse = externalResponse;
1877
+ if (externalResponse.statusCode === 200) {
1878
+ replyCode = 200;
1879
+ replyBody = externalResponse.data;
1880
+ return reply.code(replyCode).send(replyBody);
1881
+ } else if (externalResponse.statusCode === 202) {
1882
+ replyBody = externalResponse.data;
1883
+ ctx.log.debug(`External API attempt: Still processing, Pending Screenshots ${externalResponse.snapshotCount}`);
1884
+ yield new Promise((resolve) => setTimeout(resolve, 5e3));
1885
+ } else if (externalResponse.statusCode === 404) {
1886
+ ctx.log.debug(`Snapshot still processing, not uploaded`);
1887
+ yield new Promise((resolve) => setTimeout(resolve, 5e3));
1888
+ } else {
1889
+ ctx.log.debug(`Unexpected response from external API: ${JSON.stringify(externalResponse)}`);
1890
+ replyCode = 500;
1891
+ replyBody = {
1892
+ error: {
1893
+ message: `Unexpected response from external API: ${externalResponse.statusCode}`,
1894
+ externalApiStatus: externalResponse.statusCode
1895
+ }
1896
+ };
1897
+ return reply.code(replyCode).send(replyBody);
1898
+ }
1899
+ ctx.log.debug(`timeoutDuration: ${timeoutDuration}`);
1900
+ ctx.log.debug(`Time passed: ${Date.now() - startTime}`);
1901
+ if (Date.now() - startTime > timeoutDuration) {
1902
+ replyCode = 202;
1903
+ replyBody = {
1904
+ data: {
1905
+ message: "Request timed out-> Snapshot still processing"
1906
+ }
1907
+ };
1908
+ return reply.code(replyCode).send(replyBody);
1909
+ }
1910
+ } catch (externalApiError) {
1911
+ ctx.log.debug(`External API call failed: ${externalApiError.message}`);
1912
+ replyCode = 500;
1913
+ replyBody = {
1914
+ error: {
1915
+ message: `External API call failed: ${externalApiError.message}`
1916
+ }
1917
+ };
1918
+ return reply.code(replyCode).send(replyBody);
1919
+ }
1920
+ }
1921
+ } else {
1922
+ replyCode = 404;
1923
+ replyBody = { error: { message: `No snapshot found for contextId: ${contextId}` } };
1924
+ return reply.code(replyCode).send(replyBody);
1925
+ }
1926
+ } catch (error) {
1927
+ ctx.log.debug(`snapshot status failed; ${error}`);
1928
+ replyCode = 500;
1929
+ replyBody = { error: { message: error.message } };
1930
+ return reply.code(replyCode).send(replyBody);
1931
+ }
1932
+ }));
1784
1933
  yield server.listen({ port: ctx.options.port });
1785
1934
  let { port } = server.addresses()[0];
1786
1935
  process.env.SMARTUI_SERVER_ADDRESS = `http://localhost:${port}`;
@@ -1927,7 +2076,7 @@ var authExec_default = (ctx) => {
1927
2076
  };
1928
2077
 
1929
2078
  // package.json
1930
- var version = "4.1.25";
2079
+ var version = "4.1.27";
1931
2080
  var package_default = {
1932
2081
  name: "@lambdatest/smartui-cli",
1933
2082
  version,
@@ -2268,7 +2417,7 @@ var httpClient = class {
2268
2417
  }
2269
2418
  }, ctx.log);
2270
2419
  }
2271
- processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors) {
2420
+ processSnapshot(ctx, snapshot, snapshotUuid, discoveryErrors, variantCount, sync = false) {
2272
2421
  return this.request({
2273
2422
  url: `/build/${ctx.build.id}/snapshot`,
2274
2423
  method: "POST",
@@ -2277,12 +2426,14 @@ var httpClient = class {
2277
2426
  name: snapshot.name,
2278
2427
  url: snapshot.url,
2279
2428
  snapshotUuid,
2429
+ variantCount,
2280
2430
  test: {
2281
2431
  type: ctx.testType,
2282
2432
  source: "cli"
2283
2433
  },
2284
2434
  doRemoteDiscovery: snapshot.options.doRemoteDiscovery,
2285
- discoveryErrors
2435
+ discoveryErrors,
2436
+ sync
2286
2437
  }
2287
2438
  }, ctx.log);
2288
2439
  }
@@ -2546,6 +2697,15 @@ var httpClient = class {
2546
2697
  data: requestData
2547
2698
  }, ctx.log);
2548
2699
  }
2700
+ getSnapshotStatus(snapshotName, snapshotUuid, ctx) {
2701
+ return this.request({
2702
+ url: `/snapshot/status?buildId=${ctx.build.id}&snapshotName=${snapshotName}&snapshotUUID=${snapshotUuid}`,
2703
+ method: "GET",
2704
+ headers: {
2705
+ "Content-Type": "application/json"
2706
+ }
2707
+ }, ctx.log);
2708
+ }
2549
2709
  };
2550
2710
  var ctx_default = (options) => {
2551
2711
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
@@ -2633,6 +2793,9 @@ var ctx_default = (options) => {
2633
2793
  if (config.useLambdaInternal) {
2634
2794
  useLambdaInternal = true;
2635
2795
  }
2796
+ if (config.waitForPageRender && config.waitForPageRender < 3e4) {
2797
+ config.waitForPageRender = 3e4;
2798
+ }
2636
2799
  return {
2637
2800
  env,
2638
2801
  log: logger_default,
@@ -2978,7 +3141,7 @@ ${snapshot.warnings.length ? chalk__default.default.gray(`[warning] ${snapshot.w
2978
3141
  rendererOptions: { persistentOutput: true }
2979
3142
  };
2980
3143
  };
2981
- var uploadDomToS3ViaEnv = process.env.USE_LAMBDA_INTERNAL || false;
3144
+ var uploadDomToS3ViaEnv2 = process.env.USE_LAMBDA_INTERNAL || false;
2982
3145
  var finalizeBuild_default = (ctx) => {
2983
3146
  return {
2984
3147
  title: `Finalizing build`,
@@ -3043,7 +3206,7 @@ var finalizeBuild_default = (ctx) => {
3043
3206
  yield (_b = ctx2.server) == null ? void 0 : _b.close();
3044
3207
  ctx2.log.debug(`Closed server`);
3045
3208
  if (ctx2.isSnapshotCaptured) {
3046
- let uploadCLILogsToS3 = ctx2.config.useLambdaInternal || uploadDomToS3ViaEnv;
3209
+ let uploadCLILogsToS3 = ctx2.config.useLambdaInternal || uploadDomToS3ViaEnv2;
3047
3210
  if (!uploadCLILogsToS3) {
3048
3211
  ctx2.log.debug(`Log file to be uploaded`);
3049
3212
  let resp = yield ctx2.client.getS3PreSignedURL(ctx2);
@@ -3715,7 +3878,7 @@ function processSnapshot(snapshot, ctx) {
3715
3878
  };
3716
3879
  });
3717
3880
  }
3718
- var uploadDomToS3ViaEnv2 = process.env.USE_LAMBDA_INTERNAL || false;
3881
+ var uploadDomToS3ViaEnv3 = process.env.USE_LAMBDA_INTERNAL || false;
3719
3882
  var Queue = class {
3720
3883
  constructor(ctx) {
3721
3884
  this.snapshots = [];
@@ -3735,6 +3898,15 @@ var Queue = class {
3735
3898
  }
3736
3899
  }
3737
3900
  }
3901
+ enqueueFront(item) {
3902
+ this.snapshots.unshift(item);
3903
+ if (!this.ctx.config.delayedUpload) {
3904
+ if (!this.processing) {
3905
+ this.processing = true;
3906
+ this.processNext();
3907
+ }
3908
+ }
3909
+ }
3738
3910
  startProcessingfunc() {
3739
3911
  if (!this.processing) {
3740
3912
  this.processing = true;
@@ -3928,7 +4100,7 @@ var Queue = class {
3928
4100
  }
3929
4101
  processNext() {
3930
4102
  return __async(this, null, function* () {
3931
- var _a, _b, _c, _d;
4103
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
3932
4104
  if (!this.isEmpty()) {
3933
4105
  let snapshot;
3934
4106
  if (this.ctx.config.delayedUpload) {
@@ -3944,7 +4116,7 @@ var Queue = class {
3944
4116
  }
3945
4117
  if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name) && !this.ctx.config.allowDuplicateSnapshotNames) {
3946
4118
  drop = true;
3947
- this.ctx.log.info(`Skipping duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'delayedUpload' configuration as true in your config file.`);
4119
+ this.ctx.log.info(`Skipping duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'allowDuplicateSnapshotNames' or 'delayedUpload' configuration as true in your config file.`);
3948
4120
  }
3949
4121
  if (this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {
3950
4122
  drop = this.filterExistingVariants(snapshot, this.ctx.config);
@@ -3984,9 +4156,10 @@ var Queue = class {
3984
4156
  discoveryErrors = result.discoveryErrors;
3985
4157
  }
3986
4158
  if (useCapsBuildId) {
4159
+ this.ctx.log.info(`Using cached buildId: ${capsBuildId}`);
3987
4160
  if (useKafkaFlowCaps) {
3988
4161
  const snapshotUuid = uuid.v4();
3989
- let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv2;
4162
+ let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv3;
3990
4163
  if (!uploadDomToS3) {
3991
4164
  this.ctx.log.debug(`Uploading dom to S3 for snapshot using presigned URL for CAPS`);
3992
4165
  const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUploadCaps(this.ctx, processedSnapshot.name, snapshotUuid, capsBuildId, capsProjectToken);
@@ -4028,9 +4201,12 @@ var Queue = class {
4028
4201
  }
4029
4202
  }
4030
4203
  if (this.ctx.build && this.ctx.build.useKafkaFlow) {
4031
- const snapshotUuid = uuid.v4();
4204
+ let snapshotUuid = uuid.v4();
4032
4205
  let snapshotUploadResponse;
4033
- let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv2;
4206
+ 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))) {
4207
+ snapshotUuid = snapshot.options.contextId;
4208
+ }
4209
+ let uploadDomToS3 = this.ctx.config.useLambdaInternal || uploadDomToS3ViaEnv3;
4034
4210
  if (!uploadDomToS3) {
4035
4211
  this.ctx.log.debug(`Uploading dom to S3 for snapshot using presigned URL`);
4036
4212
  const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUpload(this.ctx, processedSnapshot.name, snapshotUuid);
@@ -4053,11 +4229,19 @@ var Queue = class {
4053
4229
  this.ctx.log.debug(`Closed browser context for snapshot ${snapshot.name}`);
4054
4230
  }
4055
4231
  }
4232
+ if ((_g = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _g.contextId) {
4233
+ (_i = this.ctx.contextToSnapshotMap) == null ? void 0 : _i.set((_h = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _h.contextId, 2);
4234
+ }
4056
4235
  this.processNext();
4057
4236
  } else {
4058
- yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid, discoveryErrors);
4237
+ 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);
4238
+ 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))) {
4239
+ this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 1);
4240
+ }
4241
+ this.ctx.log.debug(`ContextId: ${(_m = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _m.contextId} status set to uploaded`);
4059
4242
  }
4060
4243
  } else {
4244
+ this.ctx.log.info(`Uploading snapshot to S3`);
4061
4245
  yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot, discoveryErrors);
4062
4246
  }
4063
4247
  this.ctx.totalSnapshots++;
@@ -4067,6 +4251,9 @@ var Queue = class {
4067
4251
  } catch (error) {
4068
4252
  this.ctx.log.debug(`snapshot failed; ${error}`);
4069
4253
  this.processedSnapshots.push({ name: snapshot == null ? void 0 : snapshot.name, error: error.message });
4254
+ if (((_n = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _n.contextId) && this.ctx.contextToSnapshotMap) {
4255
+ this.ctx.contextToSnapshotMap.set(snapshot.options.contextId, 2);
4256
+ }
4070
4257
  }
4071
4258
  if (this.ctx.browser) {
4072
4259
  for (let context of this.ctx.browser.contexts()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.25",
3
+ "version": "4.1.27",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"