@lambdatest/smartui-cli 4.0.20 → 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 +654 -500
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -4,25 +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');
19
21
  var uuid = require('uuid');
20
22
  var sharp = require('sharp');
21
23
 
22
24
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
23
25
 
24
26
  var which__default = /*#__PURE__*/_interopDefault(which);
25
- var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
27
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
26
28
  var path2__default = /*#__PURE__*/_interopDefault(path2);
27
29
  var fastify__default = /*#__PURE__*/_interopDefault(fastify);
28
30
  var fs5__default = /*#__PURE__*/_interopDefault(fs5);
@@ -30,6 +32,7 @@ var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
30
32
  var addErrors__default = /*#__PURE__*/_interopDefault(addErrors);
31
33
  var FormData__default = /*#__PURE__*/_interopDefault(FormData);
32
34
  var axios__default = /*#__PURE__*/_interopDefault(axios);
35
+ var https__default = /*#__PURE__*/_interopDefault(https);
33
36
  var spawn__default = /*#__PURE__*/_interopDefault(spawn);
34
37
  var sharp__default = /*#__PURE__*/_interopDefault(sharp);
35
38
 
@@ -416,7 +419,6 @@ var constants_default = {
416
419
  "Xperia 10 IV": { os: "android", viewport: { width: 412, height: 832 } },
417
420
  "Honeywell CT40": { os: "android", viewport: { width: 360, height: 512 } }
418
421
  },
419
- FIGMA_API: "https://api.figma.com/v1/",
420
422
  DEFAULT_FIGMA_CONFIG: {
421
423
  "depth": 2,
422
424
  "figma_config": [
@@ -961,9 +963,285 @@ var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
961
963
  var validateSnapshot = ajv.compile(SnapshotSchema);
962
964
  var validateFigmaDesignConfig = ajv.compile(FigmaDesignConfigSchema);
963
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
+ }
964
1242
 
965
1243
  // src/lib/server.ts
966
- var server_default = (ctx) => __async(undefined, null, function* () {
1244
+ var server_default = (ctx) => __async(void 0, null, function* () {
967
1245
  const server = fastify__default.default({
968
1246
  logger: {
969
1247
  level: "debug",
@@ -981,7 +1259,7 @@ var server_default = (ctx) => __async(undefined, null, function* () {
981
1259
  server.get("/domserializer", opts, (request, reply) => {
982
1260
  reply.code(200).send({ data: { dom: SMARTUI_DOM } });
983
1261
  });
984
- server.post("/snapshot", opts, (request, reply) => __async(undefined, null, function* () {
1262
+ server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
985
1263
  var _a;
986
1264
  let replyCode;
987
1265
  let replyBody;
@@ -1000,6 +1278,48 @@ var server_default = (ctx) => __async(undefined, null, function* () {
1000
1278
  }
1001
1279
  return reply.code(replyCode).send(replyBody);
1002
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
+ });
1003
1323
  yield server.listen({ port: ctx.options.port });
1004
1324
  let { port } = server.addresses()[0];
1005
1325
  process.env.SMARTUI_SERVER_ADDRESS = `http://localhost:${port}`;
@@ -1025,7 +1345,9 @@ var env_default = () => {
1025
1345
  LT_SDK_DEBUG,
1026
1346
  BASELINE_BRANCH,
1027
1347
  CURRENT_BRANCH,
1028
- PROJECT_NAME
1348
+ PROJECT_NAME,
1349
+ SMARTUI_API_PROXY,
1350
+ SMARTUI_API_SKIP_CERTIFICATES
1029
1351
  } = process.env;
1030
1352
  return {
1031
1353
  PROJECT_TOKEN,
@@ -1043,7 +1365,9 @@ var env_default = () => {
1043
1365
  CURRENT_BRANCH,
1044
1366
  LT_SDK_DEBUG: LT_SDK_DEBUG === "true",
1045
1367
  SMARTUI_DO_NOT_USE_CAPTURED_COOKIES: SMARTUI_DO_NOT_USE_CAPTURED_COOKIES === "true",
1046
- PROJECT_NAME
1368
+ PROJECT_NAME,
1369
+ SMARTUI_API_PROXY,
1370
+ SMARTUI_API_SKIP_CERTIFICATES: SMARTUI_API_SKIP_CERTIFICATES === "true"
1047
1371
  };
1048
1372
  };
1049
1373
  var logContext = {};
@@ -1062,7 +1386,7 @@ var logger = winston.createLogger({
1062
1386
  let message = typeof info.message === "object" ? JSON.stringify(info.message).trim() : info.message.trim();
1063
1387
  switch (info.level) {
1064
1388
  case "warn":
1065
- message = chalk6__default.default.yellow(message);
1389
+ message = chalk__default.default.yellow(message);
1066
1390
  break;
1067
1391
  }
1068
1392
  return info.level === "info" ? message : `[${contextString}:${info.level}] ` + message;
@@ -1084,16 +1408,16 @@ var logger_default = logger;
1084
1408
  var startServer_default = (ctx) => {
1085
1409
  return {
1086
1410
  title: `Setting up SmartUI server`,
1087
- task: (ctx2, task) => __async(undefined, null, function* () {
1411
+ task: (ctx2, task) => __async(void 0, null, function* () {
1088
1412
  var _a;
1089
1413
  updateLogContext({ task: "startServer" });
1090
1414
  try {
1091
1415
  ctx2.server = yield server_default(ctx2);
1092
- 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}`);
1093
1417
  task.title = "SmartUI started";
1094
1418
  } catch (error) {
1095
1419
  ctx2.log.debug(error);
1096
- task.output = chalk6__default.default.gray(error.message);
1420
+ task.output = chalk__default.default.gray(error.message);
1097
1421
  throw new Error("SmartUI server setup failed");
1098
1422
  }
1099
1423
  }),
@@ -1103,21 +1427,21 @@ var startServer_default = (ctx) => {
1103
1427
  var auth_default = (ctx) => {
1104
1428
  return {
1105
1429
  title: `Authenticating with SmartUI`,
1106
- task: (ctx2, task) => __async(undefined, null, function* () {
1430
+ task: (ctx2, task) => __async(void 0, null, function* () {
1107
1431
  updateLogContext({ task: "auth" });
1108
1432
  try {
1109
1433
  const authResult = yield ctx2.client.auth(ctx2.log, ctx2.env);
1110
1434
  if (authResult === 2) {
1111
- 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`);
1112
1436
  } else if (authResult === 0) {
1113
- 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()}'`);
1114
1438
  } else if (authResult === 1) {
1115
- 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}'`);
1116
1440
  }
1117
1441
  task.title = "Authenticated with SmartUI";
1118
1442
  } catch (error) {
1119
1443
  ctx2.log.debug(error);
1120
- task.output = chalk6__default.default.gray(error.message);
1444
+ task.output = chalk__default.default.gray(error.message);
1121
1445
  throw new Error("Authentication failed");
1122
1446
  }
1123
1447
  }),
@@ -1126,66 +1450,36 @@ var auth_default = (ctx) => {
1126
1450
  };
1127
1451
 
1128
1452
  // package.json
1129
- var version = "4.0.20";
1453
+ var version = "4.0.21";
1130
1454
  var package_default = {
1131
1455
  name: "@lambdatest/smartui-cli",
1132
- version,
1133
- description: "A command line interface (CLI) to run SmartUI tests on LambdaTest",
1134
- files: [
1135
- "dist/**/*"
1136
- ],
1137
- scripts: {
1138
- build: "tsup",
1139
- release: "pnpm run build && pnpm publish --access public --no-git-checks",
1140
- "local-build": "pnpm run build && pnpm pack"
1141
- },
1142
- bin: {
1143
- smartui: "./dist/index.cjs"
1144
- },
1145
- type: "module",
1146
- keywords: [
1147
- "lambdatest",
1148
- "smartui",
1149
- "cli"
1150
- ],
1151
- author: "LambdaTest <keys@lambdatest.com>",
1152
- license: "MIT",
1153
- dependencies: {
1154
- "@playwright/browser-chromium": "^1.47.2",
1155
- "@playwright/browser-firefox": "^1.47.2",
1156
- "@playwright/browser-webkit": "^1.47.2",
1157
- "@playwright/test": "^1.47.2",
1158
- "@types/cross-spawn": "^6.0.4",
1159
- "@types/node": "^20.8.9",
1160
- "@types/which": "^3.0.2",
1161
- ajv: "^8.12.0",
1162
- "ajv-errors": "^3.0.0",
1163
- axios: "^1.6.0",
1164
- chalk: "^4.1.2",
1165
- commander: "^11.1.0",
1166
- "cross-spawn": "^7.0.3",
1167
- fastify: "^4.24.3",
1168
- "form-data": "^4.0.0",
1169
- listr2: "^7.0.1",
1170
- sharp: "^0.33.4",
1171
- tsup: "^7.2.0",
1172
- uuid: "^11.0.3",
1173
- which: "^4.0.0",
1174
- winston: "^3.10.0"
1175
- },
1176
- devDependencies: {
1177
- typescript: "^5.3.2"
1178
- }
1179
- };
1456
+ version};
1180
1457
  var httpClient = class {
1181
- 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 }) {
1182
1459
  this.projectToken = PROJECT_TOKEN || "";
1183
1460
  this.projectName = PROJECT_NAME || "";
1184
1461
  this.username = LT_USERNAME || "";
1185
1462
  this.accessKey = LT_ACCESS_KEY || "";
1186
- this.axiosInstance = axios__default.default.create({
1187
- baseURL: SMARTUI_CLIENT_API_URL
1188
- });
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);
1189
1483
  this.axiosInstance.interceptors.request.use((config) => {
1190
1484
  config.headers["projectToken"] = this.projectToken;
1191
1485
  config.headers["projectName"] = this.projectName;
@@ -1215,7 +1509,7 @@ var httpClient = class {
1215
1509
  headers: error.response.headers,
1216
1510
  body: error.response.data
1217
1511
  })}`);
1218
- throw new Error(((_a = error.response.data.error) == null ? undefined : _a.message) || error.response.data.message || error.response.data);
1512
+ throw new Error(((_a = error.response.data.error) == null ? void 0 : _a.message) || error.response.data.message || error.response.data);
1219
1513
  }
1220
1514
  if (error.request) {
1221
1515
  log2.debug(`http request failed: ${error.toJSON()}`);
@@ -1248,14 +1542,15 @@ var httpClient = class {
1248
1542
  }
1249
1543
  });
1250
1544
  }
1251
- createBuild(git, config, log2, buildName) {
1545
+ createBuild(git, config, log2, buildName, isStartExec) {
1252
1546
  return this.request({
1253
1547
  url: "/build",
1254
1548
  method: "POST",
1255
1549
  data: {
1256
1550
  git,
1257
1551
  config,
1258
- buildName
1552
+ buildName,
1553
+ isStartExec
1259
1554
  }
1260
1555
  }, log2);
1261
1556
  }
@@ -1266,6 +1561,15 @@ var httpClient = class {
1266
1561
  params: { buildId, baseline }
1267
1562
  }, log2);
1268
1563
  }
1564
+ ping(buildId, log2) {
1565
+ return this.request({
1566
+ url: "/build/ping",
1567
+ method: "POST",
1568
+ data: {
1569
+ buildId
1570
+ }
1571
+ }, log2);
1572
+ }
1269
1573
  finalizeBuild(buildId, totalSnapshots, log2) {
1270
1574
  let params = { buildId };
1271
1575
  if (totalSnapshots > -1)
@@ -1493,7 +1797,7 @@ var ctx_default = (options) => {
1493
1797
  }
1494
1798
  if (config.web) {
1495
1799
  webConfig = { browsers: config.web.browsers, viewports: [] };
1496
- for (let viewport of (_b = config.web) == null ? undefined : _b.viewports)
1800
+ for (let viewport of (_b = config.web) == null ? void 0 : _b.viewports)
1497
1801
  webConfig.viewports.push({ width: viewport[0], height: viewport[1] || 0 });
1498
1802
  }
1499
1803
  if (config.mobile) {
@@ -1547,396 +1851,141 @@ var ctx_default = (options) => {
1547
1851
  port,
1548
1852
  ignoreResolutions: resolutionOff,
1549
1853
  fileExtension: extensionFiles,
1550
- stripExtension: ignoreStripExtension,
1551
- ignorePattern: ignoreFilePattern,
1552
- fetchResults: fetchResultObj,
1553
- fetchResultsFileName: fetchResultsFileObj
1554
- },
1555
- cliVersion: version,
1556
- totalSnapshots: -1
1557
- };
1558
- };
1559
- function executeCommand(command4) {
1560
- let dst = process.cwd();
1561
- try {
1562
- return child_process.execSync(command4, {
1563
- cwd: dst,
1564
- stdio: ["ignore"],
1565
- encoding: "utf-8"
1566
- });
1567
- } catch (error) {
1568
- throw new Error(error.message);
1569
- }
1570
- }
1571
- function isGitRepo() {
1572
- try {
1573
- executeCommand("git status");
1574
- return true;
1575
- } catch (error) {
1576
- return false;
1577
- }
1578
- }
1579
- var git_default = (ctx) => {
1580
- if (ctx.env.SMARTUI_GIT_INFO_FILEPATH) {
1581
- let gitInfo = JSON.parse(fs5__default.default.readFileSync(ctx.env.SMARTUI_GIT_INFO_FILEPATH, "utf-8"));
1582
- return {
1583
- branch: ctx.env.CURRENT_BRANCH || gitInfo.branch || "",
1584
- commitId: gitInfo.commit_id.slice(0, 6) || "",
1585
- commitMessage: gitInfo.commit_body || "",
1586
- commitAuthor: gitInfo.commit_author || "",
1587
- githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${gitInfo.commit_id}` : "",
1588
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
1589
- };
1590
- } else {
1591
- const splitCharacter = "<##>";
1592
- const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
1593
- const command4 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
1594
- let res = executeCommand(command4).split(splitCharacter);
1595
- var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
1596
- var branch = ctx.env.CURRENT_BRANCH || branchAndTags[0];
1597
- branchAndTags.slice(1);
1598
- return {
1599
- branch: branch || "",
1600
- commitId: res[0] || "",
1601
- commitMessage: res[2] || "",
1602
- commitAuthor: res[7] || "",
1603
- githubURL: ctx.env.GITHUB_ACTIONS ? `${constants_default.GITHUB_API_HOST}/repos/${process.env.GITHUB_REPOSITORY}/statuses/${res[1]}` : "",
1604
- baselineBranch: ctx.env.BASELINE_BRANCH || ""
1605
- };
1606
- }
1607
- };
1608
- var getGitInfo_default = (ctx) => {
1609
- return {
1610
- title: `Fetching git repo details`,
1611
- skip: (ctx2) => {
1612
- return !isGitRepo() && !ctx2.env.SMARTUI_GIT_INFO_FILEPATH ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
1613
- },
1614
- task: (ctx2, task) => __async(undefined, null, function* () {
1615
- if (ctx2.env.CURRENT_BRANCH && ctx2.env.CURRENT_BRANCH.trim() === "") {
1616
- throw new Error("Error: The environment variable CURRENT_BRANCH cannot be empty.");
1617
- }
1618
- try {
1619
- ctx2.git = git_default(ctx2);
1620
- task.output = chalk6__default.default.gray(`branch: ${ctx2.git.branch}, commit: ${ctx2.git.commitId}, author: ${ctx2.git.commitAuthor}`);
1621
- task.title = "Fetched git information";
1622
- } catch (error) {
1623
- ctx2.log.debug(error);
1624
- task.output = chalk6__default.default.gray(`${error.message}`);
1625
- throw new Error("Error fetching git repo details");
1626
- }
1627
- }),
1628
- rendererOptions: { persistentOutput: true }
1629
- };
1630
- };
1631
- var createBuild_default = (ctx) => {
1632
- return {
1633
- title: `Creating SmartUI build`,
1634
- task: (ctx2, task) => __async(undefined, null, function* () {
1635
- updateLogContext({ task: "createBuild" });
1636
- try {
1637
- let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log, ctx2.build.name);
1638
- ctx2.build = {
1639
- id: resp.data.buildId,
1640
- name: resp.data.buildName,
1641
- url: resp.data.buildURL,
1642
- baseline: resp.data.baseline,
1643
- useKafkaFlow: resp.data.useKafkaFlow || false
1644
- };
1645
- task.output = chalk6__default.default.gray(`build id: ${resp.data.buildId}`);
1646
- task.title = "SmartUI build created";
1647
- } catch (error) {
1648
- ctx2.log.debug(error);
1649
- task.output = chalk6__default.default.gray(error.message);
1650
- throw new Error("SmartUI build creation failed");
1651
- }
1652
- }),
1653
- rendererOptions: { persistentOutput: true }
1654
- };
1655
- };
1656
- var isPollingActive = false;
1657
- function delDir(dir) {
1658
- if (fs5__default.default.existsSync(dir)) {
1659
- fs5__default.default.rmSync(dir, { recursive: true });
1660
- }
1661
- }
1662
- function scrollToBottomAndBackToTop({
1663
- frequency = 100,
1664
- timing = 8,
1665
- remoteWindow = window
1666
- } = {}) {
1667
- return new Promise((resolve) => {
1668
- let scrolls = 1;
1669
- let scrollLength = remoteWindow.document.body.scrollHeight / frequency;
1670
- (function scroll() {
1671
- let scrollBy = scrollLength * scrolls;
1672
- remoteWindow.setTimeout(() => {
1673
- remoteWindow.scrollTo(0, scrollBy);
1674
- if (scrolls < frequency) {
1675
- scrolls += 1;
1676
- scroll();
1677
- }
1678
- if (scrolls === frequency) {
1679
- remoteWindow.setTimeout(() => {
1680
- remoteWindow.scrollTo(0, 0);
1681
- resolve();
1682
- }, timing);
1683
- }
1684
- }, timing);
1685
- })();
1686
- });
1687
- }
1688
- function launchBrowsers(ctx) {
1689
- return __async(this, null, function* () {
1690
- var _a;
1691
- let browsers = {};
1692
- const isHeadless = ((_a = process.env.HEADLESS) == null ? undefined : _a.toLowerCase()) === "false" ? false : true;
1693
- let launchOptions = { headless: isHeadless };
1694
- if (ctx.config.web) {
1695
- for (const browser of ctx.config.web.browsers) {
1696
- switch (browser) {
1697
- case constants_default.CHROME:
1698
- browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1699
- break;
1700
- case constants_default.SAFARI:
1701
- browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1702
- break;
1703
- case constants_default.FIREFOX:
1704
- browsers[constants_default.FIREFOX] = yield test.firefox.launch(launchOptions);
1705
- break;
1706
- case constants_default.EDGE:
1707
- launchOptions.args = ["--headless=new"];
1708
- browsers[constants_default.EDGE] = yield test.chromium.launch(__spreadValues({ channel: constants_default.EDGE_CHANNEL }, launchOptions));
1709
- break;
1710
- }
1711
- }
1712
- }
1713
- if (ctx.config.mobile) {
1714
- for (const device of ctx.config.mobile.devices) {
1715
- if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "android" && !browsers[constants_default.CHROME])
1716
- browsers[constants_default.CHROME] = yield test.chromium.launch(launchOptions);
1717
- else if (constants_default.SUPPORTED_MOBILE_DEVICES[device].os === "ios" && !browsers[constants_default.SAFARI])
1718
- browsers[constants_default.SAFARI] = yield test.webkit.launch(launchOptions);
1719
- }
1720
- }
1721
- return browsers;
1722
- });
1723
- }
1724
- function closeBrowsers(browsers) {
1725
- return __async(this, null, function* () {
1726
- var _a;
1727
- for (const browserName of Object.keys(browsers))
1728
- yield (_a = browsers[browserName]) == null ? undefined : _a.close();
1729
- });
1730
- }
1731
- function getWebRenderViewports(ctx) {
1732
- let webRenderViewports = [];
1733
- if (ctx.config.web) {
1734
- for (const viewport of ctx.config.web.viewports) {
1735
- webRenderViewports.push({
1736
- viewport,
1737
- viewportString: `${viewport.width}${viewport.height ? "x" + viewport.height : ""}`,
1738
- fullPage: viewport.height ? false : true,
1739
- device: false
1740
- });
1741
- }
1742
- }
1743
- return webRenderViewports;
1744
- }
1745
- function getWebRenderViewportsForOptions(options) {
1746
- let webRenderViewports = [];
1747
- if (options.web && Array.isArray(options.web.viewports)) {
1748
- for (const viewport of options.web.viewports) {
1749
- if (Array.isArray(viewport) && viewport.length > 0) {
1750
- let viewportObj = {
1751
- width: viewport[0]
1752
- };
1753
- if (viewport.length > 1) {
1754
- viewportObj.height = viewport[1];
1755
- }
1756
- webRenderViewports.push({
1757
- viewport: viewportObj,
1758
- viewportString: `${viewport[0]}${viewport[1] ? "x" + viewport[1] : ""}`,
1759
- fullPage: viewport.length === 1,
1760
- device: false
1761
- });
1762
- }
1763
- }
1764
- }
1765
- return webRenderViewports;
1766
- }
1767
- function getMobileRenderViewports(ctx) {
1768
- var _a;
1769
- let mobileRenderViewports = {};
1770
- mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1771
- mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1772
- if (ctx.config.mobile) {
1773
- for (const device of ctx.config.mobile.devices) {
1774
- let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1775
- let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1776
- let portrait = ctx.config.mobile.orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT ? true : false;
1777
- (_a = mobileRenderViewports[os]) == null ? undefined : _a.push({
1778
- viewport: { width: portrait ? width : height, height: portrait ? height : width },
1779
- viewportString: `${device} (${ctx.config.mobile.orientation})`,
1780
- fullPage: ctx.config.mobile.fullPage,
1781
- device: true,
1782
- os
1783
- });
1784
- }
1854
+ stripExtension: ignoreStripExtension,
1855
+ ignorePattern: ignoreFilePattern,
1856
+ fetchResults: fetchResultObj,
1857
+ fetchResultsFileName: fetchResultsFileObj
1858
+ },
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);
1785
1874
  }
1786
- return mobileRenderViewports;
1787
1875
  }
1788
- function getMobileRenderViewportsForOptions(options) {
1789
- var _a;
1790
- let mobileRenderViewports = {};
1791
- mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
1792
- mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
1793
- if (options.mobile) {
1794
- for (const device of options.mobile.devices) {
1795
- let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
1796
- let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
1797
- let orientation = options.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
1798
- let portrait = orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT;
1799
- let fullPage;
1800
- if (options.mobile.fullPage === undefined || options.mobile.fullPage) {
1801
- fullPage = true;
1802
- } else {
1803
- fullPage = false;
1804
- }
1805
- (_a = mobileRenderViewports[os]) == null ? undefined : _a.push({
1806
- viewport: { width: portrait ? width : height, height: portrait ? height : width },
1807
- viewportString: `${device} (${orientation})`,
1808
- fullPage,
1809
- device: true,
1810
- os
1811
- });
1812
- }
1876
+ function isGitRepo() {
1877
+ try {
1878
+ executeCommand("git status");
1879
+ return true;
1880
+ } catch (error) {
1881
+ return false;
1813
1882
  }
1814
- return mobileRenderViewports;
1815
- }
1816
- function getRenderViewports(ctx) {
1817
- let mobileRenderViewports = getMobileRenderViewports(ctx);
1818
- let webRenderViewports = getWebRenderViewports(ctx);
1819
- return [
1820
- ...webRenderViewports,
1821
- ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1822
- ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1823
- ];
1824
- }
1825
- function getRenderViewportsForOptions(options) {
1826
- let mobileRenderViewports = getMobileRenderViewportsForOptions(options);
1827
- let webRenderViewports = getWebRenderViewportsForOptions(options);
1828
- return [
1829
- ...webRenderViewports,
1830
- ...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
1831
- ...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
1832
- ];
1833
1883
  }
1834
- process.on("SIGINT", () => {
1835
- if (isPollingActive) {
1836
- console.log("Fetching results interrupted. Exiting...");
1837
- 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
+ };
1838
1895
  } else {
1839
- 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
+ };
1840
1911
  }
1841
- process.exit(0);
1842
- });
1843
- function startPolling(ctx, task) {
1844
- return __async(this, null, function* () {
1845
- ctx.log.info("Fetching results in progress....");
1846
- isPollingActive = true;
1847
- const intervalId = setInterval(() => __async(this, null, function* () {
1848
- if (!isPollingActive) {
1849
- clearInterval(intervalId);
1850
- 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.");
1851
1922
  }
1852
1923
  try {
1853
- const resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log);
1854
- if (!resp.build) {
1855
- ctx.log.info("Error: Build data is null.");
1856
- clearInterval(intervalId);
1857
- isPollingActive = false;
1858
- }
1859
- fs5__default.default.writeFileSync(ctx.options.fetchResultsFileName, JSON.stringify(resp, null, 2));
1860
- ctx.log.debug(`Updated results in ${ctx.options.fetchResultsFileName}`);
1861
- if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
1862
- clearInterval(intervalId);
1863
- ctx.log.info(`Fetching results completed. Final results written to ${ctx.options.fetchResultsFileName}`);
1864
- isPollingActive = false;
1865
- let totalScreenshotsWithMismatches = 0;
1866
- let totalVariantsWithMismatches = 0;
1867
- const totalScreenshots = Object.keys(resp.screenshots || {}).length;
1868
- let totalVariants = 0;
1869
- for (const [screenshot, variants] of Object.entries(resp.screenshots || {})) {
1870
- let screenshotHasMismatch = false;
1871
- let variantMismatchCount = 0;
1872
- totalVariants += variants.length;
1873
- for (const variant of variants) {
1874
- if (variant.mismatch_percentage > 0) {
1875
- screenshotHasMismatch = true;
1876
- variantMismatchCount++;
1877
- }
1878
- }
1879
- if (screenshotHasMismatch) {
1880
- totalScreenshotsWithMismatches++;
1881
- totalVariantsWithMismatches += variantMismatchCount;
1882
- }
1883
- }
1884
- ctx.log.info(
1885
- chalk6__default.default.green.bold(
1886
- `
1887
- Summary of Mismatches:
1888
- ${chalk6__default.default.yellow("Total Variants with Mismatches:")} ${chalk6__default.default.white(totalVariantsWithMismatches)} out of ${chalk6__default.default.white(totalVariants)}
1889
- ${chalk6__default.default.yellow("Total Screenshots with Mismatches:")} ${chalk6__default.default.white(totalScreenshotsWithMismatches)} out of ${chalk6__default.default.white(totalScreenshots)}
1890
- ${chalk6__default.default.yellow("Branch Name:")} ${chalk6__default.default.white(resp.build.branch)}
1891
- ${chalk6__default.default.yellow("Project Name:")} ${chalk6__default.default.white(resp.project.name)}
1892
- ${chalk6__default.default.yellow("Build ID:")} ${chalk6__default.default.white(resp.build.build_id)}
1893
- `
1894
- )
1895
- );
1896
- }
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";
1897
1927
  } catch (error) {
1898
- if (error.message.includes("ENOTFOUND")) {
1899
- ctx.log.error("Error: Network error occurred while fetching build results. Please check your connection and try again.");
1900
- clearInterval(intervalId);
1901
- } else {
1902
- ctx.log.error(`Error fetching screenshot data: ${error.message}`);
1903
- }
1904
- clearInterval(intervalId);
1905
- 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");
1906
1931
  }
1907
- }), 5e3);
1908
- });
1909
- }
1910
-
1911
- // 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
+ };
1912
1961
  var exec_default = (ctx) => {
1913
1962
  var _a;
1914
1963
  return {
1915
- title: `Executing '${(_a = ctx.args.execCommand) == null ? undefined : _a.join(" ")}'`,
1916
- task: (ctx2, task) => __async(undefined, null, function* () {
1964
+ title: `Executing '${(_a = ctx.args.execCommand) == null ? void 0 : _a.join(" ")}'`,
1965
+ task: (ctx2, task) => __async(void 0, null, function* () {
1917
1966
  if (ctx2.options.fetchResults) {
1918
1967
  startPolling(ctx2);
1919
1968
  }
1920
1969
  updateLogContext({ task: "exec" });
1921
1970
  return new Promise((resolve, reject) => {
1922
1971
  var _a2, _b, _c;
1923
- const childProcess = spawn__default.default(ctx2.args.execCommand[0], (_a2 = ctx2.args.execCommand) == null ? undefined : _a2.slice(1));
1972
+ const childProcess = spawn__default.default(ctx2.args.execCommand[0], (_a2 = ctx2.args.execCommand) == null ? void 0 : _a2.slice(1));
1924
1973
  let totalOutput = "";
1925
1974
  const output = listr2.createWritable((chunk) => {
1926
1975
  totalOutput += chunk;
1927
- task.output = chalk6__default.default.gray(totalOutput);
1976
+ task.output = chalk__default.default.gray(totalOutput);
1928
1977
  });
1929
- (_b = childProcess.stdout) == null ? undefined : _b.pipe(output);
1930
- (_c = childProcess.stderr) == null ? undefined : _c.pipe(output);
1978
+ (_b = childProcess.stdout) == null ? void 0 : _b.pipe(output);
1979
+ (_c = childProcess.stderr) == null ? void 0 : _c.pipe(output);
1931
1980
  childProcess.on("error", (error) => {
1932
1981
  var _a3;
1933
- task.output = chalk6__default.default.gray(`error: ${error.message}`);
1934
- throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? undefined : _a3.join(" ")}' failed`);
1982
+ task.output = chalk__default.default.gray(`error: ${error.message}`);
1983
+ throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' failed`);
1935
1984
  });
1936
- childProcess.on("close", (code, signal) => __async(undefined, null, function* () {
1985
+ childProcess.on("close", (code, signal) => __async(void 0, null, function* () {
1937
1986
  var _a3;
1938
1987
  if (code !== null) {
1939
- task.title = `Execution of '${(_a3 = ctx2.args.execCommand) == null ? undefined : _a3.join(" ")}' completed; exited with code ${code}`;
1988
+ task.title = `Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' completed; exited with code ${code}`;
1940
1989
  } else if (signal !== null) {
1941
1990
  throw new Error(`Child process killed with signal ${signal}`);
1942
1991
  }
@@ -1951,7 +2000,7 @@ var exec_default = (ctx) => {
1951
2000
  var processSnapshot_default = (ctx) => {
1952
2001
  return {
1953
2002
  title: `Processing snapshots`,
1954
- task: (ctx2, task) => __async(undefined, null, function* () {
2003
+ task: (ctx2, task) => __async(void 0, null, function* () {
1955
2004
  var _a, _b;
1956
2005
  try {
1957
2006
  if (ctx2.config.delayedUpload) {
@@ -1973,19 +2022,19 @@ var processSnapshot_default = (ctx) => {
1973
2022
  let output = "";
1974
2023
  for (let snapshot of (_b = ctx2.snapshotQueue) == null ? void 0 : _b.getProcessedSnapshots()) {
1975
2024
  if (snapshot.error)
1976
- 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}
1977
2026
  [error] ${snapshot.error}`)}
1978
2027
  `;
1979
2028
  else
1980
- output += `${chalk6__default.default.green("\u2713")} ${chalk6__default.default.gray(snapshot.name)}
1981
- ${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] ")}
1982
2031
  `) : ""}`;
1983
2032
  }
1984
2033
  task.output = output;
1985
2034
  task.title = "Processed snapshots";
1986
2035
  } catch (error) {
1987
2036
  ctx2.log.debug(error);
1988
- task.output = chalk6__default.default.gray(error.message);
2037
+ task.output = chalk__default.default.gray(error.message);
1989
2038
  throw new Error("Processing of snapshots failed");
1990
2039
  }
1991
2040
  }),
@@ -1995,16 +2044,16 @@ ${snapshot.warnings.length ? chalk6__default.default.gray(`[warning] ${snapshot.
1995
2044
  var finalizeBuild_default = (ctx) => {
1996
2045
  return {
1997
2046
  title: `Finalizing build`,
1998
- task: (ctx2, task) => __async(undefined, null, function* () {
2047
+ task: (ctx2, task) => __async(void 0, null, function* () {
1999
2048
  var _a, _b;
2000
2049
  updateLogContext({ task: "finalizeBuild" });
2001
2050
  try {
2002
2051
  yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
2003
- task.output = chalk6__default.default.gray(`build url: ${ctx2.build.url}`);
2052
+ task.output = chalk__default.default.gray(`build url: ${ctx2.build.url}`);
2004
2053
  task.title = "Finalized build";
2005
2054
  } catch (error) {
2006
2055
  ctx2.log.debug(error);
2007
- task.output = chalk6__default.default.gray(error.message);
2056
+ task.output = chalk__default.default.gray(error.message);
2008
2057
  throw new Error("Finalize build failed");
2009
2058
  }
2010
2059
  try {
@@ -2031,7 +2080,7 @@ function processSnapshot(snapshot, ctx) {
2031
2080
  var _a, _b;
2032
2081
  updateLogContext({ task: "discovery" });
2033
2082
  ctx.log.debug(`Processing snapshot ${snapshot.name} ${snapshot.url}`);
2034
- const isHeadless = ((_a = process.env.HEADLESS) == null ? undefined : _a.toLowerCase()) === "false" ? false : true;
2083
+ const isHeadless = ((_a = process.env.HEADLESS) == null ? void 0 : _a.toLowerCase()) === "false" ? false : true;
2035
2084
  let launchOptions = {
2036
2085
  headless: isHeadless,
2037
2086
  args: constants_default.LAUNCH_ARGS
@@ -2040,7 +2089,7 @@ function processSnapshot(snapshot, ctx) {
2040
2089
  javaScriptEnabled: ctx.config.cliEnableJavaScript,
2041
2090
  userAgent: constants_default.CHROME_USER_AGENT
2042
2091
  };
2043
- if (!((_b = ctx.browser) == null ? undefined : _b.isConnected())) {
2092
+ if (!((_b = ctx.browser) == null ? void 0 : _b.isConnected())) {
2044
2093
  if (ctx.env.HTTP_PROXY || ctx.env.HTTPS_PROXY)
2045
2094
  launchOptions.proxy = { server: ctx.env.HTTP_PROXY || ctx.env.HTTPS_PROXY };
2046
2095
  if (ctx.env.SMARTUI_HTTP_PROXY || ctx.env.SMARTUI_HTTPS_PROXY)
@@ -2173,7 +2222,7 @@ function processSnapshot(snapshot, ctx) {
2173
2222
  const isNotAllEmpty = (obj) => {
2174
2223
  var _a2;
2175
2224
  for (let key in obj)
2176
- if ((_a2 = obj[key]) == null ? undefined : _a2.length)
2225
+ if ((_a2 = obj[key]) == null ? void 0 : _a2.length)
2177
2226
  return true;
2178
2227
  return false;
2179
2228
  };
@@ -2301,11 +2350,11 @@ function processSnapshot(snapshot, ctx) {
2301
2350
  return DEFAULT_HEIGHT;
2302
2351
  }
2303
2352
  const measurements = [
2304
- (body == null ? undefined : body.scrollHeight) || 0,
2305
- (body == null ? undefined : body.offsetHeight) || 0,
2306
- (html == null ? undefined : html.clientHeight) || 0,
2307
- (html == null ? undefined : html.scrollHeight) || 0,
2308
- (html == null ? undefined : html.offsetHeight) || 0
2353
+ (body == null ? void 0 : body.scrollHeight) || 0,
2354
+ (body == null ? void 0 : body.offsetHeight) || 0,
2355
+ (html == null ? void 0 : html.clientHeight) || 0,
2356
+ (html == null ? void 0 : html.scrollHeight) || 0,
2357
+ (html == null ? void 0 : html.offsetHeight) || 0
2309
2358
  ];
2310
2359
  const allMeasurementsInvalid = measurements.every((measurement) => !measurement);
2311
2360
  if (allMeasurementsInvalid) {
@@ -2420,7 +2469,7 @@ var Queue = class {
2420
2469
  }
2421
2470
  generateWebVariants(snapshot, webConfig) {
2422
2471
  var _a, _b, _c;
2423
- const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? undefined : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
2472
+ const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? void 0 : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
2424
2473
  const viewports = webConfig.viewports || [];
2425
2474
  for (const browser of browsers) {
2426
2475
  for (const viewport of viewports) {
@@ -2434,7 +2483,7 @@ var Queue = class {
2434
2483
  generateMobileVariants(snapshot, mobileConfig) {
2435
2484
  var _a, _b, _c;
2436
2485
  const devices = mobileConfig.devices || [];
2437
- const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? undefined : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
2486
+ const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? void 0 : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
2438
2487
  for (const device of devices) {
2439
2488
  const variant = `${snapshot.name}_${device}_${orientation}`;
2440
2489
  this.variants.push(variant);
@@ -2516,7 +2565,7 @@ var Queue = class {
2516
2565
  }
2517
2566
  filterWebVariants(snapshot, webConfig) {
2518
2567
  var _a, _b, _c;
2519
- const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? undefined : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
2568
+ const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? void 0 : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
2520
2569
  const viewports = webConfig.viewports || [];
2521
2570
  let allVariantsDropped = true;
2522
2571
  if (!snapshot.options) {
@@ -2554,8 +2603,8 @@ var Queue = class {
2554
2603
  snapshot.options = {};
2555
2604
  }
2556
2605
  const devices = mobileConfig.devices || [];
2557
- const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? undefined : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
2558
- const fullPage = (_f = (_e = mobileConfig.fullPage) != null ? _e : (_d = this.ctx.config.mobile) == null ? undefined : _d.fullPage) != null ? _f : true;
2606
+ const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? void 0 : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
2607
+ const fullPage = (_f = (_e = mobileConfig.fullPage) != null ? _e : (_d = this.ctx.config.mobile) == null ? void 0 : _d.fullPage) != null ? _f : true;
2559
2608
  let allVariantsDropped = true;
2560
2609
  snapshot.options.mobile = { devices: [], orientation: constants_default.MOBILE_ORIENTATION_PORTRAIT, fullPage };
2561
2610
  for (const device of devices) {
@@ -2580,6 +2629,9 @@ var Queue = class {
2580
2629
  try {
2581
2630
  this.processingSnapshot = snapshot == null ? void 0 : snapshot.name;
2582
2631
  let drop = false;
2632
+ if (this.ctx.isStartExec) {
2633
+ this.ctx.log.info(`Processing Snapshot: ${snapshot == null ? void 0 : snapshot.name}`);
2634
+ }
2583
2635
  if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {
2584
2636
  drop = true;
2585
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.`);
@@ -2643,14 +2695,14 @@ var Queue = class {
2643
2695
 
2644
2696
  // src/commander/exec.ts
2645
2697
  var command = new commander.Command();
2646
- 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) {
2647
2699
  return __async(this, null, function* () {
2648
- const options = command4.optsWithGlobals();
2700
+ const options = command7.optsWithGlobals();
2649
2701
  if (options.buildName === "") {
2650
2702
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
2651
2703
  process.exit(1);
2652
2704
  }
2653
- let ctx = ctx_default(command4.optsWithGlobals());
2705
+ let ctx = ctx_default(command7.optsWithGlobals());
2654
2706
  if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
2655
2707
  ctx.log.error(`Error: Command not found "${execCommand[0]}"`);
2656
2708
  return;
@@ -2762,9 +2814,9 @@ function verifyFigmaWebConfig(ctx) {
2762
2814
  if (ctx.env.LT_ACCESS_KEY == "") {
2763
2815
  throw new Error("Missing LT_ACCESS_KEY in Environment Variables");
2764
2816
  }
2765
- let figma = ctx.config && ((_a = ctx.config) == null ? undefined : _a.figma) || {};
2817
+ let figma = ctx.config && ((_a = ctx.config) == null ? void 0 : _a.figma) || {};
2766
2818
  const screenshots = [];
2767
- for (let c of figma == null ? undefined : figma.configs) {
2819
+ for (let c of figma == null ? void 0 : figma.configs) {
2768
2820
  if (c.screenshot_names && c.screenshot_names.length > 0 && c.figma_ids && c.figma_ids.length != c.screenshot_names.length) {
2769
2821
  throw new Error("Mismatch in Figma Ids and Screenshot Names in figma config");
2770
2822
  }
@@ -2840,8 +2892,8 @@ function captureScreenshotsForConfig(_0, _1, _2, _3, _4) {
2840
2892
  } catch (error) {
2841
2893
  throw new Error(`captureScreenshotsForConfig failed for browser ${browserName}; error: ${error}`);
2842
2894
  } finally {
2843
- yield page == null ? undefined : page.close();
2844
- yield context == null ? undefined : context.close();
2895
+ yield page == null ? void 0 : page.close();
2896
+ yield context == null ? void 0 : context.close();
2845
2897
  }
2846
2898
  });
2847
2899
  }
@@ -2905,13 +2957,13 @@ function captureScreenshots(ctx) {
2905
2957
  else
2906
2958
  yield captureScreenshotsSync(ctx, staticConfig, browsers);
2907
2959
  delDir(`screenshots/${staticConfig.name.toLowerCase().replace(/\s/g, "_")}`);
2908
- 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")}
2909
2961
  `;
2910
2962
  ctx.task.output = output;
2911
2963
  capturedScreenshots++;
2912
2964
  } catch (error) {
2913
2965
  ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
2914
- 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")}
2915
2967
  `;
2916
2968
  ctx.task.output = output;
2917
2969
  }
@@ -3088,14 +3140,14 @@ function processChunk(ctx, urlConfig) {
3088
3140
  try {
3089
3141
  yield captureScreenshotsAsync(ctx, staticConfig, browsers);
3090
3142
  delDir(`screenshots/${staticConfig.name.toLowerCase().replace(/\s/g, "_")}`);
3091
- 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")}
3092
3144
  `;
3093
3145
  ctx.task.output = ctx.task.output ? ctx.task.output + output : output;
3094
3146
  finalOutput += output;
3095
3147
  capturedScreenshots++;
3096
3148
  } catch (error) {
3097
3149
  ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
3098
- 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")}
3099
3151
  `;
3100
3152
  ctx.task.output += output;
3101
3153
  finalOutput += output;
@@ -3108,7 +3160,7 @@ function processChunk(ctx, urlConfig) {
3108
3160
  var captureScreenshots_default = (ctx) => {
3109
3161
  return {
3110
3162
  title: "Capturing screenshots",
3111
- task: (ctx2, task) => __async(undefined, null, function* () {
3163
+ task: (ctx2, task) => __async(void 0, null, function* () {
3112
3164
  try {
3113
3165
  ctx2.task = task;
3114
3166
  if (ctx2.options.fetchResults) {
@@ -3129,7 +3181,7 @@ var captureScreenshots_default = (ctx) => {
3129
3181
  task.title = "Screenshots captured successfully";
3130
3182
  } catch (error) {
3131
3183
  ctx2.log.debug(error);
3132
- task.output = chalk6__default.default.gray(`${error.message}`);
3184
+ task.output = chalk__default.default.gray(`${error.message}`);
3133
3185
  throw new Error("Capturing screenshots failed");
3134
3186
  }
3135
3187
  }),
@@ -3140,14 +3192,14 @@ var captureScreenshots_default = (ctx) => {
3140
3192
 
3141
3193
  // src/commander/capture.ts
3142
3194
  var command2 = new commander.Command();
3143
- 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) {
3144
3196
  return __async(this, null, function* () {
3145
- const options = command4.optsWithGlobals();
3197
+ const options = command7.optsWithGlobals();
3146
3198
  if (options.buildName === "") {
3147
3199
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
3148
3200
  process.exit(1);
3149
3201
  }
3150
- let ctx = ctx_default(command4.optsWithGlobals());
3202
+ let ctx = ctx_default(command7.optsWithGlobals());
3151
3203
  if (!fs5__default.default.existsSync(file)) {
3152
3204
  ctx.log.error(`Web Static Config file ${file} not found.`);
3153
3205
  return;
@@ -3195,7 +3247,7 @@ var capture_default = command2;
3195
3247
  var uploadScreenshots_default = (ctx) => {
3196
3248
  return {
3197
3249
  title: "Uploading screenshots",
3198
- task: (ctx2, task) => __async(undefined, null, function* () {
3250
+ task: (ctx2, task) => __async(void 0, null, function* () {
3199
3251
  try {
3200
3252
  ctx2.task = task;
3201
3253
  if (ctx2.options.fetchResults) {
@@ -3206,7 +3258,7 @@ var uploadScreenshots_default = (ctx) => {
3206
3258
  task.title = "Screenshots uploaded successfully";
3207
3259
  } catch (error) {
3208
3260
  ctx2.log.debug(error);
3209
- task.output = chalk6__default.default.gray(`${error.message}`);
3261
+ task.output = chalk__default.default.gray(`${error.message}`);
3210
3262
  throw new Error("Uploading screenshots failed");
3211
3263
  }
3212
3264
  }),
@@ -3221,14 +3273,14 @@ command3.name("upload").description("Upload screenshots from given directory").a
3221
3273
  return val.split(",").map((ext) => ext.trim().toLowerCase());
3222
3274
  }).option("-E, --removeExtensions", "Strips file extensions from snapshot names").option("-i, --ignoreDir <patterns>", "Comma-separated list of directories to ignore", (val) => {
3223
3275
  return val.split(",").map((pattern) => pattern.trim());
3224
- }).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) {
3225
3277
  return __async(this, null, function* () {
3226
- const options = command4.optsWithGlobals();
3278
+ const options = command7.optsWithGlobals();
3227
3279
  if (options.buildName === "") {
3228
3280
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
3229
3281
  process.exit(1);
3230
3282
  }
3231
- let ctx = ctx_default(command4.optsWithGlobals());
3283
+ let ctx = ctx_default(command7.optsWithGlobals());
3232
3284
  if (!fs5__default.default.existsSync(directory)) {
3233
3285
  console.log(`Error: The provided directory ${directory} not found.`);
3234
3286
  return;
@@ -3267,7 +3319,7 @@ command3.name("upload").description("Upload screenshots from given directory").a
3267
3319
  var upload_default = command3;
3268
3320
 
3269
3321
  // src/lib/uploadFigmaDesigns.ts
3270
- var uploadFigmaDesigns_default = (ctx) => __async(undefined, null, function* () {
3322
+ var uploadFigmaDesigns_default = (ctx) => __async(void 0, null, function* () {
3271
3323
  const depth = ctx.figmaDesignConfig.depth;
3272
3324
  const figmaConfigs = ctx.figmaDesignConfig.figma_config;
3273
3325
  let results = "";
@@ -3294,7 +3346,7 @@ var uploadFigmaDesigns_default = (ctx) => __async(undefined, null, function* ()
3294
3346
  var uploadFigmaDesigns_default2 = (ctx) => {
3295
3347
  return {
3296
3348
  title: "Uploading Figma Designs",
3297
- task: (ctx2, task) => __async(undefined, null, function* () {
3349
+ task: (ctx2, task) => __async(void 0, null, function* () {
3298
3350
  try {
3299
3351
  ctx2.task = task;
3300
3352
  updateLogContext({ task: "upload-figma" });
@@ -3306,7 +3358,7 @@ var uploadFigmaDesigns_default2 = (ctx) => {
3306
3358
  ctx2.log.debug(`Figma designs processed: ${results}`);
3307
3359
  } catch (error) {
3308
3360
  ctx2.log.debug(error);
3309
- task.output = chalk6__default.default.gray(`${error.message}`);
3361
+ task.output = chalk__default.default.gray(`${error.message}`);
3310
3362
  throw new Error("Uploading Figma designs failed");
3311
3363
  }
3312
3364
  }),
@@ -3316,13 +3368,13 @@ var uploadFigmaDesigns_default2 = (ctx) => {
3316
3368
  };
3317
3369
 
3318
3370
  // src/lib/uploadWebFigma.ts
3319
- var uploadWebFigma_default = (ctx) => __async(undefined, null, function* () {
3371
+ var uploadWebFigma_default = (ctx) => __async(void 0, null, function* () {
3320
3372
  var _a, _b;
3321
- const figmaConfig = ctx.config && ((_a = ctx.config) == null ? undefined : _a.figma) || {};
3322
- const webConfig = ctx.config && ((_b = ctx.config) == null ? undefined : _b.web) || {};
3373
+ const figmaConfig = ctx.config && ((_a = ctx.config) == null ? void 0 : _a.figma) || {};
3374
+ const webConfig = ctx.config && ((_b = ctx.config) == null ? void 0 : _b.web) || {};
3323
3375
  let results = "";
3324
3376
  const buildName = ctx.options.buildName;
3325
- if (figmaConfig.configs && figmaConfig.configs.length > 0) {
3377
+ if (figmaConfig && figmaConfig.configs && figmaConfig.configs.length > 0) {
3326
3378
  const authToken = `Basic ${Buffer.from(`${ctx.env.LT_USERNAME}:${ctx.env.LT_ACCESS_KEY}`).toString("base64")}`;
3327
3379
  const requestBody = {
3328
3380
  figma_token: ctx.env.FIGMA_TOKEN,
@@ -3349,7 +3401,7 @@ var uploadWebFigma_default = (ctx) => __async(undefined, null, function* () {
3349
3401
  });
3350
3402
 
3351
3403
  // src/lib/fetchFigma.ts
3352
- var fetchFigma_default = (ctx) => __async(undefined, null, function* () {
3404
+ var fetchFigma_default = (ctx) => __async(void 0, null, function* () {
3353
3405
  const buildId = ctx.build.id;
3354
3406
  ctx.log.debug(`Fetching figma results for buildId ${buildId}`);
3355
3407
  const startTime = Date.now();
@@ -3394,7 +3446,7 @@ function callFetchWebFigmaRecursive(startTime, buildId, ctx) {
3394
3446
  var uploadWebFigma_default2 = (ctx) => {
3395
3447
  return {
3396
3448
  title: "Processing Web Figma",
3397
- task: (ctx2, task) => __async(undefined, null, function* () {
3449
+ task: (ctx2, task) => __async(void 0, null, function* () {
3398
3450
  try {
3399
3451
  ctx2.task = task;
3400
3452
  updateLogContext({ task: "upload-figma-web" });
@@ -3403,17 +3455,17 @@ var uploadWebFigma_default2 = (ctx) => {
3403
3455
  throw new Error("Uploading Web Figma Screenshot failed");
3404
3456
  }
3405
3457
  if (ctx2.build.id) {
3406
- task.output = chalk6__default.default.gray(`Build Id: ${ctx2.build.id}`);
3458
+ task.output = chalk__default.default.gray(`Build Id: ${ctx2.build.id}`);
3407
3459
  let figmaOutput = yield fetchFigma_default(ctx2);
3408
3460
  const jsonObject = JSON.parse(figmaOutput);
3409
3461
  let output = JSON.stringify(jsonObject, null, 2);
3410
- task.output = task.output + "\n" + chalk6__default.default.green(`${output}`);
3462
+ task.output = task.output + "\n" + chalk__default.default.green(`${output}`);
3411
3463
  }
3412
3464
  task.title = "Web Figma images uploaded successfully to SmartUI";
3413
3465
  ctx2.log.debug(`Web Figma processed: ${results}`);
3414
3466
  } catch (error) {
3415
3467
  ctx2.log.debug(error);
3416
- task.output = chalk6__default.default.gray(`${error.message}`);
3468
+ task.output = chalk__default.default.gray(`${error.message}`);
3417
3469
  throw new Error("Uploading Web Figma Screenshots failed");
3418
3470
  }
3419
3471
  }),
@@ -3423,10 +3475,10 @@ var uploadWebFigma_default2 = (ctx) => {
3423
3475
  };
3424
3476
  var uploadFigma = new commander.Command();
3425
3477
  var uploadWebFigmaCommand = new commander.Command();
3426
- 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) {
3427
3479
  return __async(this, null, function* () {
3428
3480
  var _a, _b;
3429
- let ctx = ctx_default(command4.optsWithGlobals());
3481
+ let ctx = ctx_default(command7.optsWithGlobals());
3430
3482
  if (!fs5__default.default.existsSync(file)) {
3431
3483
  console.log(`Error: Figma Config file ${file} not found.`);
3432
3484
  return;
@@ -3464,10 +3516,10 @@ uploadFigma.name("upload-figma").description("Capture screenshots of static site
3464
3516
  }
3465
3517
  });
3466
3518
  });
3467
- 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) {
3468
3520
  return __async(this, null, function* () {
3469
3521
  var _a;
3470
- let ctx = ctx_default(command4.optsWithGlobals());
3522
+ let ctx = ctx_default(command7.optsWithGlobals());
3471
3523
  if (!fs5__default.default.existsSync(file)) {
3472
3524
  console.log(`Error: figma-web config file ${file} not found.`);
3473
3525
  return;
@@ -3488,7 +3540,7 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots
3488
3540
  }
3489
3541
  verifyFigmaWebConfig(ctx);
3490
3542
  } catch (error) {
3491
- 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}`));
3492
3544
  return;
3493
3545
  }
3494
3546
  let tasks = new listr2.Listr(
@@ -3516,10 +3568,112 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture screenshots
3516
3568
  }
3517
3569
  });
3518
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;
3519
3673
 
3520
3674
  // src/commander/commander.ts
3521
3675
  var program = new commander.Command();
3522
- 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);
3523
3677
  var commander_default = program;
3524
3678
  (function() {
3525
3679
  return __async(this, null, function* () {
@@ -3529,16 +3683,16 @@ var commander_default = program;
3529
3683
  let { data: { latestVersion, deprecated, additionalDescription } } = yield client.checkUpdate(log2);
3530
3684
  log2.info(`
3531
3685
  LambdaTest SmartUI CLI v${package_default.version}`);
3532
- log2.info(chalk6__default.default.yellow(`${additionalDescription}`));
3686
+ log2.info(chalk__default.default.yellow(`${additionalDescription}`));
3533
3687
  if (deprecated) {
3534
3688
  log2.warn(`This version is deprecated. A new version ${latestVersion} is available!`);
3535
3689
  } else if (package_default.version !== latestVersion) {
3536
- 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!`));
3537
3691
  } else
3538
- 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"));
3539
3693
  } catch (error) {
3540
3694
  log2.debug(error);
3541
- 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"));
3542
3696
  }
3543
3697
  commander_default.parse();
3544
3698
  });