@lambdatest/smartui-cli 4.0.19 → 4.0.21

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 +659 -453
  2. package/package.json +2 -1
package/dist/index.cjs CHANGED
@@ -4,24 +4,27 @@
4
4
  var commander = require('commander');
5
5
  var which = require('which');
6
6
  var listr2 = require('listr2');
7
- var chalk6 = require('chalk');
7
+ var chalk = require('chalk');
8
8
  var path2 = require('path');
9
9
  var fastify = require('fastify');
10
10
  var fs5 = require('fs');
11
11
  var Ajv = require('ajv');
12
12
  var addErrors = require('ajv-errors');
13
+ var test = require('@playwright/test');
14
+ var util = require('util');
13
15
  var winston = require('winston');
14
16
  var FormData = require('form-data');
15
17
  var axios = require('axios');
18
+ var https = require('https');
16
19
  var child_process = require('child_process');
17
20
  var spawn = require('cross-spawn');
18
- var test = require('@playwright/test');
21
+ var uuid = require('uuid');
19
22
  var sharp = require('sharp');
20
23
 
21
24
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
22
25
 
23
26
  var which__default = /*#__PURE__*/_interopDefault(which);
24
- var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
27
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
25
28
  var path2__default = /*#__PURE__*/_interopDefault(path2);
26
29
  var fastify__default = /*#__PURE__*/_interopDefault(fastify);
27
30
  var fs5__default = /*#__PURE__*/_interopDefault(fs5);
@@ -29,6 +32,7 @@ var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
29
32
  var addErrors__default = /*#__PURE__*/_interopDefault(addErrors);
30
33
  var FormData__default = /*#__PURE__*/_interopDefault(FormData);
31
34
  var axios__default = /*#__PURE__*/_interopDefault(axios);
35
+ var https__default = /*#__PURE__*/_interopDefault(https);
32
36
  var spawn__default = /*#__PURE__*/_interopDefault(spawn);
33
37
  var sharp__default = /*#__PURE__*/_interopDefault(sharp);
34
38
 
@@ -415,7 +419,6 @@ var constants_default = {
415
419
  "Xperia 10 IV": { os: "android", viewport: { width: 412, height: 832 } },
416
420
  "Honeywell CT40": { os: "android", viewport: { width: 360, height: 512 } }
417
421
  },
418
- FIGMA_API: "https://api.figma.com/v1/",
419
422
  DEFAULT_FIGMA_CONFIG: {
420
423
  "depth": 2,
421
424
  "figma_config": [
@@ -960,6 +963,282 @@ var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
960
963
  var validateSnapshot = ajv.compile(SnapshotSchema);
961
964
  var validateFigmaDesignConfig = ajv.compile(FigmaDesignConfigSchema);
962
965
  var validateWebFigmaConfig = ajv.compile(FigmaWebConfigSchema);
966
+ util.promisify(setTimeout);
967
+ var isPollingActive = false;
968
+ function delDir(dir) {
969
+ if (fs5__default.default.existsSync(dir)) {
970
+ fs5__default.default.rmSync(dir, { recursive: true });
971
+ }
972
+ }
973
+ function scrollToBottomAndBackToTop({
974
+ frequency = 100,
975
+ timing = 8,
976
+ remoteWindow = window
977
+ } = {}) {
978
+ return new Promise((resolve) => {
979
+ let scrolls = 1;
980
+ let scrollLength = remoteWindow.document.body.scrollHeight / frequency;
981
+ (function scroll() {
982
+ let scrollBy = scrollLength * scrolls;
983
+ remoteWindow.setTimeout(() => {
984
+ remoteWindow.scrollTo(0, scrollBy);
985
+ if (scrolls < frequency) {
986
+ scrolls += 1;
987
+ scroll();
988
+ }
989
+ if (scrolls === frequency) {
990
+ remoteWindow.setTimeout(() => {
991
+ remoteWindow.scrollTo(0, 0);
992
+ resolve();
993
+ }, timing);
994
+ }
995
+ }, timing);
996
+ })();
997
+ });
998
+ }
999
+ function launchBrowsers(ctx) {
1000
+ return __async(this, null, function* () {
1001
+ var _a;
1002
+ let browsers = {};
1003
+ const isHeadless = ((_a = process.env.HEADLESS) == null ? void 0 : _a.toLowerCase()) === "false" ? false : true;
1004
+ let launchOptions = { headless: isHeadless };
1005
+ if (ctx.config.web) {
1006
+ for (const browser of ctx.config.web.browsers) {
1007
+ switch (browser) {
1008
+ case constants_default.CHROME:
1009
+ browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1010
+ break;
1011
+ case constants_default.SAFARI:
1012
+ browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1013
+ break;
1014
+ case constants_default.FIREFOX:
1015
+ browsers[constants_default.FIREFOX] = yield test.firefox.launch(launchOptions);
1016
+ break;
1017
+ case constants_default.EDGE:
1018
+ launchOptions.args = ["--headless=new"];
1019
+ browsers[constants_default.EDGE] = yield test.chromium.launch(__spreadValues({ channel: constants_default.EDGE_CHANNEL }, launchOptions));
1020
+ break;
1021
+ }
1022
+ }
1023
+ }
1024
+ if (ctx.config.mobile) {
1025
+ for (const device of ctx.config.mobile.devices) {
1026
+ if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "android" && !browsers[constants_default.CHROME])
1027
+ browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1028
+ else if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "ios" && !browsers[constants_default.SAFARI])
1029
+ browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1030
+ }
1031
+ }
1032
+ return browsers;
1033
+ });
1034
+ }
1035
+ function closeBrowsers(browsers) {
1036
+ return __async(this, null, function* () {
1037
+ var _a;
1038
+ for (const browserName of Object.keys(browsers))
1039
+ yield (_a = browsers[browserName]) == null ? void 0 : _a.close();
1040
+ });
1041
+ }
1042
+ function getWebRenderViewports(ctx) {
1043
+ let webRenderViewports = [];
1044
+ if (ctx.config.web) {
1045
+ for (const viewport of ctx.config.web.viewports) {
1046
+ webRenderViewports.push({
1047
+ viewport,
1048
+ viewportString: `${viewport.width}${viewport.height ? "x" + viewport.height : ""}`,
1049
+ fullPage: viewport.height ? false : true,
1050
+ device: false
1051
+ });
1052
+ }
1053
+ }
1054
+ return webRenderViewports;
1055
+ }
1056
+ function getWebRenderViewportsForOptions(options) {
1057
+ let webRenderViewports = [];
1058
+ if (options.web && Array.isArray(options.web.viewports)) {
1059
+ for (const viewport of options.web.viewports) {
1060
+ if (Array.isArray(viewport) && viewport.length > 0) {
1061
+ let viewportObj = {
1062
+ width: viewport[0]
1063
+ };
1064
+ if (viewport.length > 1) {
1065
+ viewportObj.height = viewport[1];
1066
+ }
1067
+ webRenderViewports.push({
1068
+ viewport: viewportObj,
1069
+ viewportString: `${viewport[0]}${viewport[1] ? "x" + viewport[1] : ""}`,
1070
+ fullPage: viewport.length === 1,
1071
+ device: false
1072
+ });
1073
+ }
1074
+ }
1075
+ }
1076
+ return webRenderViewports;
1077
+ }
1078
+ function getMobileRenderViewports(ctx) {
1079
+ var _a;
1080
+ let mobileRenderViewports = {};
1081
+ mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1082
+ mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1083
+ if (ctx.config.mobile) {
1084
+ for (const device of ctx.config.mobile.devices) {
1085
+ let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1086
+ let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1087
+ let portrait = ctx.config.mobile.orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT ? true : false;
1088
+ (_a = mobileRenderViewports[os]) == null ? void 0 : _a.push({
1089
+ viewport: { width: portrait ? width : height, height: portrait ? height : width },
1090
+ viewportString: `${device} (${ctx.config.mobile.orientation})`,
1091
+ fullPage: ctx.config.mobile.fullPage,
1092
+ device: true,
1093
+ os
1094
+ });
1095
+ }
1096
+ }
1097
+ return mobileRenderViewports;
1098
+ }
1099
+ function getMobileRenderViewportsForOptions(options) {
1100
+ var _a;
1101
+ let mobileRenderViewports = {};
1102
+ mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1103
+ mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1104
+ if (options.mobile) {
1105
+ for (const device of options.mobile.devices) {
1106
+ let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1107
+ let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1108
+ let orientation = options.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
1109
+ let portrait = orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT;
1110
+ let fullPage;
1111
+ if (options.mobile.fullPage === void 0 || options.mobile.fullPage) {
1112
+ fullPage = true;
1113
+ } else {
1114
+ fullPage = false;
1115
+ }
1116
+ (_a = mobileRenderViewports[os]) == null ? void 0 : _a.push({
1117
+ viewport: { width: portrait ? width : height, height: portrait ? height : width },
1118
+ viewportString: `${device} (${orientation})`,
1119
+ fullPage,
1120
+ device: true,
1121
+ os
1122
+ });
1123
+ }
1124
+ }
1125
+ return mobileRenderViewports;
1126
+ }
1127
+ function getRenderViewports(ctx) {
1128
+ let mobileRenderViewports = getMobileRenderViewports(ctx);
1129
+ let webRenderViewports = getWebRenderViewports(ctx);
1130
+ return [
1131
+ ...webRenderViewports,
1132
+ ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1133
+ ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1134
+ ];
1135
+ }
1136
+ function getRenderViewportsForOptions(options) {
1137
+ let mobileRenderViewports = getMobileRenderViewportsForOptions(options);
1138
+ let webRenderViewports = getWebRenderViewportsForOptions(options);
1139
+ return [
1140
+ ...webRenderViewports,
1141
+ ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1142
+ ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1143
+ ];
1144
+ }
1145
+ process.on("SIGINT", () => __async(void 0, null, function* () {
1146
+ if (isPollingActive) {
1147
+ console.log("Fetching results interrupted. Exiting...");
1148
+ isPollingActive = false;
1149
+ } else {
1150
+ console.log("\nExiting gracefully...");
1151
+ }
1152
+ process.exit(0);
1153
+ }));
1154
+ function startPolling(ctx) {
1155
+ return __async(this, null, function* () {
1156
+ ctx.log.info("Fetching results in progress....");
1157
+ isPollingActive = true;
1158
+ const intervalId = setInterval(() => __async(this, null, function* () {
1159
+ if (!isPollingActive) {
1160
+ clearInterval(intervalId);
1161
+ return;
1162
+ }
1163
+ try {
1164
+ const resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log);
1165
+ if (!resp.build) {
1166
+ ctx.log.info("Error: Build data is null.");
1167
+ clearInterval(intervalId);
1168
+ isPollingActive = false;
1169
+ }
1170
+ fs5__default.default.writeFileSync(ctx.options.fetchResultsFileName, JSON.stringify(resp, null, 2));
1171
+ ctx.log.debug(`Updated results in ${ctx.options.fetchResultsFileName}`);
1172
+ if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1173
+ clearInterval(intervalId);
1174
+ ctx.log.info(`Fetching results completed. Final results written to ${ctx.options.fetchResultsFileName}`);
1175
+ isPollingActive = false;
1176
+ let totalScreenshotsWithMismatches = 0;
1177
+ let totalVariantsWithMismatches = 0;
1178
+ const totalScreenshots = Object.keys(resp.screenshots || {}).length;
1179
+ let totalVariants = 0;
1180
+ for (const [screenshot, variants] of Object.entries(resp.screenshots || {})) {
1181
+ let screenshotHasMismatch = false;
1182
+ let variantMismatchCount = 0;
1183
+ totalVariants += variants.length;
1184
+ for (const variant of variants) {
1185
+ if (variant.mismatch_percentage > 0) {
1186
+ screenshotHasMismatch = true;
1187
+ variantMismatchCount++;
1188
+ }
1189
+ }
1190
+ if (screenshotHasMismatch) {
1191
+ totalScreenshotsWithMismatches++;
1192
+ totalVariantsWithMismatches += variantMismatchCount;
1193
+ }
1194
+ }
1195
+ ctx.log.info(
1196
+ chalk__default.default.green.bold(
1197
+ `
1198
+ Summary of Mismatches:
1199
+ ${chalk__default.default.yellow("Total Variants with Mismatches:")} ${chalk__default.default.white(totalVariantsWithMismatches)} out of ${chalk__default.default.white(totalVariants)}
1200
+ ${chalk__default.default.yellow("Total Screenshots with Mismatches:")} ${chalk__default.default.white(totalScreenshotsWithMismatches)} out of ${chalk__default.default.white(totalScreenshots)}
1201
+ ${chalk__default.default.yellow("Branch Name:")} ${chalk__default.default.white(resp.build.branch)}
1202
+ ${chalk__default.default.yellow("Project Name:")} ${chalk__default.default.white(resp.project.name)}
1203
+ ${chalk__default.default.yellow("Build ID:")} ${chalk__default.default.white(resp.build.build_id)}
1204
+ `
1205
+ )
1206
+ );
1207
+ }
1208
+ } catch (error) {
1209
+ if (error.message.includes("ENOTFOUND")) {
1210
+ ctx.log.error("Error: Network error occurred while fetching build results. Please check your connection and try again.");
1211
+ clearInterval(intervalId);
1212
+ } else {
1213
+ ctx.log.error(`Error fetching screenshot data: ${error.message}`);
1214
+ }
1215
+ clearInterval(intervalId);
1216
+ isPollingActive = false;
1217
+ }
1218
+ }), 5e3);
1219
+ });
1220
+ }
1221
+ var pingIntervalId = null;
1222
+ function startPingPolling(ctx) {
1223
+ return __async(this, null, function* () {
1224
+ try {
1225
+ ctx.log.debug("Sending initial ping to server...");
1226
+ yield ctx.client.ping(ctx.build.id, ctx.log);
1227
+ ctx.log.debug("Initial ping sent successfully.");
1228
+ } catch (error) {
1229
+ ctx.log.error(`Error during initial ping: ${error.message}`);
1230
+ }
1231
+ pingIntervalId = setInterval(() => __async(this, null, function* () {
1232
+ try {
1233
+ ctx.log.debug("Sending ping to server...");
1234
+ yield ctx.client.ping(ctx.build.id, ctx.log);
1235
+ ctx.log.debug("Ping sent successfully.");
1236
+ } catch (error) {
1237
+ ctx.log.error(`Error during ping polling: ${error.message}`);
1238
+ }
1239
+ }), 10 * 60 * 1e3);
1240
+ });
1241
+ }
963
1242
 
964
1243
  // src/lib/server.ts
965
1244
  var server_default = (ctx) => __async(void 0, null, function* () {
@@ -999,6 +1278,48 @@ var server_default = (ctx) => __async(void 0, null, function* () {
999
1278
  }
1000
1279
  return reply.code(replyCode).send(replyBody);
1001
1280
  }));
1281
+ server.post("/stop", opts, (_, reply) => __async(void 0, null, function* () {
1282
+ var _a, _b;
1283
+ let replyCode;
1284
+ let replyBody;
1285
+ try {
1286
+ if (ctx.config.delayedUpload) {
1287
+ ctx.log.debug("started after processing because of delayedUpload");
1288
+ (_a = ctx.snapshotQueue) == null ? void 0 : _a.startProcessingfunc();
1289
+ }
1290
+ yield new Promise((resolve) => {
1291
+ const intervalId = setInterval(() => {
1292
+ var _a2, _b2;
1293
+ if (((_a2 = ctx.snapshotQueue) == null ? void 0 : _a2.isEmpty()) && !((_b2 = ctx.snapshotQueue) == null ? void 0 : _b2.isProcessing())) {
1294
+ clearInterval(intervalId);
1295
+ resolve();
1296
+ }
1297
+ }, 1e3);
1298
+ });
1299
+ yield ctx.client.finalizeBuild(ctx.build.id, ctx.totalSnapshots, ctx.log);
1300
+ yield (_b = ctx.browser) == null ? void 0 : _b.close();
1301
+ if (ctx.server) {
1302
+ ctx.server.close();
1303
+ }
1304
+ let resp = yield ctx.client.getS3PreSignedURL(ctx);
1305
+ yield ctx.client.uploadLogs(ctx, resp.data.url);
1306
+ if (pingIntervalId !== null) {
1307
+ clearInterval(pingIntervalId);
1308
+ ctx.log.debug("Ping polling stopped immediately.");
1309
+ }
1310
+ replyCode = 200;
1311
+ replyBody = { data: { message: "success", type: "DELETE" } };
1312
+ } catch (error) {
1313
+ ctx.log.debug(error);
1314
+ ctx.log.debug(`stop endpoint failed; ${error}`);
1315
+ replyCode = 500;
1316
+ replyBody = { error: { message: error.message } };
1317
+ }
1318
+ return reply.code(replyCode).send(replyBody);
1319
+ }));
1320
+ server.get("/ping", opts, (_, reply) => {
1321
+ reply.code(200).send({ status: "Server is running", version: ctx.cliVersion });
1322
+ });
1002
1323
  yield server.listen({ port: ctx.options.port });
1003
1324
  let { port } = server.addresses()[0];
1004
1325
  process.env.SMARTUI_SERVER_ADDRESS = `http://localhost:${port}`;
@@ -1024,7 +1345,9 @@ var env_default = () => {
1024
1345
  LT_SDK_DEBUG,
1025
1346
  BASELINE_BRANCH,
1026
1347
  CURRENT_BRANCH,
1027
- PROJECT_NAME
1348
+ PROJECT_NAME,
1349
+ SMARTUI_API_PROXY,
1350
+ SMARTUI_API_SKIP_CERTIFICATES
1028
1351
  } = process.env;
1029
1352
  return {
1030
1353
  PROJECT_TOKEN,
@@ -1042,7 +1365,9 @@ var env_default = () => {
1042
1365
  CURRENT_BRANCH,
1043
1366
  LT_SDK_DEBUG: LT_SDK_DEBUG === "true",
1044
1367
  SMARTUI_DO_NOT_USE_CAPTURED_COOKIES: SMARTUI_DO_NOT_USE_CAPTURED_COOKIES === "true",
1045
- PROJECT_NAME
1368
+ PROJECT_NAME,
1369
+ SMARTUI_API_PROXY,
1370
+ SMARTUI_API_SKIP_CERTIFICATES: SMARTUI_API_SKIP_CERTIFICATES === "true"
1046
1371
  };
1047
1372
  };
1048
1373
  var logContext = {};
@@ -1061,7 +1386,7 @@ var logger = winston.createLogger({
1061
1386
  let message = typeof info.message === "object" ? JSON.stringify(info.message).trim() : info.message.trim();
1062
1387
  switch (info.level) {
1063
1388
  case "warn":
1064
- message = chalk6__default.default.yellow(message);
1389
+ message = chalk__default.default.yellow(message);
1065
1390
  break;
1066
1391
  }
1067
1392
  return info.level === "info" ? message : `[${contextString}:${info.level}] ` + message;
@@ -1088,11 +1413,11 @@ var startServer_default = (ctx) => {
1088
1413
  updateLogContext({ task: "startServer" });
1089
1414
  try {
1090
1415
  ctx2.server = yield server_default(ctx2);
1091
- task.output = chalk6__default.default.gray(`listening on port ${(_a = ctx2.server.addresses()[0]) == null ? void 0 : _a.port}`);
1416
+ task.output = chalk__default.default.gray(`listening on port ${(_a = ctx2.server.addresses()[0]) == null ? void 0 : _a.port}`);
1092
1417
  task.title = "SmartUI started";
1093
1418
  } catch (error) {
1094
1419
  ctx2.log.debug(error);
1095
- task.output = chalk6__default.default.gray(error.message);
1420
+ task.output = chalk__default.default.gray(error.message);
1096
1421
  throw new Error("SmartUI server setup failed");
1097
1422
  }
1098
1423
  }),
@@ -1107,16 +1432,16 @@ var auth_default = (ctx) => {
1107
1432
  try {
1108
1433
  const authResult = yield ctx2.client.auth(ctx2.log, ctx2.env);
1109
1434
  if (authResult === 2) {
1110
- task.output = chalk6__default.default.gray(`New project '${ctx2.env.PROJECT_NAME}' created successfully`);
1435
+ task.output = chalk__default.default.gray(`New project '${ctx2.env.PROJECT_NAME}' created successfully`);
1111
1436
  } else if (authResult === 0) {
1112
- task.output = chalk6__default.default.gray(`Using existing project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
1437
+ task.output = chalk__default.default.gray(`Using existing project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
1113
1438
  } else if (authResult === 1) {
1114
- task.output = chalk6__default.default.gray(`Using existing project '${ctx2.env.PROJECT_NAME}'`);
1439
+ task.output = chalk__default.default.gray(`Using existing project '${ctx2.env.PROJECT_NAME}'`);
1115
1440
  }
1116
1441
  task.title = "Authenticated with SmartUI";
1117
1442
  } catch (error) {
1118
1443
  ctx2.log.debug(error);
1119
- task.output = chalk6__default.default.gray(error.message);
1444
+ task.output = chalk__default.default.gray(error.message);
1120
1445
  throw new Error("Authentication failed");
1121
1446
  }
1122
1447
  }),
@@ -1125,65 +1450,36 @@ var auth_default = (ctx) => {
1125
1450
  };
1126
1451
 
1127
1452
  // package.json
1128
- var version = "4.0.19";
1453
+ var version = "4.0.21";
1129
1454
  var package_default = {
1130
1455
  name: "@lambdatest/smartui-cli",
1131
- version,
1132
- description: "A command line interface (CLI) to run SmartUI tests on LambdaTest",
1133
- files: [
1134
- "dist/**/*"
1135
- ],
1136
- scripts: {
1137
- build: "tsup",
1138
- release: "pnpm run build && pnpm publish --access public --no-git-checks",
1139
- "local-build": "pnpm run build && pnpm pack"
1140
- },
1141
- bin: {
1142
- smartui: "./dist/index.cjs"
1143
- },
1144
- type: "module",
1145
- keywords: [
1146
- "lambdatest",
1147
- "smartui",
1148
- "cli"
1149
- ],
1150
- author: "LambdaTest <keys@lambdatest.com>",
1151
- license: "MIT",
1152
- dependencies: {
1153
- "@playwright/browser-chromium": "^1.47.2",
1154
- "@playwright/browser-firefox": "^1.47.2",
1155
- "@playwright/browser-webkit": "^1.47.2",
1156
- "@playwright/test": "^1.47.2",
1157
- "@types/cross-spawn": "^6.0.4",
1158
- "@types/node": "^20.8.9",
1159
- "@types/which": "^3.0.2",
1160
- ajv: "^8.12.0",
1161
- "ajv-errors": "^3.0.0",
1162
- axios: "^1.6.0",
1163
- chalk: "^4.1.2",
1164
- commander: "^11.1.0",
1165
- "cross-spawn": "^7.0.3",
1166
- fastify: "^4.24.3",
1167
- "form-data": "^4.0.0",
1168
- listr2: "^7.0.1",
1169
- sharp: "^0.33.4",
1170
- tsup: "^7.2.0",
1171
- which: "^4.0.0",
1172
- winston: "^3.10.0"
1173
- },
1174
- devDependencies: {
1175
- typescript: "^5.3.2"
1176
- }
1177
- };
1456
+ version};
1178
1457
  var httpClient = class {
1179
- constructor({ SMARTUI_CLIENT_API_URL, PROJECT_TOKEN, PROJECT_NAME, LT_USERNAME, LT_ACCESS_KEY }) {
1458
+ constructor({ SMARTUI_CLIENT_API_URL, PROJECT_TOKEN, PROJECT_NAME, LT_USERNAME, LT_ACCESS_KEY, SMARTUI_API_PROXY, SMARTUI_API_SKIP_CERTIFICATES }) {
1180
1459
  this.projectToken = PROJECT_TOKEN || "";
1181
1460
  this.projectName = PROJECT_NAME || "";
1182
1461
  this.username = LT_USERNAME || "";
1183
1462
  this.accessKey = LT_ACCESS_KEY || "";
1184
- this.axiosInstance = axios__default.default.create({
1185
- baseURL: SMARTUI_CLIENT_API_URL
1186
- });
1463
+ let proxyUrl = null;
1464
+ try {
1465
+ const urlStr = (SMARTUI_API_PROXY == null ? void 0 : SMARTUI_API_PROXY.startsWith("http")) ? SMARTUI_API_PROXY : `http://${SMARTUI_API_PROXY}`;
1466
+ proxyUrl = SMARTUI_API_PROXY ? new URL(urlStr) : null;
1467
+ } catch (error) {
1468
+ console.error("Invalid proxy URL:", error);
1469
+ }
1470
+ const axiosConfig = {
1471
+ baseURL: SMARTUI_CLIENT_API_URL,
1472
+ proxy: proxyUrl ? {
1473
+ host: proxyUrl.hostname,
1474
+ port: proxyUrl.port ? Number(proxyUrl.port) : 80
1475
+ } : false
1476
+ };
1477
+ if (SMARTUI_API_SKIP_CERTIFICATES) {
1478
+ axiosConfig.httpsAgent = new https__default.default.Agent({
1479
+ rejectUnauthorized: false
1480
+ });
1481
+ }
1482
+ this.axiosInstance = axios__default.default.create(axiosConfig);
1187
1483
  this.axiosInstance.interceptors.request.use((config) => {
1188
1484
  config.headers["projectToken"] = this.projectToken;
1189
1485
  config.headers["projectName"] = this.projectName;
@@ -1246,14 +1542,15 @@ var httpClient = class {
1246
1542
  }
1247
1543
  });
1248
1544
  }
1249
- createBuild(git, config, log2, buildName) {
1545
+ createBuild(git, config, log2, buildName, isStartExec) {
1250
1546
  return this.request({
1251
1547
  url: "/build",
1252
1548
  method: "POST",
1253
1549
  data: {
1254
1550
  git,
1255
1551
  config,
1256
- buildName
1552
+ buildName,
1553
+ isStartExec
1257
1554
  }
1258
1555
  }, log2);
1259
1556
  }
@@ -1264,6 +1561,15 @@ var httpClient = class {
1264
1561
  params: { buildId, baseline }
1265
1562
  }, log2);
1266
1563
  }
1564
+ ping(buildId, log2) {
1565
+ return this.request({
1566
+ url: "/build/ping",
1567
+ method: "POST",
1568
+ data: {
1569
+ buildId
1570
+ }
1571
+ }, log2);
1572
+ }
1267
1573
  finalizeBuild(buildId, totalSnapshots, log2) {
1268
1574
  let params = { buildId };
1269
1575
  if (totalSnapshots > -1)
@@ -1288,6 +1594,23 @@ var httpClient = class {
1288
1594
  }
1289
1595
  }, ctx.log);
1290
1596
  }
1597
+ processSnapshot(ctx, snapshot, snapshotUuid) {
1598
+ return this.request({
1599
+ url: `/build/${ctx.build.id}/snapshot`,
1600
+ method: "POST",
1601
+ headers: { "Content-Type": "application/json" },
1602
+ data: {
1603
+ name: snapshot.name,
1604
+ url: snapshot.url,
1605
+ snapshotUuid,
1606
+ test: {
1607
+ type: ctx.testType,
1608
+ source: "cli"
1609
+ },
1610
+ async: false
1611
+ }
1612
+ }, ctx.log);
1613
+ }
1291
1614
  uploadScreenshot({ id: buildId, name: buildName, baseline }, ssPath, ssName, browserName, viewport, log2) {
1292
1615
  browserName = browserName === constants_default.SAFARI ? constants_default.WEBKIT : browserName;
1293
1616
  const file = fs5__default.default.readFileSync(ssPath);
@@ -1356,6 +1679,18 @@ var httpClient = class {
1356
1679
  }
1357
1680
  }, ctx.log);
1358
1681
  }
1682
+ getS3PresignedURLForSnapshotUpload(ctx, snapshotName, snapshotUuid) {
1683
+ return this.request({
1684
+ url: `/snapshotuploadurl`,
1685
+ method: "POST",
1686
+ headers: { "Content-Type": "application/json" },
1687
+ data: {
1688
+ buildId: ctx.build.id,
1689
+ snapshotName,
1690
+ snapshotUuid
1691
+ }
1692
+ }, ctx.log);
1693
+ }
1359
1694
  uploadLogs(ctx, uploadURL) {
1360
1695
  const fileStream = fs5__default.default.createReadStream(constants_default.LOG_FILE_PATH);
1361
1696
  const { size } = fs5__default.default.statSync(constants_default.LOG_FILE_PATH);
@@ -1373,6 +1708,20 @@ var httpClient = class {
1373
1708
  // prevent axios from limiting the content size
1374
1709
  }, ctx.log);
1375
1710
  }
1711
+ uploadSnapshotToS3(ctx, uploadURL, snapshot) {
1712
+ return this.request({
1713
+ url: uploadURL,
1714
+ method: "PUT",
1715
+ headers: {
1716
+ "Content-Type": "application/json"
1717
+ },
1718
+ data: snapshot,
1719
+ maxBodyLength: Infinity,
1720
+ // prevent axios from limiting the body size
1721
+ maxContentLength: Infinity
1722
+ // prevent axios from limiting the content size
1723
+ }, ctx.log);
1724
+ }
1376
1725
  processWebFigma(requestBody, log2) {
1377
1726
  return this.request({
1378
1727
  url: "figma-web/upload",
@@ -1507,362 +1856,108 @@ var ctx_default = (options) => {
1507
1856
  fetchResults: fetchResultObj,
1508
1857
  fetchResultsFileName: fetchResultsFileObj
1509
1858
  },
1510
- cliVersion: version,
1511
- totalSnapshots: -1
1512
- };
1513
- };
1514
- function executeCommand(command4) {
1515
- let dst = process.cwd();
1516
- try {
1517
- return child_process.execSync(command4, {
1518
- cwd: dst,
1519
- stdio: ["ignore"],
1520
- encoding: "utf-8"
1521
- });
1522
- } catch (error) {
1523
- throw new Error(error.message);
1524
- }
1525
- }
1526
- function isGitRepo() {
1527
- try {
1528
- executeCommand("git status");
1529
- return true;
1530
- } catch (error) {
1531
- return false;
1532
- }
1533
- }
1534
- var git_default = (ctx) => {
1535
- if (ctx.env.SMARTUI_GIT_INFO_FILEPATH) {
1536
- let gitInfo = JSON.parse(fs5__default.default.readFileSync(ctx.env.SMARTUI_GIT_INFO_FILEPATH, "utf-8"));
1537
- return {
1538
- branch: ctx.env.CURRENT_BRANCH || gitInfo.branch || "",
1539
- commitId: gitInfo.commit_id.slice(0, 6) || "",
1540
- commitMessage: gitInfo.commit_body || "",
1541
- commitAuthor: gitInfo.commit_author || "",
1542
- githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${gitInfo.commit_id}` : "",
1543
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
1544
- };
1545
- } else {
1546
- const splitCharacter = "<##>";
1547
- const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
1548
- const command4 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
1549
- let res = executeCommand(command4).split(splitCharacter);
1550
- var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
1551
- var branch = ctx.env.CURRENT_BRANCH || branchAndTags[0];
1552
- branchAndTags.slice(1);
1553
- return {
1554
- branch: branch || "",
1555
- commitId: res[0] || "",
1556
- commitMessage: res[2] || "",
1557
- commitAuthor: res[7] || "",
1558
- githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${res[1]}` : "",
1559
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
1560
- };
1561
- }
1562
- };
1563
- var getGitInfo_default = (ctx) => {
1564
- return {
1565
- title: `Fetching git repo details`,
1566
- skip: (ctx2) => {
1567
- return !isGitRepo() && !ctx2.env.SMARTUI_GIT_INFO_FILEPATH ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
1568
- },
1569
- task: (ctx2, task) => __async(void 0, null, function* () {
1570
- if (ctx2.env.CURRENT_BRANCH && ctx2.env.CURRENT_BRANCH.trim() === "") {
1571
- throw new Error("Error: The environment variable CURRENT_BRANCH cannot be empty.");
1572
- }
1573
- try {
1574
- ctx2.git = git_default(ctx2);
1575
- task.output = chalk6__default.default.gray(`branch: ${ctx2.git.branch}, commit: ${ctx2.git.commitId}, author: ${ctx2.git.commitAuthor}`);
1576
- task.title = "Fetched git information";
1577
- } catch (error) {
1578
- ctx2.log.debug(error);
1579
- task.output = chalk6__default.default.gray(`${error.message}`);
1580
- throw new Error("Error fetching git repo details");
1581
- }
1582
- }),
1583
- rendererOptions: { persistentOutput: true }
1584
- };
1585
- };
1586
- var createBuild_default = (ctx) => {
1587
- return {
1588
- title: `Creating SmartUI build`,
1589
- task: (ctx2, task) => __async(void 0, null, function* () {
1590
- updateLogContext({ task: "createBuild" });
1591
- try {
1592
- let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name);
1593
- ctx2.build = {
1594
- id: resp.data.buildId,
1595
- name: resp.data.buildName,
1596
- url: resp.data.buildURL,
1597
- baseline: resp.data.baseline
1598
- };
1599
- task.output = chalk6__default.default.gray(`build id: ${resp.data.buildId}`);
1600
- task.title = "SmartUI build created";
1601
- } catch (error) {
1602
- ctx2.log.debug(error);
1603
- task.output = chalk6__default.default.gray(error.message);
1604
- throw new Error("SmartUI build creation failed");
1605
- }
1606
- }),
1607
- rendererOptions: { persistentOutput: true }
1608
- };
1609
- };
1610
- var isPollingActive = false;
1611
- function delDir(dir) {
1612
- if (fs5__default.default.existsSync(dir)) {
1613
- fs5__default.default.rmSync(dir, { recursive: true });
1614
- }
1615
- }
1616
- function scrollToBottomAndBackToTop({
1617
- frequency = 100,
1618
- timing = 8,
1619
- remoteWindow = window
1620
- } = {}) {
1621
- return new Promise((resolve) => {
1622
- let scrolls = 1;
1623
- let scrollLength = remoteWindow.document.body.scrollHeight / frequency;
1624
- (function scroll() {
1625
- let scrollBy = scrollLength * scrolls;
1626
- remoteWindow.setTimeout(() => {
1627
- remoteWindow.scrollTo(0, scrollBy);
1628
- if (scrolls < frequency) {
1629
- scrolls += 1;
1630
- scroll();
1631
- }
1632
- if (scrolls === frequency) {
1633
- remoteWindow.setTimeout(() => {
1634
- remoteWindow.scrollTo(0, 0);
1635
- resolve();
1636
- }, timing);
1637
- }
1638
- }, timing);
1639
- })();
1640
- });
1641
- }
1642
- function launchBrowsers(ctx) {
1643
- return __async(this, null, function* () {
1644
- var _a;
1645
- let browsers = {};
1646
- const isHeadless = ((_a = process.env.HEADLESS) == null ? void 0 : _a.toLowerCase()) === "false" ? false : true;
1647
- let launchOptions = { headless: isHeadless };
1648
- if (ctx.config.web) {
1649
- for (const browser of ctx.config.web.browsers) {
1650
- switch (browser) {
1651
- case constants_default.CHROME:
1652
- browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1653
- break;
1654
- case constants_default.SAFARI:
1655
- browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1656
- break;
1657
- case constants_default.FIREFOX:
1658
- browsers[constants_default.FIREFOX] = yield test.firefox.launch(launchOptions);
1659
- break;
1660
- case constants_default.EDGE:
1661
- launchOptions.args = ["--headless=new"];
1662
- browsers[constants_default.EDGE] = yield test.chromium.launch(__spreadValues({ channel: constants_default.EDGE_CHANNEL }, launchOptions));
1663
- break;
1664
- }
1665
- }
1666
- }
1667
- if (ctx.config.mobile) {
1668
- for (const device of ctx.config.mobile.devices) {
1669
- if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "android" && !browsers[constants_default.CHROME])
1670
- browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1671
- else if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "ios" && !browsers[constants_default.SAFARI])
1672
- browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1673
- }
1674
- }
1675
- return browsers;
1676
- });
1677
- }
1678
- function closeBrowsers(browsers) {
1679
- return __async(this, null, function* () {
1680
- var _a;
1681
- for (const browserName of Object.keys(browsers))
1682
- yield (_a = browsers[browserName]) == null ? void 0 : _a.close();
1683
- });
1684
- }
1685
- function getWebRenderViewports(ctx) {
1686
- let webRenderViewports = [];
1687
- if (ctx.config.web) {
1688
- for (const viewport of ctx.config.web.viewports) {
1689
- webRenderViewports.push({
1690
- viewport,
1691
- viewportString: `${viewport.width}${viewport.height ? "x" + viewport.height : ""}`,
1692
- fullPage: viewport.height ? false : true,
1693
- device: false
1694
- });
1695
- }
1696
- }
1697
- return webRenderViewports;
1698
- }
1699
- function getWebRenderViewportsForOptions(options) {
1700
- let webRenderViewports = [];
1701
- if (options.web && Array.isArray(options.web.viewports)) {
1702
- for (const viewport of options.web.viewports) {
1703
- if (Array.isArray(viewport) && viewport.length > 0) {
1704
- let viewportObj = {
1705
- width: viewport[0]
1706
- };
1707
- if (viewport.length > 1) {
1708
- viewportObj.height = viewport[1];
1709
- }
1710
- webRenderViewports.push({
1711
- viewport: viewportObj,
1712
- viewportString: `${viewport[0]}${viewport[1] ? "x" + viewport[1] : ""}`,
1713
- fullPage: viewport.length === 1,
1714
- device: false
1715
- });
1716
- }
1717
- }
1718
- }
1719
- return webRenderViewports;
1720
- }
1721
- function getMobileRenderViewports(ctx) {
1722
- var _a;
1723
- let mobileRenderViewports = {};
1724
- mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1725
- mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1726
- if (ctx.config.mobile) {
1727
- for (const device of ctx.config.mobile.devices) {
1728
- let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1729
- let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1730
- let portrait = ctx.config.mobile.orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT ? true : false;
1731
- (_a = mobileRenderViewports[os]) == null ? void 0 : _a.push({
1732
- viewport: { width: portrait ? width : height, height: portrait ? height : width },
1733
- viewportString: `${device} (${ctx.config.mobile.orientation})`,
1734
- fullPage: ctx.config.mobile.fullPage,
1735
- device: true,
1736
- os
1737
- });
1738
- }
1859
+ cliVersion: version,
1860
+ totalSnapshots: -1,
1861
+ isStartExec: false
1862
+ };
1863
+ };
1864
+ function executeCommand(command7) {
1865
+ let dst = process.cwd();
1866
+ try {
1867
+ return child_process.execSync(command7, {
1868
+ cwd: dst,
1869
+ stdio: ["ignore"],
1870
+ encoding: "utf-8"
1871
+ });
1872
+ } catch (error) {
1873
+ throw new Error(error.message);
1739
1874
  }
1740
- return mobileRenderViewports;
1741
1875
  }
1742
- function getMobileRenderViewportsForOptions(options) {
1743
- var _a;
1744
- let mobileRenderViewports = {};
1745
- mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1746
- mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1747
- if (options.mobile) {
1748
- for (const device of options.mobile.devices) {
1749
- let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1750
- let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1751
- let orientation = options.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
1752
- let portrait = orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT;
1753
- let fullPage;
1754
- if (options.mobile.fullPage === void 0 || options.mobile.fullPage) {
1755
- fullPage = true;
1756
- } else {
1757
- fullPage = false;
1758
- }
1759
- (_a = mobileRenderViewports[os]) == null ? void 0 : _a.push({
1760
- viewport: { width: portrait ? width : height, height: portrait ? height : width },
1761
- viewportString: `${device} (${orientation})`,
1762
- fullPage,
1763
- device: true,
1764
- os
1765
- });
1766
- }
1876
+ function isGitRepo() {
1877
+ try {
1878
+ executeCommand("git status");
1879
+ return true;
1880
+ } catch (error) {
1881
+ return false;
1767
1882
  }
1768
- return mobileRenderViewports;
1769
- }
1770
- function getRenderViewports(ctx) {
1771
- let mobileRenderViewports = getMobileRenderViewports(ctx);
1772
- let webRenderViewports = getWebRenderViewports(ctx);
1773
- return [
1774
- ...webRenderViewports,
1775
- ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1776
- ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1777
- ];
1778
- }
1779
- function getRenderViewportsForOptions(options) {
1780
- let mobileRenderViewports = getMobileRenderViewportsForOptions(options);
1781
- let webRenderViewports = getWebRenderViewportsForOptions(options);
1782
- return [
1783
- ...webRenderViewports,
1784
- ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1785
- ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1786
- ];
1787
1883
  }
1788
- process.on("SIGINT", () => {
1789
- if (isPollingActive) {
1790
- console.log("Fetching results interrupted. Exiting...");
1791
- isPollingActive = false;
1884
+ var git_default = (ctx) => {
1885
+ if (ctx.env.SMARTUI_GIT_INFO_FILEPATH) {
1886
+ let gitInfo = JSON.parse(fs5__default.default.readFileSync(ctx.env.SMARTUI_GIT_INFO_FILEPATH, "utf-8"));
1887
+ return {
1888
+ branch: ctx.env.CURRENT_BRANCH || gitInfo.branch || "",
1889
+ commitId: gitInfo.commit_id.slice(0, 6) || "",
1890
+ commitMessage: gitInfo.commit_body || "",
1891
+ commitAuthor: gitInfo.commit_author || "",
1892
+ githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${gitInfo.commit_id}` : "",
1893
+ baselineBranch: ctx.env.BASELINE_BRANCH || ""
1894
+ };
1792
1895
  } else {
1793
- console.log("\nExiting gracefully...");
1896
+ const splitCharacter = "<##>";
1897
+ const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
1898
+ const command7 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
1899
+ let res = executeCommand(command7).split(splitCharacter);
1900
+ var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
1901
+ var branch = ctx.env.CURRENT_BRANCH || branchAndTags[0];
1902
+ branchAndTags.slice(1);
1903
+ return {
1904
+ branch: branch || "",
1905
+ commitId: res[0] || "",
1906
+ commitMessage: res[2] || "",
1907
+ commitAuthor: res[7] || "",
1908
+ githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${res[1]}` : "",
1909
+ baselineBranch: ctx.env.BASELINE_BRANCH || ""
1910
+ };
1794
1911
  }
1795
- process.exit(0);
1796
- });
1797
- function startPolling(ctx, task) {
1798
- return __async(this, null, function* () {
1799
- ctx.log.info("Fetching results in progress....");
1800
- isPollingActive = true;
1801
- const intervalId = setInterval(() => __async(this, null, function* () {
1802
- if (!isPollingActive) {
1803
- clearInterval(intervalId);
1804
- return;
1912
+ };
1913
+ var getGitInfo_default = (ctx) => {
1914
+ return {
1915
+ title: `Fetching git repo details`,
1916
+ skip: (ctx2) => {
1917
+ return !isGitRepo() && !ctx2.env.SMARTUI_GIT_INFO_FILEPATH ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
1918
+ },
1919
+ task: (ctx2, task) => __async(void 0, null, function* () {
1920
+ if (ctx2.env.CURRENT_BRANCH && ctx2.env.CURRENT_BRANCH.trim() === "") {
1921
+ throw new Error("Error: The environment variable CURRENT_BRANCH cannot be empty.");
1805
1922
  }
1806
1923
  try {
1807
- const resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log);
1808
- if (!resp.build) {
1809
- ctx.log.info("Error: Build data is null.");
1810
- clearInterval(intervalId);
1811
- isPollingActive = false;
1812
- }
1813
- fs5__default.default.writeFileSync(ctx.options.fetchResultsFileName, JSON.stringify(resp, null, 2));
1814
- ctx.log.debug(`Updated results in ${ctx.options.fetchResultsFileName}`);
1815
- if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1816
- clearInterval(intervalId);
1817
- ctx.log.info(`Fetching results completed. Final results written to ${ctx.options.fetchResultsFileName}`);
1818
- isPollingActive = false;
1819
- let totalScreenshotsWithMismatches = 0;
1820
- let totalVariantsWithMismatches = 0;
1821
- const totalScreenshots = Object.keys(resp.screenshots || {}).length;
1822
- let totalVariants = 0;
1823
- for (const [screenshot, variants] of Object.entries(resp.screenshots || {})) {
1824
- let screenshotHasMismatch = false;
1825
- let variantMismatchCount = 0;
1826
- totalVariants += variants.length;
1827
- for (const variant of variants) {
1828
- if (variant.mismatch_percentage > 0) {
1829
- screenshotHasMismatch = true;
1830
- variantMismatchCount++;
1831
- }
1832
- }
1833
- if (screenshotHasMismatch) {
1834
- totalScreenshotsWithMismatches++;
1835
- totalVariantsWithMismatches += variantMismatchCount;
1836
- }
1837
- }
1838
- ctx.log.info(
1839
- chalk6__default.default.green.bold(
1840
- `
1841
- Summary of Mismatches:
1842
- ${chalk6__default.default.yellow("Total Variants with Mismatches:")} ${chalk6__default.default.white(totalVariantsWithMismatches)} out of ${chalk6__default.default.white(totalVariants)}
1843
- ${chalk6__default.default.yellow("Total Screenshots with Mismatches:")} ${chalk6__default.default.white(totalScreenshotsWithMismatches)} out of ${chalk6__default.default.white(totalScreenshots)}
1844
- ${chalk6__default.default.yellow("Branch Name:")} ${chalk6__default.default.white(resp.build.branch)}
1845
- ${chalk6__default.default.yellow("Project Name:")} ${chalk6__default.default.white(resp.project.name)}
1846
- ${chalk6__default.default.yellow("Build ID:")} ${chalk6__default.default.white(resp.build.build_id)}
1847
- `
1848
- )
1849
- );
1850
- }
1924
+ ctx2.git = git_default(ctx2);
1925
+ task.output = chalk__default.default.gray(`branch: ${ctx2.git.branch}, commit: ${ctx2.git.commitId}, author: ${ctx2.git.commitAuthor}`);
1926
+ task.title = "Fetched git information";
1851
1927
  } catch (error) {
1852
- if (error.message.includes("ENOTFOUND")) {
1853
- ctx.log.error("Error: Network error occurred while fetching build results. Please check your connection and try again.");
1854
- clearInterval(intervalId);
1855
- } else {
1856
- ctx.log.error(`Error fetching screenshot data: ${error.message}`);
1857
- }
1858
- clearInterval(intervalId);
1859
- isPollingActive = false;
1928
+ ctx2.log.debug(error);
1929
+ task.output = chalk__default.default.gray(`${error.message}`);
1930
+ throw new Error("Error fetching git repo details");
1860
1931
  }
1861
- }), 5e3);
1862
- });
1863
- }
1864
-
1865
- // src/tasks/exec.ts
1932
+ }),
1933
+ rendererOptions: { persistentOutput: true }
1934
+ };
1935
+ };
1936
+ var createBuild_default = (ctx) => {
1937
+ return {
1938
+ title: `Creating SmartUI build`,
1939
+ task: (ctx2, task) => __async(void 0, null, function* () {
1940
+ updateLogContext({ task: "createBuild" });
1941
+ try {
1942
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name, ctx2.isStartExec);
1943
+ ctx2.build = {
1944
+ id: resp.data.buildId,
1945
+ name: resp.data.buildName,
1946
+ url: resp.data.buildURL,
1947
+ baseline: resp.data.baseline,
1948
+ useKafkaFlow: resp.data.useKafkaFlow || false
1949
+ };
1950
+ task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
1951
+ task.title = "SmartUI build created";
1952
+ } catch (error) {
1953
+ ctx2.log.debug(error);
1954
+ task.output = chalk__default.default.gray(error.message);
1955
+ throw new Error("SmartUI build creation failed");
1956
+ }
1957
+ }),
1958
+ rendererOptions: { persistentOutput: true }
1959
+ };
1960
+ };
1866
1961
  var exec_default = (ctx) => {
1867
1962
  var _a;
1868
1963
  return {
@@ -1878,13 +1973,13 @@ var exec_default = (ctx) => {
1878
1973
  let totalOutput = "";
1879
1974
  const output = listr2.createWritable((chunk) => {
1880
1975
  totalOutput += chunk;
1881
- task.output = chalk6__default.default.gray(totalOutput);
1976
+ task.output = chalk__default.default.gray(totalOutput);
1882
1977
  });
1883
1978
  (_b = childProcess.stdout) == null ? void 0 : _b.pipe(output);
1884
1979
  (_c = childProcess.stderr) == null ? void 0 : _c.pipe(output);
1885
1980
  childProcess.on("error", (error) => {
1886
1981
  var _a3;
1887
- task.output = chalk6__default.default.gray(`error: ${error.message}`);
1982
+ task.output = chalk__default.default.gray(`error: ${error.message}`);
1888
1983
  throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' failed`);
1889
1984
  });
1890
1985
  childProcess.on("close", (code, signal) => __async(void 0, null, function* () {
@@ -1927,19 +2022,19 @@ var processSnapshot_default = (ctx) => {
1927
2022
  let output = "";
1928
2023
  for (let snapshot of (_b = ctx2.snapshotQueue) == null ? void 0 : _b.getProcessedSnapshots()) {
1929
2024
  if (snapshot.error)
1930
- output += `${chalk6__default.default.red("\u2717")} ${chalk6__default.default.gray(`${snapshot.name}
2025
+ output += `${chalk__default.default.red("\u2717")} ${chalk__default.default.gray(`${snapshot.name}
1931
2026
  [error] ${snapshot.error}`)}
1932
2027
  `;
1933
2028
  else
1934
- output += `${chalk6__default.default.green("\u2713")} ${chalk6__default.default.gray(snapshot.name)}
1935
- ${snapshot.warnings.length ? chalk6__default.default.gray(`[warning] ${snapshot.warnings.join("\n[warning] ")}
2029
+ output += `${chalk__default.default.green("\u2713")} ${chalk__default.default.gray(snapshot.name)}
2030
+ ${snapshot.warnings.length ? chalk__default.default.gray(`[warning] ${snapshot.warnings.join("\n[warning] ")}
1936
2031
  `) : ""}`;
1937
2032
  }
1938
2033
  task.output = output;
1939
2034
  task.title = "Processed snapshots";
1940
2035
  } catch (error) {
1941
2036
  ctx2.log.debug(error);
1942
- task.output = chalk6__default.default.gray(error.message);
2037
+ task.output = chalk__default.default.gray(error.message);
1943
2038
  throw new Error("Processing of snapshots failed");
1944
2039
  }
1945
2040
  }),
@@ -1954,11 +2049,11 @@ var finalizeBuild_default = (ctx) => {
1954
2049
  updateLogContext({ task: "finalizeBuild" });
1955
2050
  try {
1956
2051
  yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
1957
- task.output = chalk6__default.default.gray(`build url: ${ctx2.build.url}`);
2052
+ task.output = chalk__default.default.gray(`build url: ${ctx2.build.url}`);
1958
2053
  task.title = "Finalized build";
1959
2054
  } catch (error) {
1960
2055
  ctx2.log.debug(error);
1961
- task.output = chalk6__default.default.gray(error.message);
2056
+ task.output = chalk__default.default.gray(error.message);
1962
2057
  throw new Error("Finalize build failed");
1963
2058
  }
1964
2059
  try {
@@ -2312,8 +2407,6 @@ function processSnapshot(snapshot, ctx) {
2312
2407
  };
2313
2408
  });
2314
2409
  }
2315
-
2316
- // src/lib/snapshotQueue.ts
2317
2410
  var Queue = class {
2318
2411
  constructor(ctx) {
2319
2412
  this.snapshots = [];
@@ -2536,6 +2629,9 @@ var Queue = class {
2536
2629
  try {
2537
2630
  this.processingSnapshot = snapshot == null ? void 0 : snapshot.name;
2538
2631
  let drop = false;
2632
+ if (this.ctx.isStartExec) {
2633
+ this.ctx.log.info(`Processing Snapshot: ${snapshot == null ? void 0 : snapshot.name}`);
2634
+ }
2539
2635
  if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {
2540
2636
  drop = true;
2541
2637
  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.`);
@@ -2551,7 +2647,15 @@ var Queue = class {
2551
2647
  }
2552
2648
  if (!drop) {
2553
2649
  let { processedSnapshot, warnings } = yield processSnapshot(snapshot, this.ctx);
2554
- yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
2650
+ if (this.ctx.build && this.ctx.build.useKafkaFlow) {
2651
+ const snapshotUuid = uuid.v4();
2652
+ const presignedResponse = yield this.ctx.client.getS3PresignedURLForSnapshotUpload(this.ctx, processedSnapshot.name, snapshotUuid);
2653
+ const uploadUrl = presignedResponse.data.url;
2654
+ yield this.ctx.client.uploadSnapshotToS3(this.ctx, uploadUrl, processedSnapshot);
2655
+ yield this.ctx.client.processSnapshot(this.ctx, processedSnapshot, snapshotUuid);
2656
+ } else {
2657
+ yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
2658
+ }
2555
2659
  this.ctx.totalSnapshots++;
2556
2660
  this.processedSnapshots.push({ name: snapshot.name, warnings });
2557
2661
  }
@@ -2591,14 +2695,14 @@ var Queue = class {
2591
2695
 
2592
2696
  // src/commander/exec.ts
2593
2697
  var command = new commander.Command();
2594
- command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").option("-P, --port <number>", "Port number for the server").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(execCommand, _, command4) {
2698
+ command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").option("-P, --port <number>", "Port number for the server").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(execCommand, _, command7) {
2595
2699
  return __async(this, null, function* () {
2596
- const options = command4.optsWithGlobals();
2700
+ const options = command7.optsWithGlobals();
2597
2701
  if (options.buildName === "") {
2598
2702
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
2599
2703
  process.exit(1);
2600
2704
  }
2601
- let ctx = ctx_default(command4.optsWithGlobals());
2705
+ let ctx = ctx_default(command7.optsWithGlobals());
2602
2706
  if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
2603
2707
  ctx.log.error(`Error: Command not found "${execCommand[0]}"`);
2604
2708
  return;
@@ -2853,13 +2957,13 @@ function captureScreenshots(ctx) {
2853
2957
  else
2854
2958
  yield captureScreenshotsSync(ctx, staticConfig, browsers);
2855
2959
  delDir(`screenshots/${staticConfig.name.toLowerCase().replace(/\s/g, "_")}`);
2856
- output += `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.green("\u2713")}
2960
+ output += `${chalk__default.default.gray(staticConfig.name)} ${chalk__default.default.green("\u2713")}
2857
2961
  `;
2858
2962
  ctx.task.output = output;
2859
2963
  capturedScreenshots++;
2860
2964
  } catch (error) {
2861
2965
  ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
2862
- output += `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.red("\u2717")}
2966
+ output += `${chalk__default.default.gray(staticConfig.name)} ${chalk__default.default.red("\u2717")}
2863
2967
  `;
2864
2968
  ctx.task.output = output;
2865
2969
  }
@@ -3036,14 +3140,14 @@ function processChunk(ctx, urlConfig) {
3036
3140
  try {
3037
3141
  yield captureScreenshotsAsync(ctx, staticConfig, browsers);
3038
3142
  delDir(`screenshots/${staticConfig.name.toLowerCase().replace(/\s/g, "_")}`);
3039
- let output = `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.green("\u2713")}
3143
+ let output = `${chalk__default.default.gray(staticConfig.name)} ${chalk__default.default.green("\u2713")}
3040
3144
  `;
3041
3145
  ctx.task.output = ctx.task.output ? ctx.task.output + output : output;
3042
3146
  finalOutput += output;
3043
3147
  capturedScreenshots++;
3044
3148
  } catch (error) {
3045
3149
  ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
3046
- let output = `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.red("\u2717")}
3150
+ let output = `${chalk__default.default.gray(staticConfig.name)} ${chalk__default.default.red("\u2717")}
3047
3151
  `;
3048
3152
  ctx.task.output += output;
3049
3153
  finalOutput += output;
@@ -3077,7 +3181,7 @@ var captureScreenshots_default = (ctx) => {
3077
3181
  task.title = "Screenshots captured successfully";
3078
3182
  } catch (error) {
3079
3183
  ctx2.log.debug(error);
3080
- task.output = chalk6__default.default.gray(`${error.message}`);
3184
+ task.output = chalk__default.default.gray(`${error.message}`);
3081
3185
  throw new Error("Capturing screenshots failed");
3082
3186
  }
3083
3187
  }),
@@ -3088,14 +3192,14 @@ var captureScreenshots_default = (ctx) => {
3088
3192
 
3089
3193
  // src/commander/capture.ts
3090
3194
  var command2 = new commander.Command();
3091
- command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("-C, --parallel [number]", "Specify the number of instances per browser", parseInt).option("-F, --force", "forcefully apply the specified parallel instances per browser").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(file, _, command4) {
3195
+ command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("-C, --parallel [number]", "Specify the number of instances per browser", parseInt).option("-F, --force", "forcefully apply the specified parallel instances per browser").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(file, _, command7) {
3092
3196
  return __async(this, null, function* () {
3093
- const options = command4.optsWithGlobals();
3197
+ const options = command7.optsWithGlobals();
3094
3198
  if (options.buildName === "") {
3095
3199
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
3096
3200
  process.exit(1);
3097
3201
  }
3098
- let ctx = ctx_default(command4.optsWithGlobals());
3202
+ let ctx = ctx_default(command7.optsWithGlobals());
3099
3203
  if (!fs5__default.default.existsSync(file)) {
3100
3204
  ctx.log.error(`Web Static Config file ${file} not found.`);
3101
3205
  return;
@@ -3154,7 +3258,7 @@ var uploadScreenshots_default = (ctx) => {
3154
3258
  task.title = "Screenshots uploaded successfully";
3155
3259
  } catch (error) {
3156
3260
  ctx2.log.debug(error);
3157
- task.output = chalk6__default.default.gray(`${error.message}`);
3261
+ task.output = chalk__default.default.gray(`${error.message}`);
3158
3262
  throw new Error("Uploading screenshots failed");
3159
3263
  }
3160
3264
  }),
@@ -3169,14 +3273,14 @@ command3.name("upload").description("Upload screenshots from given directory").a
3169
3273
  return val.split(",").map((ext) => ext.trim().toLowerCase());
3170
3274
  }).option("-E, --removeExtensions", "Strips file extensions from snapshot names").option("-i, --ignoreDir <patterns>", "Comma-separated list of directories to ignore", (val) => {
3171
3275
  return val.split(",").map((pattern) => pattern.trim());
3172
- }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(directory, _, command4) {
3276
+ }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").action(function(directory, _, command7) {
3173
3277
  return __async(this, null, function* () {
3174
- const options = command4.optsWithGlobals();
3278
+ const options = command7.optsWithGlobals();
3175
3279
  if (options.buildName === "") {
3176
3280
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
3177
3281
  process.exit(1);
3178
3282
  }
3179
- let ctx = ctx_default(command4.optsWithGlobals());
3283
+ let ctx = ctx_default(command7.optsWithGlobals());
3180
3284
  if (!fs5__default.default.existsSync(directory)) {
3181
3285
  console.log(`Error: The provided directory ${directory} not found.`);
3182
3286
  return;
@@ -3254,7 +3358,7 @@ var uploadFigmaDesigns_default2 = (ctx) => {
3254
3358
  ctx2.log.debug(`Figma designs processed: ${results}`);
3255
3359
  } catch (error) {
3256
3360
  ctx2.log.debug(error);
3257
- task.output = chalk6__default.default.gray(`${error.message}`);
3361
+ task.output = chalk__default.default.gray(`${error.message}`);
3258
3362
  throw new Error("Uploading Figma designs failed");
3259
3363
  }
3260
3364
  }),
@@ -3351,17 +3455,17 @@ var uploadWebFigma_default2 = (ctx) => {
3351
3455
  throw new Error("Uploading Web Figma Screenshot failed");
3352
3456
  }
3353
3457
  if (ctx2.build.id) {
3354
- task.output = chalk6__default.default.gray(`Build Id: ${ctx2.build.id}`);
3458
+ task.output = chalk__default.default.gray(`Build Id: ${ctx2.build.id}`);
3355
3459
  let figmaOutput = yield fetchFigma_default(ctx2);
3356
3460
  const jsonObject = JSON.parse(figmaOutput);
3357
3461
  let output = JSON.stringify(jsonObject, null, 2);
3358
- task.output = task.output + "\n" + chalk6__default.default.green(`${output}`);
3462
+ task.output = task.output + "\n" + chalk__default.default.green(`${output}`);
3359
3463
  }
3360
3464
  task.title = "Web Figma images uploaded successfully to SmartUI";
3361
3465
  ctx2.log.debug(`Web Figma processed: ${results}`);
3362
3466
  } catch (error) {
3363
3467
  ctx2.log.debug(error);
3364
- task.output = chalk6__default.default.gray(`${error.message}`);
3468
+ task.output = chalk__default.default.gray(`${error.message}`);
3365
3469
  throw new Error("Uploading Web Figma Screenshots failed");
3366
3470
  }
3367
3471
  }),
@@ -3371,10 +3475,10 @@ var uploadWebFigma_default2 = (ctx) => {
3371
3475
  };
3372
3476
  var uploadFigma = new commander.Command();
3373
3477
  var uploadWebFigmaCommand = new commander.Command();
3374
- uploadFigma.name("upload-figma").description("Capture screenshots of static sites").argument("<file>", "figma design config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command4) {
3478
+ uploadFigma.name("upload-figma").description("Capture screenshots of static sites").argument("<file>", "figma design config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command7) {
3375
3479
  return __async(this, null, function* () {
3376
3480
  var _a, _b;
3377
- let ctx = ctx_default(command4.optsWithGlobals());
3481
+ let ctx = ctx_default(command7.optsWithGlobals());
3378
3482
  if (!fs5__default.default.existsSync(file)) {
3379
3483
  console.log(`Error: Figma Config file ${file} not found.`);
3380
3484
  return;
@@ -3412,10 +3516,10 @@ uploadFigma.name("upload-figma").description("Capture screenshots of static site
3412
3516
  }
3413
3517
  });
3414
3518
  });
3415
- uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots of static sites").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command4) {
3519
+ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots of static sites").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").action(function(file, _, command7) {
3416
3520
  return __async(this, null, function* () {
3417
3521
  var _a;
3418
- let ctx = ctx_default(command4.optsWithGlobals());
3522
+ let ctx = ctx_default(command7.optsWithGlobals());
3419
3523
  if (!fs5__default.default.existsSync(file)) {
3420
3524
  console.log(`Error: figma-web config file ${file} not found.`);
3421
3525
  return;
@@ -3436,7 +3540,7 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots
3436
3540
  }
3437
3541
  verifyFigmaWebConfig(ctx);
3438
3542
  } catch (error) {
3439
- ctx.log.error(chalk6__default.default.red(`Invalid figma-web config; ${error.message}`));
3543
+ ctx.log.error(chalk__default.default.red(`Invalid figma-web config; ${error.message}`));
3440
3544
  return;
3441
3545
  }
3442
3546
  let tasks = new listr2.Listr(
@@ -3464,10 +3568,112 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots
3464
3568
  }
3465
3569
  });
3466
3570
  });
3571
+ var command4 = new commander.Command();
3572
+ 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() {
3573
+ return __async(this, null, function* () {
3574
+ const options = command4.optsWithGlobals();
3575
+ if (options.buildName === "") {
3576
+ console.log(`Error: The '--buildName' option cannot be an empty string.`);
3577
+ process.exit(1);
3578
+ }
3579
+ let ctx = ctx_default(command4.optsWithGlobals());
3580
+ ctx.snapshotQueue = new Queue(ctx);
3581
+ ctx.totalSnapshots = 0;
3582
+ ctx.isStartExec = true;
3583
+ let tasks = new listr2.Listr(
3584
+ [
3585
+ auth_default(),
3586
+ startServer_default(),
3587
+ getGitInfo_default(),
3588
+ createBuild_default()
3589
+ ],
3590
+ {
3591
+ rendererOptions: {
3592
+ icon: {
3593
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: `\u2192`
3594
+ },
3595
+ color: {
3596
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
3597
+ }
3598
+ }
3599
+ }
3600
+ );
3601
+ try {
3602
+ yield tasks.run(ctx);
3603
+ startPingPolling(ctx);
3604
+ if (ctx.options.fetchResults) {
3605
+ startPolling(ctx);
3606
+ }
3607
+ } catch (error) {
3608
+ console.error("Error during server execution:", error);
3609
+ }
3610
+ });
3611
+ });
3612
+ var server_default2 = command4;
3613
+ var command5 = new commander.Command();
3614
+ function getSmartUIServerAddress() {
3615
+ const serverAddress = process.env.SMARTUI_SERVER_ADDRESS || "http://localhost:49152";
3616
+ return serverAddress;
3617
+ }
3618
+ command5.name("exec:stop").description("Stop the SmartUI server").action(function() {
3619
+ return __async(this, null, function* () {
3620
+ try {
3621
+ const serverAddress = getSmartUIServerAddress();
3622
+ console.log(chalk__default.default.yellow(`Stopping server at ${serverAddress} from terminal...`));
3623
+ const response = yield axios__default.default.post(`${serverAddress}/stop`, { timeout: 15e3 }, {
3624
+ headers: {
3625
+ "Content-Type": "application/json"
3626
+ // Ensure the correct Content-Type header
3627
+ }
3628
+ });
3629
+ if (response.status === 200) {
3630
+ console.log(chalk__default.default.green("Server stopped successfully"));
3631
+ console.log(chalk__default.default.green(`Response: ${JSON.stringify(response.data)}`));
3632
+ } else {
3633
+ console.log(chalk__default.default.red("Failed to stop server"));
3634
+ }
3635
+ } catch (error) {
3636
+ if (error.code === "ECONNABORTED") {
3637
+ console.error(chalk__default.default.red("Error: SmartUI server did not respond in 15 seconds"));
3638
+ } else {
3639
+ console.error(chalk__default.default.red("Error while stopping server"));
3640
+ }
3641
+ }
3642
+ });
3643
+ });
3644
+ var stopServer_default = command5;
3645
+ function getSmartUIServerAddress2() {
3646
+ const serverAddress = process.env.SMARTUI_SERVER_ADDRESS || "http://localhost:49152";
3647
+ return serverAddress;
3648
+ }
3649
+ var command6 = new commander.Command();
3650
+ command6.name("exec:ping").description("Ping the SmartUI server to check if it is running").action(function() {
3651
+ return __async(this, null, function* () {
3652
+ try {
3653
+ console.log(chalk__default.default.yellow("Pinging server..."));
3654
+ const serverAddress = getSmartUIServerAddress2();
3655
+ console.log(chalk__default.default.yellow(`Pinging server at ${serverAddress} from terminal...`));
3656
+ const response = yield axios__default.default.get(`${serverAddress}/ping`, { timeout: 15e3 });
3657
+ if (response.status === 200) {
3658
+ console.log(chalk__default.default.green("SmartUI Server is running"));
3659
+ console.log(chalk__default.default.green(`Response: ${JSON.stringify(response.data)}`));
3660
+ } else {
3661
+ console.log(chalk__default.default.red("Failed to reach the server"));
3662
+ }
3663
+ } catch (error) {
3664
+ if (error.code === "ECONNABORTED") {
3665
+ console.error(chalk__default.default.red("Error: SmartUI server did not respond in 15 seconds"));
3666
+ } else {
3667
+ console.error(chalk__default.default.red("SmartUI server is not running"));
3668
+ }
3669
+ }
3670
+ });
3671
+ });
3672
+ var ping_default = command6;
3467
3673
 
3468
3674
  // src/commander/commander.ts
3469
3675
  var program = new commander.Command();
3470
- program.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(uploadWebFigmaCommand);
3676
+ program.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(server_default2).addCommand(stopServer_default).addCommand(ping_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(uploadWebFigmaCommand);
3471
3677
  var commander_default = program;
3472
3678
  (function() {
3473
3679
  return __async(this, null, function* () {
@@ -3477,16 +3683,16 @@ var commander_default = program;
3477
3683
  let { data: { latestVersion, deprecated, additionalDescription } } = yield client.checkUpdate(log2);
3478
3684
  log2.info(`
3479
3685
  LambdaTest SmartUI CLI v${package_default.version}`);
3480
- log2.info(chalk6__default.default.yellow(`${additionalDescription}`));
3686
+ log2.info(chalk__default.default.yellow(`${additionalDescription}`));
3481
3687
  if (deprecated) {
3482
3688
  log2.warn(`This version is deprecated. A new version ${latestVersion} is available!`);
3483
3689
  } else if (package_default.version !== latestVersion) {
3484
- log2.info(chalk6__default.default.green(`A new version ${latestVersion} is available!`));
3690
+ log2.info(chalk__default.default.green(`A new version ${latestVersion} is available!`));
3485
3691
  } else
3486
- log2.info(chalk6__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
3692
+ log2.info(chalk__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
3487
3693
  } catch (error) {
3488
3694
  log2.debug(error);
3489
- log2.info(chalk6__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
3695
+ log2.info(chalk__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
3490
3696
  }
3491
3697
  commander_default.parse();
3492
3698
  });