@lambdatest/smartui-cli 4.1.55-beta.0 → 4.1.56-beta.1

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 +150 -21
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -18,10 +18,10 @@ var stringify = require('json-stringify-safe');
18
18
  var FormData = require('form-data');
19
19
  var axios = require('axios');
20
20
  var https = require('https');
21
+ var uuid = require('uuid');
21
22
  var child_process = require('child_process');
22
23
  var spawn = require('cross-spawn');
23
24
  var NodeCache = require('node-cache');
24
- var uuid = require('uuid');
25
25
  var sharp = require('sharp');
26
26
  var http = require('http');
27
27
 
@@ -2432,16 +2432,28 @@ function findAvailablePort(server, startPort, log2) {
2432
2432
  return currentPort;
2433
2433
  } catch (error) {
2434
2434
  if (error.code === "EADDRINUSE") {
2435
- log2.debug(`Port ${currentPort} is in use, finding available port in range 49100-60000`);
2436
- const availablePorts = yield fp(constants_default.MIN_PORT_RANGE, constants_default.MAX_PORT_RANGE);
2437
- if (availablePorts.length > 0) {
2438
- const freePort = availablePorts[0];
2439
- yield server.listen({ port: freePort });
2440
- log2.debug(`Found and started server on port ${freePort}`);
2441
- return freePort;
2442
- } else {
2443
- throw new Error("No available ports found in range 49100-60000");
2435
+ log2.debug(`Port ${currentPort} is in use, finding available port in range ${constants_default.MIN_PORT_RANGE}-${constants_default.MAX_PORT_RANGE}`);
2436
+ const maxRetries = 3;
2437
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
2438
+ try {
2439
+ const availablePorts = yield fp(constants_default.MIN_PORT_RANGE, constants_default.MAX_PORT_RANGE);
2440
+ if (availablePorts.length > 0) {
2441
+ const freePort = availablePorts[0];
2442
+ yield server.listen({ port: freePort });
2443
+ log2.debug(`Found and started server on port ${freePort}`);
2444
+ return freePort;
2445
+ } else {
2446
+ throw new Error(`No available ports found in range ${constants_default.MIN_PORT_RANGE}-${constants_default.MAX_PORT_RANGE}`);
2447
+ }
2448
+ } catch (retryError) {
2449
+ if (retryError.code === "EADDRINUSE" && attempt < maxRetries) {
2450
+ log2.debug(`Port race condition on attempt ${attempt}, retrying...`);
2451
+ continue;
2452
+ }
2453
+ throw retryError;
2454
+ }
2444
2455
  }
2456
+ throw new Error("Failed to find available port after max retries");
2445
2457
  } else {
2446
2458
  throw error;
2447
2459
  }
@@ -2700,6 +2712,52 @@ var server_default = (ctx) => __async(null, null, function* () {
2700
2712
  return reply.code(replyCode).send(replyBody);
2701
2713
  }
2702
2714
  }));
2715
+ server.get("/smartui/results", opts, (request, reply) => __async(null, null, function* () {
2716
+ var _a;
2717
+ let replyCode;
2718
+ let replyBody;
2719
+ try {
2720
+ const { sessionId } = request.query;
2721
+ ctx.log.debug(`smartui results request: sessionId=${sessionId || "none"}`);
2722
+ let resolvedBuildId = "";
2723
+ let projectToken = "";
2724
+ if (sessionId && ((_a = ctx.sessionCapabilitiesMap) == null ? void 0 : _a.has(sessionId))) {
2725
+ const cachedCapabilities = ctx.sessionCapabilitiesMap.get(sessionId);
2726
+ resolvedBuildId = (cachedCapabilities == null ? void 0 : cachedCapabilities.buildId) || "";
2727
+ projectToken = (cachedCapabilities == null ? void 0 : cachedCapabilities.projectToken) || "";
2728
+ ctx.log.debug(`Resolved from sessionCapabilitiesMap for sessionId ${sessionId}: buildId=${resolvedBuildId}, projectToken=${projectToken ? "present" : "missing"}`);
2729
+ }
2730
+ if ((!resolvedBuildId || resolvedBuildId.length <= 30) && ctx.build && ctx.build.id) {
2731
+ resolvedBuildId = ctx.build.id;
2732
+ }
2733
+ if (!projectToken) {
2734
+ projectToken = ctx.env.PROJECT_TOKEN || "";
2735
+ }
2736
+ ctx.log.debug(`smartui results params: sessionId=${sessionId || "none"}, buildId=${resolvedBuildId}, projectToken=${projectToken ? "present" : "missing"}`);
2737
+ if (!resolvedBuildId) {
2738
+ replyCode = 404;
2739
+ replyBody = { error: { message: "Unable to determine buildId. Ensure a SmartUI build is active." } };
2740
+ return reply.code(replyCode).send(replyBody);
2741
+ }
2742
+ const resp = yield ctx.client.getScreenshotData(
2743
+ resolvedBuildId,
2744
+ false,
2745
+ ctx.log,
2746
+ projectToken,
2747
+ "",
2748
+ sessionId || "",
2749
+ "smartui-results"
2750
+ );
2751
+ replyCode = 200;
2752
+ replyBody = resp;
2753
+ } catch (error) {
2754
+ const errMsg = (error == null ? void 0 : error.message) || (typeof error === "string" ? error : JSON.stringify(error));
2755
+ ctx.log.debug(`smartui results failed; ${errMsg}`);
2756
+ replyCode = 500;
2757
+ replyBody = { error: { message: `smartui results failed; ${errMsg}` } };
2758
+ }
2759
+ return reply.code(replyCode).send(replyBody);
2760
+ }));
2703
2761
  server.get("/build/info", opts, (request, reply) => __async(null, null, function* () {
2704
2762
  let replyCode;
2705
2763
  let replyBody;
@@ -2838,6 +2896,24 @@ var logger = winston.createLogger({
2838
2896
  })
2839
2897
  ]
2840
2898
  });
2899
+ function removeFileTransport() {
2900
+ logger.transports.forEach((transport) => {
2901
+ if (transport instanceof winston.transports.File) {
2902
+ logger.remove(transport);
2903
+ }
2904
+ });
2905
+ }
2906
+ function reconfigureLogFile(newFilePath) {
2907
+ logger.transports.forEach((transport) => {
2908
+ if (transport instanceof winston.transports.File) {
2909
+ logger.remove(transport);
2910
+ }
2911
+ });
2912
+ logger.add(new winston.transports.File({
2913
+ level: "debug",
2914
+ filename: newFilePath
2915
+ }));
2916
+ }
2841
2917
  var logger_default = logger;
2842
2918
 
2843
2919
  // src/tasks/startServer.ts
@@ -2895,7 +2971,7 @@ var authExec_default = (ctx) => {
2895
2971
  };
2896
2972
 
2897
2973
  // package.json
2898
- var version = "4.1.55-beta.0";
2974
+ var version = "4.1.56-beta.1";
2899
2975
  var package_default = {
2900
2976
  name: "@lambdatest/smartui-cli",
2901
2977
  version,
@@ -3185,12 +3261,19 @@ var httpClient = class {
3185
3261
  }
3186
3262
  }, log2);
3187
3263
  }
3188
- getScreenshotData(buildId, baseline, log2, projectToken, buildName) {
3264
+ getScreenshotData(buildId, baseline, log2, projectToken, buildName, sessionId, type) {
3189
3265
  log2.debug(`Fetching screenshot data for buildId: ${buildId} having buildName: ${buildName} with baseline: ${baseline}`);
3266
+ const params = { buildId, baseline, buildName };
3267
+ if (sessionId) {
3268
+ params.sessionId = sessionId;
3269
+ }
3270
+ if (type) {
3271
+ params.type = type;
3272
+ }
3190
3273
  return this.request({
3191
3274
  url: "/screenshot",
3192
3275
  method: "GET",
3193
- params: { buildId, baseline, buildName },
3276
+ params,
3194
3277
  headers: { projectToken }
3195
3278
  }, log2);
3196
3279
  }
@@ -3509,8 +3592,13 @@ var httpClient = class {
3509
3592
  }, ctx.log);
3510
3593
  }
3511
3594
  uploadLogs(ctx, uploadURL) {
3512
- const fileStream = fs6__default.default.createReadStream(constants_default.LOG_FILE_PATH);
3513
- const { size } = fs6__default.default.statSync(constants_default.LOG_FILE_PATH);
3595
+ if (!ctx.logFilePath) {
3596
+ ctx.log.debug("Log file disabled, skipping log upload");
3597
+ return Promise.resolve();
3598
+ }
3599
+ const logPath = ctx.logFilePath;
3600
+ const fileStream = fs6__default.default.createReadStream(logPath);
3601
+ const { size } = fs6__default.default.statSync(logPath);
3514
3602
  return this.request({
3515
3603
  url: uploadURL,
3516
3604
  method: "PUT",
@@ -3526,8 +3614,13 @@ var httpClient = class {
3526
3614
  }, ctx.log);
3527
3615
  }
3528
3616
  uploadLogsForCaps(ctx, uploadURL) {
3529
- const logContent = fs6__default.default.readFileSync(constants_default.LOG_FILE_PATH);
3530
- const { size } = fs6__default.default.statSync(constants_default.LOG_FILE_PATH);
3617
+ if (!ctx.logFilePath) {
3618
+ ctx.log.debug("Log file disabled, skipping log upload");
3619
+ return Promise.resolve();
3620
+ }
3621
+ const logPath = ctx.logFilePath;
3622
+ const logContent = fs6__default.default.readFileSync(logPath);
3623
+ const { size } = fs6__default.default.statSync(logPath);
3531
3624
  return this.request({
3532
3625
  url: uploadURL,
3533
3626
  method: "PUT",
@@ -3543,7 +3636,12 @@ var httpClient = class {
3543
3636
  }, ctx.log);
3544
3637
  }
3545
3638
  sendCliLogsToLSRS(ctx) {
3546
- const logContent = fs6__default.default.readFileSync(constants_default.LOG_FILE_PATH, "utf-8");
3639
+ if (!ctx.logFilePath) {
3640
+ ctx.log.debug("Log file disabled, skipping log upload");
3641
+ return Promise.resolve();
3642
+ }
3643
+ const logPath = ctx.logFilePath;
3644
+ const logContent = fs6__default.default.readFileSync(logPath, "utf-8");
3547
3645
  return this.request({
3548
3646
  url: `/upload/logs`,
3549
3647
  method: "POST",
@@ -3555,7 +3653,12 @@ var httpClient = class {
3555
3653
  }, ctx.log);
3556
3654
  }
3557
3655
  sendCliLogsToLSRSForCaps(ctx, capsBuildId, capsProjectToken) {
3558
- const logContent = fs6__default.default.readFileSync(constants_default.LOG_FILE_PATH, "utf-8");
3656
+ if (!ctx.logFilePath) {
3657
+ ctx.log.debug("Log file disabled, skipping log upload");
3658
+ return Promise.resolve();
3659
+ }
3660
+ const logPath = ctx.logFilePath;
3661
+ const logContent = fs6__default.default.readFileSync(logPath, "utf-8");
3559
3662
  return this.request({
3560
3663
  url: `/upload/logs`,
3561
3664
  method: "POST",
@@ -3851,6 +3954,26 @@ var ctx_default = (options) => {
3851
3954
  if (config.waitForPageRender && config.waitForPageRender < 3e4) {
3852
3955
  config.waitForPageRender = 3e4;
3853
3956
  }
3957
+ let disableLogFile = options.disableLogFile ? true : false;
3958
+ if (disableLogFile) {
3959
+ removeFileTransport();
3960
+ logger_default.debug("File logging disabled via --disableLogFile flag");
3961
+ }
3962
+ let logFileUUID;
3963
+ let logFilePath = disableLogFile ? void 0 : constants_default.LOG_FILE_PATH;
3964
+ if (!disableLogFile && options.createUniqueLogFile) {
3965
+ logFileUUID = uuid.v4();
3966
+ logFilePath = `.smartui-${logFileUUID}.log`;
3967
+ reconfigureLogFile(logFilePath);
3968
+ try {
3969
+ if (fs6__default.default.existsSync(logFilePath)) {
3970
+ fs6__default.default.unlinkSync(logFilePath);
3971
+ }
3972
+ } catch (error) {
3973
+ logger_default.debug(`Could not delete existing unique log file: ${error.message}`);
3974
+ }
3975
+ logger_default.debug(`Using unique log file: ${logFilePath} (UUID: ${logFileUUID})`);
3976
+ }
3854
3977
  return {
3855
3978
  env,
3856
3979
  log: logger_default,
@@ -3947,7 +4070,9 @@ var ctx_default = (options) => {
3947
4070
  mergeBuildSourceId: "",
3948
4071
  mergeBuildTargetId: "",
3949
4072
  mergeByBranch: false,
3950
- mergeByBuild: false
4073
+ mergeByBuild: false,
4074
+ logFileUUID,
4075
+ logFilePath
3951
4076
  };
3952
4077
  };
3953
4078
 
@@ -4565,6 +4690,10 @@ function prepareSnapshot(snapshot, ctx) {
4565
4690
  processedOptions.selectors = selectors;
4566
4691
  processedOptions.ignoreDOM = options == null ? void 0 : options.ignoreDOM;
4567
4692
  processedOptions.selectDOM = options == null ? void 0 : options.selectDOM;
4693
+ if ((options == null ? void 0 : options.customCookies) && Array.isArray(options.customCookies) && options.customCookies.length > 0) {
4694
+ ctx.log.debug(`Setting ${options.customCookies.length} custom cookies`);
4695
+ processedOptions.customCookies = options.customCookies;
4696
+ }
4568
4697
  ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
4569
4698
  let renderViewports;
4570
4699
  if (snapshot.options && snapshot.options.web || snapshot.options && snapshot.options.mobile) {
@@ -7638,7 +7767,7 @@ var uploadPdf_default = command10;
7638
7767
 
7639
7768
  // src/commander/commander.ts
7640
7769
  var program2 = new commander.Command();
7641
- program2.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").option("--markBaseline", "Mark this build baseline").option("--baselineBranch <string>", "Mark this build baseline").option("--baselineBuild <string>", "Mark this build baseline").option("--githubURL <string>", "GitHub URL including commitId").option("--gitURL <string>", "Git URL including commitId").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(server_default2).addCommand(stopServer_default).addCommand(merge_default).addCommand(ping_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(configAppFigma).addCommand(uploadWebFigmaCommand).addCommand(uploadAppFigmaCommand).addCommand(pingTest_default).addCommand(uploadPdf_default);
7770
+ program2.name("smartui").description("CLI to help you run your SmartUI tests on LambdaTest platform").version(`v${version}`).option("-c --config <filepath>", "Config file path").option("--markBaseline", "Mark this build baseline").option("--baselineBranch <string>", "Mark this build baseline").option("--baselineBuild <string>", "Mark this build baseline").option("--githubURL <string>", "GitHub URL including commitId").option("--gitURL <string>", "Git URL including commitId").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").option("--createUniqueLogFile", "Create a unique log file for each CLI execution to avoid file lock issues in parallel runs").option("--disableLogFile", "Disable writing logs to a file").addCommand(exec_default2).addCommand(capture_default).addCommand(configWeb).addCommand(configStatic).addCommand(upload_default).addCommand(server_default2).addCommand(stopServer_default).addCommand(merge_default).addCommand(ping_default).addCommand(configFigma).addCommand(uploadFigma).addCommand(configWebFigma).addCommand(configAppFigma).addCommand(uploadWebFigmaCommand).addCommand(uploadAppFigmaCommand).addCommand(pingTest_default).addCommand(uploadPdf_default);
7642
7771
  var commander_default = program2;
7643
7772
  (function() {
7644
7773
  return __async(this, null, function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdatest/smartui-cli",
3
- "version": "4.1.55-beta.0",
3
+ "version": "4.1.56-beta.1",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"