@lambdatest/smartui-cli 4.1.2 → 4.1.3-beta.0

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 +371 -76
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -625,6 +625,10 @@ var ConfigSchema = {
625
625
  useGlobalCache: {
626
626
  type: "boolean",
627
627
  errorMessage: "Invalid config; useGlobalCache must be true/false"
628
+ },
629
+ skipBuildCreation: {
630
+ type: "boolean",
631
+ errorMessage: "Invalid config; skipBuildCreation must be true/false"
628
632
  }
629
633
  },
630
634
  anyOf: [
@@ -845,6 +849,10 @@ var SnapshotSchema = {
845
849
  loadDomContent: {
846
850
  type: "boolean",
847
851
  errorMessage: "Invalid snapshot options; loadDomContent must be a boolean"
852
+ },
853
+ sessionId: {
854
+ type: "string",
855
+ errorMessage: "Invalid snapshot options; sessionId must be a string"
848
856
  }
849
857
  },
850
858
  additionalProperties: false
@@ -992,7 +1000,6 @@ var validateSnapshot = ajv.compile(SnapshotSchema);
992
1000
  var validateFigmaDesignConfig = ajv.compile(FigmaDesignConfigSchema);
993
1001
  var validateWebFigmaConfig = ajv.compile(FigmaWebConfigSchema);
994
1002
  util.promisify(setTimeout);
995
- var isPollingActive = false;
996
1003
  function delDir(dir) {
997
1004
  if (fs5__default.default.existsSync(dir)) {
998
1005
  fs5__default.default.rmSync(dir, { recursive: true });
@@ -1170,38 +1177,37 @@ function getRenderViewportsForOptions(options) {
1170
1177
  ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1171
1178
  ];
1172
1179
  }
1173
- process.on("SIGINT", () => __async(void 0, null, function* () {
1174
- if (isPollingActive) {
1175
- console.log("Fetching results interrupted. Exiting...");
1176
- isPollingActive = false;
1177
- } else {
1178
- console.log("\nExiting gracefully...");
1179
- }
1180
- process.exit(0);
1181
- }));
1182
- function startPolling(ctx) {
1180
+ function startPolling(ctx, build_id, baseline, projectToken) {
1183
1181
  return __async(this, null, function* () {
1184
- ctx.log.info("Fetching results in progress....");
1185
- ctx.log.debug(ctx.build);
1186
- isPollingActive = true;
1182
+ if (build_id) {
1183
+ ctx.log.info(`Fetching results for buildId ${build_id} in progress....`);
1184
+ } else if (ctx.build && ctx.build.id) {
1185
+ ctx.log.info(`Fetching results for buildId ${ctx.build.id} in progress....`);
1186
+ }
1187
1187
  const intervalId = setInterval(() => __async(this, null, function* () {
1188
- if (!isPollingActive) {
1189
- clearInterval(intervalId);
1190
- return;
1191
- }
1192
1188
  try {
1193
- const resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline || false, ctx.log);
1189
+ let resp;
1190
+ if (build_id) {
1191
+ resp = yield ctx.client.getScreenshotData(build_id, baseline, ctx.log, projectToken);
1192
+ } else if (ctx.build && ctx.build.id) {
1193
+ resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log, "");
1194
+ } else {
1195
+ return;
1196
+ }
1194
1197
  if (!resp.build) {
1195
1198
  ctx.log.info("Error: Build data is null.");
1196
1199
  clearInterval(intervalId);
1197
- isPollingActive = false;
1200
+ return;
1201
+ }
1202
+ let fileName = `${resp.build.build_id}.json`;
1203
+ if (ctx.options.fetchResults && ctx.options.fetchResultsFileName && ctx.build && ctx.build.id && resp.build.build_id === ctx.build.id) {
1204
+ fileName = `${ctx.options.fetchResultsFileName}`;
1198
1205
  }
1199
- fs5__default.default.writeFileSync(ctx.options.fetchResultsFileName, JSON.stringify(resp, null, 2));
1200
- ctx.log.debug(`Updated results in ${ctx.options.fetchResultsFileName}`);
1206
+ fs5__default.default.writeFileSync(`${fileName}`, JSON.stringify(resp, null, 2));
1207
+ ctx.log.debug(`Updated results in ${fileName}`);
1201
1208
  if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1202
1209
  clearInterval(intervalId);
1203
- ctx.log.info(`Fetching results completed. Final results written to ${ctx.options.fetchResultsFileName}`);
1204
- isPollingActive = false;
1210
+ ctx.log.info(`Fetching results completed. Final results written to ${fileName}`);
1205
1211
  let totalScreenshotsWithMismatches = 0;
1206
1212
  let totalVariantsWithMismatches = 0;
1207
1213
  const totalScreenshots = Object.keys(resp.screenshots || {}).length;
@@ -1224,7 +1230,7 @@ function startPolling(ctx) {
1224
1230
  ctx.log.info(
1225
1231
  chalk__default.default.green.bold(
1226
1232
  `
1227
- Summary of Mismatches:
1233
+ Summary of Mismatches for buildId: ${build_id}
1228
1234
  ${chalk__default.default.yellow("Total Variants with Mismatches:")} ${chalk__default.default.white(totalVariantsWithMismatches)} out of ${chalk__default.default.white(totalVariants)}
1229
1235
  ${chalk__default.default.yellow("Total Screenshots with Mismatches:")} ${chalk__default.default.white(totalScreenshotsWithMismatches)} out of ${chalk__default.default.white(totalScreenshots)}
1230
1236
  ${chalk__default.default.yellow("Branch Name:")} ${chalk__default.default.white(resp.build.branch)}
@@ -1242,7 +1248,6 @@ ${chalk__default.default.yellow("Build ID:")} ${chalk__default.default.white(res
1242
1248
  ctx.log.error(`Error fetching screenshot data: ${error.message}`);
1243
1249
  }
1244
1250
  clearInterval(intervalId);
1245
- isPollingActive = false;
1246
1251
  }
1247
1252
  }), 5e3);
1248
1253
  });
@@ -1289,15 +1294,37 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1289
1294
  reply.code(200).send({ data: { dom: SMARTUI_DOM } });
1290
1295
  });
1291
1296
  server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
1292
- var _a;
1297
+ var _a, _b, _c;
1293
1298
  let replyCode;
1294
1299
  let replyBody;
1295
1300
  try {
1296
1301
  let { snapshot, testType } = request.body;
1297
1302
  if (!validateSnapshot(snapshot))
1298
1303
  throw new Error(validateSnapshot.errors[0].message);
1304
+ const sessionId = (_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.sessionId;
1305
+ let capsBuildId = "";
1306
+ if (sessionId) {
1307
+ if ((_b = ctx.sessionCapabilitiesMap) == null ? void 0 : _b.has(sessionId)) {
1308
+ const cachedCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
1309
+ capsBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
1310
+ } else {
1311
+ try {
1312
+ let fetchedCapabilitiesResp = yield ctx.client.getSmartUICapabilities(sessionId, ctx.config, ctx.git, ctx.log);
1313
+ capsBuildId = (fetchedCapabilitiesResp == null ? void 0 : fetchedCapabilitiesResp.buildId) || "";
1314
+ ctx.log.debug(`fetch caps for sessionId: ${sessionId} are ${JSON.stringify(fetchedCapabilitiesResp)}`);
1315
+ if (capsBuildId) {
1316
+ ctx.sessionCapabilitiesMap.set(sessionId, fetchedCapabilitiesResp);
1317
+ } else if (fetchedCapabilitiesResp && (fetchedCapabilitiesResp == null ? void 0 : fetchedCapabilitiesResp.sessionId)) {
1318
+ ctx.sessionCapabilitiesMap.set(sessionId, fetchedCapabilitiesResp);
1319
+ }
1320
+ } catch (error) {
1321
+ ctx.log.debug(`Failed to fetch capabilities for sessionId ${sessionId}: ${error.message}`);
1322
+ console.log(`Failed to fetch capabilities for sessionId ${sessionId}: ${error.message}`);
1323
+ }
1324
+ }
1325
+ }
1299
1326
  ctx.testType = testType;
1300
- (_a = ctx.snapshotQueue) == null ? void 0 : _a.enqueue(snapshot);
1327
+ (_c = ctx.snapshotQueue) == null ? void 0 : _c.enqueue(snapshot);
1301
1328
  ctx.isSnapshotCaptured = true;
1302
1329
  replyCode = 200;
1303
1330
  replyBody = { data: { message: "success", warnings: [] } };
@@ -1457,21 +1484,28 @@ var startServer_default = (ctx) => {
1457
1484
  rendererOptions: { persistentOutput: true }
1458
1485
  };
1459
1486
  };
1460
- var auth_default = (ctx) => {
1487
+ var authExec_default = (ctx) => {
1461
1488
  return {
1462
1489
  title: `Authenticating with SmartUI`,
1463
1490
  task: (ctx2, task) => __async(void 0, null, function* () {
1464
1491
  updateLogContext({ task: "auth" });
1465
1492
  try {
1466
- const authResult = yield ctx2.client.auth(ctx2.log, ctx2.env);
1467
- if (authResult === 2) {
1468
- task.output = chalk__default.default.gray(`New project '${ctx2.env.PROJECT_NAME}' created successfully`);
1469
- } else if (authResult === 0) {
1470
- task.output = chalk__default.default.gray(`Using existing project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
1471
- } else if (authResult === 1) {
1472
- task.output = chalk__default.default.gray(`Using existing project '${ctx2.env.PROJECT_NAME}'`);
1493
+ if (!ctx2.env.PROJECT_NAME && !ctx2.env.PROJECT_TOKEN) {
1494
+ ctx2.authenticatedInitially = false;
1495
+ task.output = chalk__default.default.gray(`Empty PROJECT_TOKEN and PROJECT_NAME. Skipping authentication. Expecting SmartUI Capabilities in driver!`);
1496
+ task.title = "Skipped Authentication with SmartUI";
1497
+ } else {
1498
+ const authResult = yield ctx2.client.auth(ctx2.log, ctx2.env);
1499
+ if (authResult === 2) {
1500
+ task.output = chalk__default.default.gray(`New project '${ctx2.env.PROJECT_NAME}' created successfully`);
1501
+ } else if (authResult === 0) {
1502
+ task.output = chalk__default.default.gray(`Using existing project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
1503
+ } else if (authResult === 1) {
1504
+ task.output = chalk__default.default.gray(`Using existing project '${ctx2.env.PROJECT_NAME}'`);
1505
+ }
1506
+ ctx2.authenticatedInitially = true;
1507
+ task.title = "Authenticated with SmartUI";
1473
1508
  }
1474
- task.title = "Authenticated with SmartUI";
1475
1509
  } catch (error) {
1476
1510
  ctx2.log.debug(error);
1477
1511
  task.output = chalk__default.default.gray(error.message);
@@ -1483,7 +1517,7 @@ var auth_default = (ctx) => {
1483
1517
  };
1484
1518
 
1485
1519
  // package.json
1486
- var version = "4.1.2";
1520
+ var version = "4.1.3-beta.0";
1487
1521
  var package_default = {
1488
1522
  name: "@lambdatest/smartui-cli",
1489
1523
  version,
@@ -1563,7 +1597,9 @@ var httpClient = class {
1563
1597
  }
1564
1598
  this.axiosInstance = axios__default.default.create(axiosConfig);
1565
1599
  this.axiosInstance.interceptors.request.use((config) => {
1566
- config.headers["projectToken"] = this.projectToken;
1600
+ if (!config.headers["projectToken"]) {
1601
+ config.headers["projectToken"] = this.projectToken;
1602
+ }
1567
1603
  config.headers["projectName"] = this.projectName;
1568
1604
  config.headers["username"] = this.username;
1569
1605
  config.headers["accessKey"] = this.accessKey;
@@ -1661,11 +1697,12 @@ var httpClient = class {
1661
1697
  }
1662
1698
  }, log2);
1663
1699
  }
1664
- getScreenshotData(buildId, baseline, log2) {
1700
+ getScreenshotData(buildId, baseline, log2, projectToken) {
1665
1701
  return this.request({
1666
1702
  url: "/screenshot",
1667
1703
  method: "GET",
1668
- params: { buildId, baseline }
1704
+ params: { buildId, baseline },
1705
+ headers: { projectToken }
1669
1706
  }, log2);
1670
1707
  }
1671
1708
  ping(buildId, log2) {
@@ -1677,6 +1714,25 @@ var httpClient = class {
1677
1714
  }
1678
1715
  }, log2);
1679
1716
  }
1717
+ getSmartUICapabilities(sessionId, config, git, log2) {
1718
+ return this.request({
1719
+ url: "/sessions/capabilities",
1720
+ method: "GET",
1721
+ params: {
1722
+ sessionId
1723
+ },
1724
+ data: {
1725
+ git,
1726
+ config
1727
+ },
1728
+ headers: {
1729
+ projectToken: "",
1730
+ projectName: "",
1731
+ username: "",
1732
+ accessKey: ""
1733
+ }
1734
+ }, log2);
1735
+ }
1680
1736
  finalizeBuild(buildId, totalSnapshots, log2) {
1681
1737
  let params = { buildId };
1682
1738
  if (totalSnapshots > -1)
@@ -1687,6 +1743,20 @@ var httpClient = class {
1687
1743
  params
1688
1744
  }, log2);
1689
1745
  }
1746
+ finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, log2) {
1747
+ let params = { buildId };
1748
+ if (totalSnapshots > -1)
1749
+ params.totalSnapshots = totalSnapshots;
1750
+ return this.request({
1751
+ url: "/build",
1752
+ method: "DELETE",
1753
+ params,
1754
+ headers: {
1755
+ projectToken
1756
+ // Use projectToken dynamically
1757
+ }
1758
+ }, log2);
1759
+ }
1690
1760
  uploadSnapshot(ctx, snapshot) {
1691
1761
  return this.request({
1692
1762
  url: `/builds/${ctx.build.id}/snapshot`,
@@ -1718,6 +1788,45 @@ var httpClient = class {
1718
1788
  }
1719
1789
  }, ctx.log);
1720
1790
  }
1791
+ processSnapshotCaps(ctx, snapshot, snapshotUuid, capsBuildId, capsProjectToken) {
1792
+ return this.request({
1793
+ url: `/build/${capsBuildId}/snapshot`,
1794
+ method: "POST",
1795
+ headers: {
1796
+ "Content-Type": "application/json",
1797
+ projectToken: capsProjectToken !== "" ? capsProjectToken : this.projectToken
1798
+ },
1799
+ data: {
1800
+ name: snapshot.name,
1801
+ url: snapshot.url,
1802
+ snapshotUuid,
1803
+ test: {
1804
+ type: ctx.testType,
1805
+ source: "cli"
1806
+ },
1807
+ async: false
1808
+ }
1809
+ }, ctx.log);
1810
+ }
1811
+ uploadSnapshotForCaps(ctx, snapshot, capsBuildId, capsProjectToken) {
1812
+ const buildId = capsBuildId !== "" ? capsBuildId : ctx.build.id;
1813
+ return this.request({
1814
+ url: `/builds/${buildId}/snapshot`,
1815
+ method: "POST",
1816
+ headers: {
1817
+ "Content-Type": "application/json",
1818
+ projectToken: capsProjectToken !== "" ? capsProjectToken : this.projectToken
1819
+ // Use capsProjectToken dynamically
1820
+ },
1821
+ data: {
1822
+ snapshot,
1823
+ test: {
1824
+ type: ctx.testType,
1825
+ source: "cli"
1826
+ }
1827
+ }
1828
+ }, ctx.log);
1829
+ }
1721
1830
  uploadScreenshot({ id: buildId, name: buildName, baseline }, ssPath, ssName, browserName, viewport, log2) {
1722
1831
  browserName = browserName === constants_default.SAFARI ? constants_default.WEBKIT : browserName;
1723
1832
  const file = fs5__default.default.readFileSync(ssPath);
@@ -1799,6 +1908,21 @@ var httpClient = class {
1799
1908
  }
1800
1909
  }, ctx.log);
1801
1910
  }
1911
+ getS3PresignedURLForSnapshotUploadCaps(ctx, snapshotName, snapshotUuid, capsBuildId, capsProjectToken) {
1912
+ return this.request({
1913
+ url: `/snapshotuploadurl`,
1914
+ method: "POST",
1915
+ headers: {
1916
+ "Content-Type": "application/json",
1917
+ projectToken: capsProjectToken !== "" ? capsProjectToken : this.projectToken
1918
+ },
1919
+ data: {
1920
+ buildId: capsBuildId,
1921
+ snapshotName,
1922
+ snapshotUuid
1923
+ }
1924
+ }, ctx.log);
1925
+ }
1802
1926
  uploadLogs(ctx, uploadURL) {
1803
1927
  const fileStream = fs5__default.default.createReadStream(constants_default.LOG_FILE_PATH);
1804
1928
  const { size } = fs5__default.default.statSync(constants_default.LOG_FILE_PATH);
@@ -1830,6 +1954,21 @@ var httpClient = class {
1830
1954
  // prevent axios from limiting the content size
1831
1955
  }, ctx.log);
1832
1956
  }
1957
+ uploadSnapshotToS3Caps(ctx, uploadURL, snapshot, capsProjectToken) {
1958
+ return this.request({
1959
+ url: uploadURL,
1960
+ method: "PUT",
1961
+ headers: {
1962
+ "Content-Type": "application/json",
1963
+ projectToken: capsProjectToken !== "" ? capsProjectToken : this.projectToken
1964
+ },
1965
+ data: snapshot,
1966
+ maxBodyLength: Infinity,
1967
+ // prevent axios from limiting the body size
1968
+ maxContentLength: Infinity
1969
+ // prevent axios from limiting the content size
1970
+ }, ctx.log);
1971
+ }
1833
1972
  processWebFigma(requestBody, log2) {
1834
1973
  return this.request({
1835
1974
  url: "figma-web/upload",
@@ -1852,7 +1991,7 @@ var httpClient = class {
1852
1991
  }
1853
1992
  };
1854
1993
  var ctx_default = (options) => {
1855
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1994
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1856
1995
  let env = env_default();
1857
1996
  let webConfig;
1858
1997
  let mobileConfig;
@@ -1893,7 +2032,7 @@ var ctx_default = (options) => {
1893
2032
  process.exit(1);
1894
2033
  }
1895
2034
  fetchResultObj = true;
1896
- fetchResultsFileObj = options.fetchResults === true ? "results.json" : options.fetchResults;
2035
+ fetchResultsFileObj = options.fetchResults === true ? "" : options.fetchResults;
1897
2036
  } else {
1898
2037
  fetchResultObj = false;
1899
2038
  fetchResultsFileObj = "";
@@ -1936,7 +2075,8 @@ var ctx_default = (options) => {
1936
2075
  smartIgnore: (_f = config.smartIgnore) != null ? _f : false,
1937
2076
  delayedUpload: (_g = config.delayedUpload) != null ? _g : false,
1938
2077
  useGlobalCache: (_h = config.useGlobalCache) != null ? _h : false,
1939
- ignoreHTTPSErrors: (_i = config.ignoreHTTPSErrors) != null ? _i : false
2078
+ ignoreHTTPSErrors: (_i = config.ignoreHTTPSErrors) != null ? _i : false,
2079
+ skipBuildCreation: (_j = config.skipBuildCreation) != null ? _j : false
1940
2080
  },
1941
2081
  uploadFilePath: "",
1942
2082
  webStaticConfig: [],
@@ -1970,7 +2110,10 @@ var ctx_default = (options) => {
1970
2110
  cliVersion: version,
1971
2111
  totalSnapshots: -1,
1972
2112
  isStartExec: false,
1973
- isSnapshotCaptured: false
2113
+ isSnapshotCaptured: false,
2114
+ sessionCapabilitiesMap: /* @__PURE__ */ new Map(),
2115
+ buildToSnapshotCountMap: /* @__PURE__ */ new Map(),
2116
+ fetchResultsForBuild: new Array()
1974
2117
  };
1975
2118
  };
1976
2119
  function executeCommand(command7) {
@@ -2045,22 +2188,27 @@ var getGitInfo_default = (ctx) => {
2045
2188
  rendererOptions: { persistentOutput: true }
2046
2189
  };
2047
2190
  };
2048
- var createBuild_default = (ctx) => {
2191
+ var createBuildExec_default = (ctx) => {
2049
2192
  return {
2050
2193
  title: `Creating SmartUI build`,
2051
2194
  task: (ctx2, task) => __async(void 0, null, function* () {
2052
2195
  updateLogContext({ task: "createBuild" });
2053
2196
  try {
2054
- let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
2055
- ctx2.build = {
2056
- id: resp.data.buildId,
2057
- name: resp.data.buildName,
2058
- url: resp.data.buildURL,
2059
- baseline: resp.data.baseline,
2060
- useKafkaFlow: resp.data.useKafkaFlow || false
2061
- };
2062
- task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
2063
- task.title = "SmartUI build created";
2197
+ if (ctx2.authenticatedInitially && !ctx2.config.skipBuildCreation) {
2198
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
2199
+ ctx2.build = {
2200
+ id: resp.data.buildId,
2201
+ name: resp.data.buildName,
2202
+ url: resp.data.buildURL,
2203
+ baseline: resp.data.baseline,
2204
+ useKafkaFlow: resp.data.useKafkaFlow || false
2205
+ };
2206
+ task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
2207
+ task.title = "SmartUI build created";
2208
+ } else {
2209
+ task.output = chalk__default.default.gray(`Empty PROJECT_TOKEN and PROJECT_NAME. Skipping Creation of Build!`);
2210
+ task.title = "Skipped SmartUI build creation";
2211
+ }
2064
2212
  } catch (error) {
2065
2213
  ctx2.log.debug(error);
2066
2214
  task.output = chalk__default.default.gray(error.message);
@@ -2076,7 +2224,9 @@ var exec_default = (ctx) => {
2076
2224
  title: `Executing '${(_a = ctx.args.execCommand) == null ? void 0 : _a.join(" ")}'`,
2077
2225
  task: (ctx2, task) => __async(void 0, null, function* () {
2078
2226
  if (ctx2.options.fetchResults) {
2079
- startPolling(ctx2);
2227
+ if (ctx2.build && ctx2.build.id) {
2228
+ startPolling(ctx2, "", false, "");
2229
+ }
2080
2230
  }
2081
2231
  updateLogContext({ task: "exec" });
2082
2232
  return new Promise((resolve, reject) => {
@@ -2160,14 +2310,50 @@ var finalizeBuild_default = (ctx) => {
2160
2310
  var _a, _b;
2161
2311
  updateLogContext({ task: "finalizeBuild" });
2162
2312
  try {
2163
- yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
2164
- task.output = chalk__default.default.gray(`build url: ${ctx2.build.url}`);
2165
- task.title = "Finalized build";
2313
+ if (ctx2.build.id) {
2314
+ yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
2315
+ }
2166
2316
  } catch (error) {
2167
2317
  ctx2.log.debug(error);
2168
2318
  task.output = chalk__default.default.gray(error.message);
2169
2319
  throw new Error("Finalize build failed");
2170
2320
  }
2321
+ let buildUrls = `build url: ${ctx2.build.url}
2322
+ `;
2323
+ for (const [sessionId, capabilities] of ctx2.sessionCapabilitiesMap.entries()) {
2324
+ try {
2325
+ const buildId = (capabilities == null ? void 0 : capabilities.buildId) || "";
2326
+ const projectToken = (capabilities == null ? void 0 : capabilities.projectToken) || "";
2327
+ const totalSnapshots = (capabilities == null ? void 0 : capabilities.snapshotCount) || 0;
2328
+ const sessionBuildUrl = (capabilities == null ? void 0 : capabilities.buildURL) || "";
2329
+ const testId = (capabilities == null ? void 0 : capabilities.id) || "";
2330
+ if (ctx2.options.fetchResults && ctx2.fetchResultsForBuild) {
2331
+ if (!ctx2.fetchResultsForBuild.includes(buildId)) {
2332
+ let is_baseline;
2333
+ if (capabilities.baseline) {
2334
+ is_baseline = true;
2335
+ } else {
2336
+ is_baseline = false;
2337
+ }
2338
+ console.log(`start polling was called at finalize build for buildId: ${buildId}`);
2339
+ startPolling(ctx2, buildId, is_baseline, capabilities.projectToken);
2340
+ yield new Promise((resolve) => setTimeout(resolve, 7e3));
2341
+ ctx2.fetchResultsForBuild.push(buildId);
2342
+ }
2343
+ }
2344
+ if (buildId && projectToken) {
2345
+ yield ctx2.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx2.log);
2346
+ }
2347
+ if (testId && buildId) {
2348
+ buildUrls += `TestId ${testId}: ${sessionBuildUrl}
2349
+ `;
2350
+ }
2351
+ } catch (error) {
2352
+ ctx2.log.debug(`Error finalizing build for session ${sessionId}: ${error.message}`);
2353
+ }
2354
+ }
2355
+ task.output = chalk__default.default.gray(buildUrls);
2356
+ task.title = "Finalized build";
2171
2357
  try {
2172
2358
  yield (_a = ctx2.browser) == null ? void 0 : _a.close();
2173
2359
  ctx2.log.debug(`Closed browser`);
@@ -2360,6 +2546,16 @@ function processSnapshot(snapshot, ctx) {
2360
2546
  if (options.loadDomContent) {
2361
2547
  processedOptions.loadDomContent = true;
2362
2548
  }
2549
+ if (options.sessionId) {
2550
+ const sessionId = options.sessionId;
2551
+ processedOptions.sessionId = sessionId;
2552
+ if (ctx.sessionCapabilitiesMap && ctx.sessionCapabilitiesMap.has(sessionId)) {
2553
+ const sessionCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
2554
+ if (sessionCapabilities && sessionCapabilities.id) {
2555
+ processedOptions.testId = sessionCapabilities.id;
2556
+ }
2557
+ }
2558
+ }
2363
2559
  if (options.web && Object.keys(options.web).length) {
2364
2560
  processedOptions.web = {};
2365
2561
  if (options.web.viewports && options.web.viewports.length > 0) {
@@ -2750,6 +2946,7 @@ var Queue = class {
2750
2946
  }
2751
2947
  processNext() {
2752
2948
  return __async(this, null, function* () {
2949
+ var _a, _b, _c;
2753
2950
  if (!this.isEmpty()) {
2754
2951
  let snapshot;
2755
2952
  if (this.ctx.config.delayedUpload) {
@@ -2777,22 +2974,71 @@ var Queue = class {
2777
2974
  this.processGenerateVariants(snapshot);
2778
2975
  }
2779
2976
  if (!drop) {
2977
+ const sessionId = (_a = snapshot == null ? void 0 : snapshot.options) == null ? void 0 : _a.sessionId;
2978
+ let capsBuildId = "";
2979
+ let capsProjectToken = "";
2980
+ let useCapsBuildId = false;
2981
+ let useKafkaFlowCaps = false;
2982
+ if (sessionId && ((_b = this.ctx.sessionCapabilitiesMap) == null ? void 0 : _b.has(sessionId))) {
2983
+ const cachedCapabilities = this.ctx.sessionCapabilitiesMap.get(sessionId);
2984
+ capsProjectToken = (cachedCapabilities == null ? void 0 : cachedCapabilities.projectToken) || "";
2985
+ capsBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
2986
+ useKafkaFlowCaps = (cachedCapabilities == null ? void 0 : cachedCapabilities.useKafkaFlow) || false;
2987
+ if (capsBuildId != "" && capsProjectToken != "") {
2988
+ useCapsBuildId = true;
2989
+ }
2990
+ }
2780
2991
  let { processedSnapshot, warnings } = yield processSnapshot(snapshot, this.ctx);
2781
- if (this.ctx.build && this.ctx.build.useKafkaFlow) {
2782
- const snapshotUuid = uuid.v4();
2783
- const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUpload(this.ctx, processedSnapshot.name, snapshotUuid);
2784
- const uploadUrl = presignedResponse.data.url;
2785
- yield this.ctx.client.uploadSnapshotToS3(this.ctx, uploadUrl, processedSnapshot);
2786
- yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid);
2992
+ if (useCapsBuildId) {
2993
+ if (useKafkaFlowCaps) {
2994
+ const snapshotUuid = uuid.v4();
2995
+ const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUploadCaps(this.ctx, processedSnapshot.name, snapshotUuid, capsBuildId, capsProjectToken);
2996
+ const uploadUrl = presignedResponse.data.url;
2997
+ yield this.ctx.client.uploadSnapshotToS3Caps(this.ctx, uploadUrl, processedSnapshot, capsProjectToken);
2998
+ yield this.ctx.client.processSnapshotCaps(this.ctx, processedSnapshot, snapshotUuid, capsBuildId, capsProjectToken);
2999
+ } else {
3000
+ yield this.ctx.client.uploadSnapshotForCaps(this.ctx, processedSnapshot, capsBuildId, capsProjectToken);
3001
+ }
3002
+ const cachedCapabilities = this.ctx.sessionCapabilitiesMap.get(sessionId);
3003
+ const currentCount = (cachedCapabilities == null ? void 0 : cachedCapabilities.snapshotCount) || 0;
3004
+ cachedCapabilities.snapshotCount = currentCount + 1;
3005
+ this.ctx.sessionCapabilitiesMap.set(sessionId, cachedCapabilities);
2787
3006
  } else {
2788
- yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
3007
+ if (!((_c = this.ctx.build) == null ? void 0 : _c.id)) {
3008
+ if (this.ctx.authenticatedInitially) {
3009
+ let resp = yield this.ctx.client.createBuild(this.ctx.git, this.ctx.config, this.ctx.log, this.ctx.build.name);
3010
+ this.ctx.build = {
3011
+ id: resp.data.buildId,
3012
+ name: resp.data.buildName,
3013
+ url: resp.data.buildURL,
3014
+ baseline: resp.data.baseline,
3015
+ useKafkaFlow: resp.data.useKafkaFlow || false
3016
+ };
3017
+ } else {
3018
+ throw new Error("SmartUI capabilities are missing in env variables or in driver capabilities");
3019
+ }
3020
+ if (this.ctx.options.fetchResults) {
3021
+ if (this.ctx.build && this.ctx.build.id) {
3022
+ startPolling(this.ctx, "", false, "");
3023
+ }
3024
+ }
3025
+ }
3026
+ if (this.ctx.build && this.ctx.build.useKafkaFlow) {
3027
+ const snapshotUuid = uuid.v4();
3028
+ const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUpload(this.ctx, processedSnapshot.name, snapshotUuid);
3029
+ const uploadUrl = presignedResponse.data.url;
3030
+ yield this.ctx.client.uploadSnapshotToS3(this.ctx, uploadUrl, processedSnapshot);
3031
+ yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid);
3032
+ } else {
3033
+ yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
3034
+ }
3035
+ this.ctx.totalSnapshots++;
2789
3036
  }
2790
- this.ctx.totalSnapshots++;
2791
- this.processedSnapshots.push({ name: snapshot.name, warnings });
3037
+ this.processedSnapshots.push({ name: snapshot == null ? void 0 : snapshot.name, warnings });
2792
3038
  }
2793
3039
  } catch (error) {
2794
3040
  this.ctx.log.debug(`snapshot failed; ${error}`);
2795
- this.processedSnapshots.push({ name: snapshot.name, error: error.message });
3041
+ this.processedSnapshots.push({ name: snapshot == null ? void 0 : snapshot.name, error: error.message });
2796
3042
  }
2797
3043
  if (this.ctx.browser) {
2798
3044
  for (let context of this.ctx.browser.contexts()) {
@@ -2843,10 +3089,10 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
2843
3089
  ctx.totalSnapshots = 0;
2844
3090
  let tasks = new listr2.Listr(
2845
3091
  [
2846
- auth_default(),
3092
+ authExec_default(),
2847
3093
  startServer_default(),
2848
3094
  getGitInfo_default(),
2849
- createBuild_default(),
3095
+ createBuildExec_default(),
2850
3096
  exec_default(ctx),
2851
3097
  processSnapshot_default(),
2852
3098
  finalizeBuild_default()
@@ -2991,6 +3237,55 @@ configWebFigma.name("config:create-figma-web").description("Create figma config
2991
3237
  createWebFigmaConfig(filepath);
2992
3238
  });
2993
3239
  });
3240
+ var auth_default = (ctx) => {
3241
+ return {
3242
+ title: `Authenticating with SmartUI`,
3243
+ task: (ctx2, task) => __async(void 0, null, function* () {
3244
+ updateLogContext({ task: "auth" });
3245
+ try {
3246
+ const authResult = yield ctx2.client.auth(ctx2.log, ctx2.env);
3247
+ if (authResult === 2) {
3248
+ task.output = chalk__default.default.gray(`New project '${ctx2.env.PROJECT_NAME}' created successfully`);
3249
+ } else if (authResult === 0) {
3250
+ task.output = chalk__default.default.gray(`Using existing project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
3251
+ } else if (authResult === 1) {
3252
+ task.output = chalk__default.default.gray(`Using existing project '${ctx2.env.PROJECT_NAME}'`);
3253
+ }
3254
+ task.title = "Authenticated with SmartUI";
3255
+ } catch (error) {
3256
+ ctx2.log.debug(error);
3257
+ task.output = chalk__default.default.gray(error.message);
3258
+ throw new Error("Authentication failed");
3259
+ }
3260
+ }),
3261
+ rendererOptions: { persistentOutput: true }
3262
+ };
3263
+ };
3264
+ var createBuild_default = (ctx) => {
3265
+ return {
3266
+ title: `Creating SmartUI build`,
3267
+ task: (ctx2, task) => __async(void 0, null, function* () {
3268
+ updateLogContext({ task: "createBuild" });
3269
+ try {
3270
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
3271
+ ctx2.build = {
3272
+ id: resp.data.buildId,
3273
+ name: resp.data.buildName,
3274
+ url: resp.data.buildURL,
3275
+ baseline: resp.data.baseline,
3276
+ useKafkaFlow: resp.data.useKafkaFlow || false
3277
+ };
3278
+ task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
3279
+ task.title = "SmartUI build created";
3280
+ } catch (error) {
3281
+ ctx2.log.debug(error);
3282
+ task.output = chalk__default.default.gray(error.message);
3283
+ throw new Error("SmartUI build creation failed");
3284
+ }
3285
+ }),
3286
+ rendererOptions: { persistentOutput: true }
3287
+ };
3288
+ };
2994
3289
  function captureScreenshotsForConfig(ctx, browsers, urlConfig, browserName, renderViewports) {
2995
3290
  return __async(this, null, function* () {
2996
3291
  ctx.log.debug(`*** urlConfig ${JSON.stringify(urlConfig)}`);
@@ -3318,7 +3613,7 @@ var captureScreenshots_default = (ctx) => {
3318
3613
  try {
3319
3614
  ctx2.task = task;
3320
3615
  if (ctx2.options.fetchResults) {
3321
- startPolling(ctx2);
3616
+ startPolling(ctx2, "", false, "");
3322
3617
  }
3323
3618
  updateLogContext({ task: "capture" });
3324
3619
  if (ctx2.options.parallel) {
@@ -3417,7 +3712,7 @@ var uploadScreenshots_default = (ctx) => {
3417
3712
  try {
3418
3713
  ctx2.task = task;
3419
3714
  if (ctx2.options.fetchResults) {
3420
- startPolling(ctx2);
3715
+ startPolling(ctx2, "", false, "");
3421
3716
  }
3422
3717
  updateLogContext({ task: "upload" });
3423
3718
  yield uploadScreenshots(ctx2);
@@ -3630,7 +3925,7 @@ var uploadWebFigma_default2 = (ctx) => {
3630
3925
  task.output = task.output + "\n" + chalk__default.default.green(`${output}`);
3631
3926
  }
3632
3927
  if (ctx2.options.fetchResults) {
3633
- startPolling(ctx2);
3928
+ startPolling(ctx2, "", false, "");
3634
3929
  }
3635
3930
  task.title = "Web Figma images uploaded successfully to SmartUI";
3636
3931
  ctx2.log.debug(`Web Figma processed: ${results}`);
@@ -3774,7 +4069,7 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
3774
4069
  yield tasks.run(ctx);
3775
4070
  startPingPolling(ctx);
3776
4071
  if (ctx.options.fetchResults) {
3777
- startPolling(ctx);
4072
+ startPolling(ctx, "", false, "");
3778
4073
  }
3779
4074
  } catch (error) {
3780
4075
  console.error("Error during server execution:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.2",
3
+ "version": "4.1.3-beta.0",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"