@lambdatest/smartui-cli 4.1.28 → 4.1.29

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 +372 -42
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1716,6 +1716,130 @@ function calculateVariantCountFromSnapshot(snapshot, globalConfig) {
1716
1716
  }
1717
1717
  return variantCount;
1718
1718
  }
1719
+ function startPdfPolling(ctx) {
1720
+ console.log(chalk__default.default.yellow("\nFetching PDF test results..."));
1721
+ ctx.log.debug(`Starting fetching results for build: ${ctx.build.id || ctx.build.name}`);
1722
+ if (!ctx.build.id && !ctx.build.name) {
1723
+ ctx.log.error(chalk__default.default.red("Error: Build information not found for fetching results"));
1724
+ return;
1725
+ }
1726
+ if (!ctx.env.LT_USERNAME || !ctx.env.LT_ACCESS_KEY) {
1727
+ console.log(chalk__default.default.red("Error: LT_USERNAME and LT_ACCESS_KEY environment variables are required for fetching results"));
1728
+ return;
1729
+ }
1730
+ let attempts = 0;
1731
+ const maxAttempts = 60;
1732
+ console.log(chalk__default.default.yellow("Waiting for results..."));
1733
+ const interval = setInterval(() => __async(this, null, function* () {
1734
+ attempts++;
1735
+ try {
1736
+ const response = yield ctx.client.fetchPdfResults(ctx);
1737
+ if (response.screenshots) {
1738
+ clearInterval(interval);
1739
+ const pdfGroups = groupScreenshotsByPdf(response.screenshots);
1740
+ const pdfsWithMismatches = countPdfsWithMismatches(pdfGroups);
1741
+ const pagesWithMismatches = countPagesWithMismatches(response.screenshots);
1742
+ console.log(chalk__default.default.green("\n\u2713 PDF Test Results:"));
1743
+ console.log(chalk__default.default.green(`Build Name: ${response.build.name}`));
1744
+ console.log(chalk__default.default.green(`Project Name: ${response.project.name}`));
1745
+ console.log(chalk__default.default.green(`Total PDFs: ${Object.keys(pdfGroups).length}`));
1746
+ console.log(chalk__default.default.green(`Total Pages: ${response.screenshots.length}`));
1747
+ if (pdfsWithMismatches > 0 || pagesWithMismatches > 0) {
1748
+ console.log(chalk__default.default.yellow(`${pdfsWithMismatches} PDFs and ${pagesWithMismatches} Pages in build ${response.build.name} have changes present.`));
1749
+ } else {
1750
+ console.log(chalk__default.default.green("All PDFs match the baseline."));
1751
+ }
1752
+ Object.entries(pdfGroups).forEach(([pdfName, pages]) => {
1753
+ const hasMismatch = pages.some((page) => page.mismatch_percentage > 0);
1754
+ const statusColor = hasMismatch ? chalk__default.default.yellow : chalk__default.default.green;
1755
+ console.log(statusColor(`
1756
+ \u{1F4C4} ${pdfName} (${pages.length} pages)`));
1757
+ pages.forEach((page) => {
1758
+ const pageStatusColor = page.mismatch_percentage > 0 ? chalk__default.default.yellow : chalk__default.default.green;
1759
+ console.log(pageStatusColor(` - Page ${getPageNumber(page.screenshot_name)}: ${page.status} (Mismatch: ${page.mismatch_percentage}%)`));
1760
+ });
1761
+ });
1762
+ const formattedResults = {
1763
+ status: "success",
1764
+ data: {
1765
+ buildId: response.build.id,
1766
+ buildName: response.build.name,
1767
+ projectName: response.project.name,
1768
+ buildStatus: response.build.build_satus,
1769
+ pdfs: formatPdfsForOutput(pdfGroups)
1770
+ }
1771
+ };
1772
+ if (ctx.options.fetchResults && ctx.options.fetchResultsFileName) {
1773
+ const filename = ctx.options.fetchResultsFileName !== "" ? ctx.options.fetchResultsFileName : "pdf-results.json";
1774
+ fs5__default.default.writeFileSync(filename, JSON.stringify(formattedResults, null, 2));
1775
+ console.log(chalk__default.default.green(`
1776
+ Results saved to ${filename}`));
1777
+ }
1778
+ return;
1779
+ }
1780
+ if (attempts >= maxAttempts) {
1781
+ clearInterval(interval);
1782
+ console.log(chalk__default.default.red("\nTimeout: Could not fetch PDF results after 5 minutes"));
1783
+ return;
1784
+ }
1785
+ } catch (error) {
1786
+ ctx.log.debug(`Error during polling: ${error.message}`);
1787
+ if (attempts >= maxAttempts) {
1788
+ clearInterval(interval);
1789
+ console.log(chalk__default.default.red("\nTimeout: Could not fetch PDF results after 5 minutes"));
1790
+ if (error.response && error.response.data) {
1791
+ console.log(chalk__default.default.red(`Error details: ${JSON.stringify(error.response.data)}`));
1792
+ } else {
1793
+ console.log(chalk__default.default.red(`Error details: ${error.message}`));
1794
+ }
1795
+ return;
1796
+ }
1797
+ process.stdout.write(chalk__default.default.yellow("."));
1798
+ }
1799
+ }), 1e4);
1800
+ }
1801
+ function groupScreenshotsByPdf(screenshots) {
1802
+ const pdfGroups = {};
1803
+ screenshots.forEach((screenshot) => {
1804
+ const pdfName = screenshot.screenshot_name.split("#")[0];
1805
+ if (!pdfGroups[pdfName]) {
1806
+ pdfGroups[pdfName] = [];
1807
+ }
1808
+ pdfGroups[pdfName].push(screenshot);
1809
+ });
1810
+ return pdfGroups;
1811
+ }
1812
+ function countPdfsWithMismatches(pdfGroups) {
1813
+ let count = 0;
1814
+ Object.values(pdfGroups).forEach((pages) => {
1815
+ if (pages.some((page) => page.mismatch_percentage > 0)) {
1816
+ count++;
1817
+ }
1818
+ });
1819
+ return count;
1820
+ }
1821
+ function countPagesWithMismatches(screenshots) {
1822
+ return screenshots.filter((screenshot) => screenshot.mismatch_percentage > 0).length;
1823
+ }
1824
+ function formatPdfsForOutput(pdfGroups) {
1825
+ return Object.entries(pdfGroups).map(([pdfName, pages]) => {
1826
+ return {
1827
+ pdfName,
1828
+ pageCount: pages.length,
1829
+ pages: pages.map((page) => ({
1830
+ pageNumber: getPageNumber(page.screenshot_name),
1831
+ screenshotId: page.captured_image_id,
1832
+ mismatchPercentage: page.mismatch_percentage,
1833
+ status: page.status,
1834
+ screenshotUrl: page.shareable_link
1835
+ }))
1836
+ };
1837
+ });
1838
+ }
1839
+ function getPageNumber(screenshotName) {
1840
+ const parts = screenshotName.split("#");
1841
+ return parts.length > 1 ? parts[1] : "1";
1842
+ }
1719
1843
 
1720
1844
  // src/lib/server.ts
1721
1845
  var uploadDomToS3ViaEnv = process.env.USE_LAMBDA_INTERNAL || false;
@@ -1764,7 +1888,6 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1764
1888
  }
1765
1889
  } catch (error) {
1766
1890
  ctx.log.debug(`Failed to fetch capabilities for sessionId ${sessionId}: ${error.message}`);
1767
- console.log(`Failed to fetch capabilities for sessionId ${sessionId}: ${error.message}`);
1768
1891
  }
1769
1892
  }
1770
1893
  if (capsBuildId && capsBuildId !== "") {
@@ -1813,19 +1936,39 @@ var server_default = (ctx) => __async(void 0, null, function* () {
1813
1936
  }
1814
1937
  }, 1e3);
1815
1938
  });
1816
- yield ctx.client.finalizeBuild(ctx.build.id, ctx.totalSnapshots, ctx.log);
1817
- yield (_b = ctx.browser) == null ? void 0 : _b.close();
1939
+ for (const [sessionId, capabilities] of ctx.sessionCapabilitiesMap.entries()) {
1940
+ try {
1941
+ const buildId = (capabilities == null ? void 0 : capabilities.buildId) || "";
1942
+ const projectToken = (capabilities == null ? void 0 : capabilities.projectToken) || "";
1943
+ const totalSnapshots = (capabilities == null ? void 0 : capabilities.snapshotCount) || 0;
1944
+ const sessionBuildUrl = (capabilities == null ? void 0 : capabilities.buildURL) || "";
1945
+ const testId = (capabilities == null ? void 0 : capabilities.id) || "";
1946
+ if (buildId && projectToken) {
1947
+ yield ctx.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx.log);
1948
+ }
1949
+ if (testId && buildId) {
1950
+ buildUrls += `TestId ${testId}: ${sessionBuildUrl}
1951
+ `;
1952
+ }
1953
+ } catch (error) {
1954
+ ctx.log.debug(`Error finalizing build for session ${sessionId}: ${error.message}`);
1955
+ }
1956
+ }
1957
+ if (ctx.build && ctx.build.id) {
1958
+ yield ctx.client.finalizeBuild(ctx.build.id, ctx.totalSnapshots, ctx.log);
1959
+ let uploadCLILogsToS3 = ((_b = ctx == null ? void 0 : ctx.config) == null ? void 0 : _b.useLambdaInternal) || uploadDomToS3ViaEnv;
1960
+ if (!uploadCLILogsToS3) {
1961
+ ctx.log.debug(`Log file to be uploaded`);
1962
+ let resp = yield ctx.client.getS3PreSignedURL(ctx);
1963
+ yield ctx.client.uploadLogs(ctx, resp.data.url);
1964
+ } else {
1965
+ ctx.log.debug(`Skipping upload of CLI logs as useLambdaInternal is set`);
1966
+ }
1967
+ }
1968
+ yield (_c = ctx.browser) == null ? void 0 : _c.close();
1818
1969
  if (ctx.server) {
1819
1970
  ctx.server.close();
1820
1971
  }
1821
- let uploadCLILogsToS3 = ((_c = ctx == null ? void 0 : ctx.config) == null ? void 0 : _c.useLambdaInternal) || uploadDomToS3ViaEnv;
1822
- if (!uploadCLILogsToS3) {
1823
- ctx.log.debug(`Log file to be uploaded`);
1824
- let resp = yield ctx.client.getS3PreSignedURL(ctx);
1825
- yield ctx.client.uploadLogs(ctx, resp.data.url);
1826
- } else {
1827
- ctx.log.debug(`Skipping upload of CLI logs as useLambdaInternal is set`);
1828
- }
1829
1972
  if (pingIntervalId !== null) {
1830
1973
  clearInterval(pingIntervalId);
1831
1974
  ctx.log.debug("Ping polling stopped immediately.");
@@ -1942,6 +2085,7 @@ var env_default = () => {
1942
2085
  const {
1943
2086
  PROJECT_TOKEN = "",
1944
2087
  SMARTUI_CLIENT_API_URL = "https://api.lambdatest.com/visualui/1.0",
2088
+ SMARTUI_UPLOAD_URL = "https://api.lambdatest.com",
1945
2089
  SMARTUI_GIT_INFO_FILEPATH,
1946
2090
  SMARTUI_DO_NOT_USE_CAPTURED_COOKIES,
1947
2091
  HTTP_PROXY,
@@ -1964,6 +2108,7 @@ var env_default = () => {
1964
2108
  return {
1965
2109
  PROJECT_TOKEN,
1966
2110
  SMARTUI_CLIENT_API_URL,
2111
+ SMARTUI_UPLOAD_URL,
1967
2112
  SMARTUI_GIT_INFO_FILEPATH,
1968
2113
  HTTP_PROXY,
1969
2114
  HTTPS_PROXY,
@@ -2076,7 +2221,7 @@ var authExec_default = (ctx) => {
2076
2221
  };
2077
2222
 
2078
2223
  // package.json
2079
- var version = "4.1.28";
2224
+ var version = "4.1.29";
2080
2225
  var package_default = {
2081
2226
  name: "@lambdatest/smartui-cli",
2082
2227
  version,
@@ -2133,6 +2278,18 @@ var package_default = {
2133
2278
  }
2134
2279
  };
2135
2280
  var httpClient = class {
2281
+ handleHttpError(error, log2) {
2282
+ var _a;
2283
+ if (error && error.response) {
2284
+ log2.debug(`http response error: ${JSON.stringify({
2285
+ status: error.response.status,
2286
+ body: error.response.data
2287
+ })}`);
2288
+ throw new Error(((_a = error.response.data) == null ? void 0 : _a.message) || error.response.data || `HTTP ${error.response.status} error`);
2289
+ }
2290
+ log2.debug(`http request failed: ${error.message}`);
2291
+ throw new Error(error.message);
2292
+ }
2136
2293
  constructor({ SMARTUI_CLIENT_API_URL, PROJECT_TOKEN, PROJECT_NAME, LT_USERNAME, LT_ACCESS_KEY, SMARTUI_API_PROXY, SMARTUI_API_SKIP_CERTIFICATES }) {
2137
2294
  this.projectToken = PROJECT_TOKEN || "";
2138
2295
  this.projectName = PROJECT_NAME || "";
@@ -2189,6 +2346,8 @@ var httpClient = class {
2189
2346
  return this.axiosInstance(config);
2190
2347
  }
2191
2348
  return Promise.reject(error);
2349
+ } else {
2350
+ return Promise.reject(error);
2192
2351
  }
2193
2352
  })
2194
2353
  );
@@ -2715,6 +2874,61 @@ var httpClient = class {
2715
2874
  }
2716
2875
  }, ctx.log);
2717
2876
  }
2877
+ uploadPdf(ctx, form, buildName) {
2878
+ return __async(this, null, function* () {
2879
+ form.append("projectToken", this.projectToken);
2880
+ if (ctx.build.name !== void 0 && ctx.build.name !== "") {
2881
+ form.append("buildName", buildName);
2882
+ }
2883
+ try {
2884
+ const response = yield this.axiosInstance.request({
2885
+ url: ctx.env.SMARTUI_UPLOAD_URL + "/pdf/upload",
2886
+ method: "POST",
2887
+ headers: form.getHeaders(),
2888
+ data: form
2889
+ });
2890
+ ctx.log.debug(`http response: ${JSON.stringify({
2891
+ status: response.status,
2892
+ headers: response.headers,
2893
+ body: response.data
2894
+ })}`);
2895
+ return response.data;
2896
+ } catch (error) {
2897
+ this.handleHttpError(error, ctx.log);
2898
+ }
2899
+ });
2900
+ }
2901
+ fetchPdfResults(ctx) {
2902
+ return __async(this, null, function* () {
2903
+ const params = {};
2904
+ if (ctx.build.projectId) {
2905
+ params.project_id = ctx.build.projectId;
2906
+ } else {
2907
+ throw new Error("Project ID not found to fetch PDF results");
2908
+ }
2909
+ params.build_id = ctx.build.id;
2910
+ const auth = Buffer.from(`${this.username}:${this.accessKey}`).toString("base64");
2911
+ try {
2912
+ const response = yield axios__default.default.request({
2913
+ url: ctx.env.SMARTUI_UPLOAD_URL + "/smartui/2.0/build/screenshots",
2914
+ method: "GET",
2915
+ params,
2916
+ headers: {
2917
+ "accept": "application/json",
2918
+ "Authorization": `Basic ${auth}`
2919
+ }
2920
+ });
2921
+ ctx.log.debug(`http response: ${JSON.stringify({
2922
+ status: response.status,
2923
+ headers: response.headers,
2924
+ body: response.data
2925
+ })}`);
2926
+ return response.data;
2927
+ } catch (error) {
2928
+ this.handleHttpError(error, ctx.log);
2929
+ }
2930
+ });
2931
+ }
2718
2932
  };
2719
2933
  var ctx_default = (options) => {
2720
2934
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
@@ -2889,10 +3103,10 @@ var ctx_default = (options) => {
2889
3103
  mergeByBuild: false
2890
3104
  };
2891
3105
  };
2892
- function executeCommand(command10) {
3106
+ function executeCommand(command11) {
2893
3107
  let dst = process.cwd();
2894
3108
  try {
2895
- return child_process.execSync(command10, {
3109
+ return child_process.execSync(command11, {
2896
3110
  cwd: dst,
2897
3111
  stdio: ["ignore"],
2898
3112
  encoding: "utf-8"
@@ -2901,11 +3115,12 @@ function executeCommand(command10) {
2901
3115
  throw new Error(error.message);
2902
3116
  }
2903
3117
  }
2904
- function isGitRepo() {
3118
+ function isGitRepo(ctx) {
2905
3119
  try {
2906
3120
  executeCommand("git status");
2907
3121
  return true;
2908
3122
  } catch (error) {
3123
+ setNonGitInfo(ctx);
2909
3124
  return false;
2910
3125
  }
2911
3126
  }
@@ -2937,8 +3152,8 @@ var git_default = (ctx) => {
2937
3152
  } else {
2938
3153
  const splitCharacter = "<##>";
2939
3154
  const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
2940
- const command10 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
2941
- let res = executeCommand(command10).split(splitCharacter);
3155
+ const command11 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
3156
+ let res = executeCommand(command11).split(splitCharacter);
2942
3157
  var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
2943
3158
  var branch = ctx.env.CURRENT_BRANCH || branchAndTags[0];
2944
3159
  branchAndTags.slice(1);
@@ -2956,11 +3171,30 @@ var git_default = (ctx) => {
2956
3171
  };
2957
3172
  }
2958
3173
  };
3174
+ function setNonGitInfo(ctx) {
3175
+ let branch = ctx.env.CURRENT_BRANCH || "unknown-branch";
3176
+ if (ctx.options.markBaseline) {
3177
+ ctx.env.BASELINE_BRANCH = branch;
3178
+ ctx.env.SMART_GIT = false;
3179
+ }
3180
+ let githubURL;
3181
+ if (ctx.options.githubURL && ctx.options.githubURL.startsWith("https://")) {
3182
+ githubURL = ctx.options.githubURL;
3183
+ }
3184
+ ctx.git = {
3185
+ branch,
3186
+ commitId: "-",
3187
+ commitAuthor: "-",
3188
+ commitMessage: "-",
3189
+ githubURL: githubURL ? githubURL : "",
3190
+ baselineBranch: ctx.options.baselineBranch || ctx.env.BASELINE_BRANCH || ""
3191
+ };
3192
+ }
2959
3193
  var getGitInfo_default = (ctx) => {
2960
3194
  return {
2961
3195
  title: `Fetching git repo details`,
2962
3196
  skip: (ctx2) => {
2963
- return !isGitRepo() && !ctx2.env.SMARTUI_GIT_INFO_FILEPATH ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
3197
+ return !isGitRepo(ctx2) && !ctx2.env.SMARTUI_GIT_INFO_FILEPATH ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
2964
3198
  },
2965
3199
  task: (ctx2, task) => __async(void 0, null, function* () {
2966
3200
  if (ctx2.env.CURRENT_BRANCH && ctx2.env.CURRENT_BRANCH.trim() === "") {
@@ -3168,7 +3402,7 @@ var finalizeBuild_default = (ctx) => {
3168
3402
  task.output = chalk__default.default.gray(error.message);
3169
3403
  throw new Error("Finalize build failed");
3170
3404
  }
3171
- let buildUrls = `build url: ${ctx2.build.url}
3405
+ let buildUrls2 = `build url: ${ctx2.build.url}
3172
3406
  `;
3173
3407
  if (pingIntervalId !== null) {
3174
3408
  clearInterval(pingIntervalId);
@@ -3198,14 +3432,14 @@ var finalizeBuild_default = (ctx) => {
3198
3432
  yield ctx2.client.finalizeBuildForCapsWithToken(buildId, totalSnapshots, projectToken, ctx2.log);
3199
3433
  }
3200
3434
  if (testId && buildId) {
3201
- buildUrls += `TestId ${testId}: ${sessionBuildUrl}
3435
+ buildUrls2 += `TestId ${testId}: ${sessionBuildUrl}
3202
3436
  `;
3203
3437
  }
3204
3438
  } catch (error) {
3205
3439
  ctx2.log.debug(`Error finalizing build for session ${sessionId}: ${error.message}`);
3206
3440
  }
3207
3441
  }
3208
- task.output = chalk__default.default.gray(buildUrls);
3442
+ task.output = chalk__default.default.gray(buildUrls2);
3209
3443
  task.title = "Finalized build";
3210
3444
  try {
3211
3445
  yield (_a = ctx2.browser) == null ? void 0 : _a.close();
@@ -4124,7 +4358,7 @@ var Queue = class {
4124
4358
  try {
4125
4359
  this.processingSnapshot = snapshot == null ? void 0 : snapshot.name;
4126
4360
  let drop = false;
4127
- if (this.ctx.isStartExec && !this.ctx.config.tunnel) {
4361
+ if (this.ctx.isStartExec) {
4128
4362
  this.ctx.log.info(`Processing Snapshot: ${snapshot == null ? void 0 : snapshot.name}`);
4129
4363
  }
4130
4364
  if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name) && !this.ctx.config.allowDuplicateSnapshotNames) {
@@ -4319,15 +4553,15 @@ var startTunnel_default = (ctx) => {
4319
4553
 
4320
4554
  // src/commander/exec.ts
4321
4555
  var command = new commander.Command();
4322
- 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").option("--scheduled <string>", "Specify the schedule ID").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(execCommand, _, command10) {
4556
+ 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").option("--scheduled <string>", "Specify the schedule ID").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(execCommand, _, command11) {
4323
4557
  return __async(this, null, function* () {
4324
4558
  var _a;
4325
- const options = command10.optsWithGlobals();
4559
+ const options = command11.optsWithGlobals();
4326
4560
  if (options.buildName === "") {
4327
4561
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
4328
4562
  process.exit(1);
4329
4563
  }
4330
- let ctx = ctx_default(command10.optsWithGlobals());
4564
+ let ctx = ctx_default(command11.optsWithGlobals());
4331
4565
  if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
4332
4566
  ctx.log.error(`Error: Command not found "${execCommand[0]}"`);
4333
4567
  return;
@@ -4943,15 +5177,15 @@ var captureScreenshots_default = (ctx) => {
4943
5177
 
4944
5178
  // src/commander/capture.ts
4945
5179
  var command2 = new commander.Command();
4946
- 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").option("--scheduled <string>", "Specify the schedule ID").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(file, _, command10) {
5180
+ 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").option("--scheduled <string>", "Specify the schedule ID").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(file, _, command11) {
4947
5181
  return __async(this, null, function* () {
4948
5182
  var _a, _b;
4949
- const options = command10.optsWithGlobals();
5183
+ const options = command11.optsWithGlobals();
4950
5184
  if (options.buildName === "") {
4951
5185
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
4952
5186
  process.exit(1);
4953
5187
  }
4954
- let ctx = ctx_default(command10.optsWithGlobals());
5188
+ let ctx = ctx_default(command11.optsWithGlobals());
4955
5189
  ctx.isSnapshotCaptured = true;
4956
5190
  if (!fs5__default.default.existsSync(file)) {
4957
5191
  ctx.log.error(`Web Static Config file ${file} not found.`);
@@ -5039,14 +5273,14 @@ command3.name("upload").description("Upload screenshots from given directory").a
5039
5273
  return val.split(",").map((ext) => ext.trim().toLowerCase());
5040
5274
  }).option("-E, --removeExtensions", "Strips file extensions from snapshot names").option("-i, --ignoreDir <patterns>", "Comma-separated list of directories to ignore", (val) => {
5041
5275
  return val.split(",").map((pattern) => pattern.trim());
5042
- }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(directory, _, command10) {
5276
+ }).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").option("--buildName <string>", "Specify the build name").option("--userName <string>", "Specify the LT username").option("--accessKey <string>", "Specify the LT accesskey").action(function(directory, _, command11) {
5043
5277
  return __async(this, null, function* () {
5044
- const options = command10.optsWithGlobals();
5278
+ const options = command11.optsWithGlobals();
5045
5279
  if (options.buildName === "") {
5046
5280
  console.log(`Error: The '--buildName' option cannot be an empty string.`);
5047
5281
  process.exit(1);
5048
5282
  }
5049
- let ctx = ctx_default(command10.optsWithGlobals());
5283
+ let ctx = ctx_default(command11.optsWithGlobals());
5050
5284
  ctx.isSnapshotCaptured = true;
5051
5285
  if (!fs5__default.default.existsSync(directory)) {
5052
5286
  console.log(`Error: The provided directory ${directory} not found.`);
@@ -5324,10 +5558,10 @@ var uploadAppFigma_default2 = (ctx) => {
5324
5558
  var uploadFigma = new commander.Command();
5325
5559
  var uploadWebFigmaCommand = new commander.Command();
5326
5560
  var uploadAppFigmaCommand = new commander.Command();
5327
- 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, _, command10) {
5561
+ 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, _, command11) {
5328
5562
  return __async(this, null, function* () {
5329
5563
  var _a, _b;
5330
- let ctx = ctx_default(command10.optsWithGlobals());
5564
+ let ctx = ctx_default(command11.optsWithGlobals());
5331
5565
  ctx.isSnapshotCaptured = true;
5332
5566
  if (!fs5__default.default.existsSync(file)) {
5333
5567
  console.log(`Error: Figma Config file ${file} not found.`);
@@ -5366,10 +5600,10 @@ uploadFigma.name("upload-figma").description("Capture screenshots of static site
5366
5600
  }
5367
5601
  });
5368
5602
  });
5369
- uploadWebFigmaCommand.name("upload-figma-web").description("Capture figma screenshots into CLI build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command10) {
5603
+ uploadWebFigmaCommand.name("upload-figma-web").description("Capture figma screenshots into CLI build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command11) {
5370
5604
  return __async(this, null, function* () {
5371
5605
  var _a;
5372
- let ctx = ctx_default(command10.optsWithGlobals());
5606
+ let ctx = ctx_default(command11.optsWithGlobals());
5373
5607
  if (!fs5__default.default.existsSync(file)) {
5374
5608
  console.log(`Error: figma-web config file ${file} not found.`);
5375
5609
  return;
@@ -5419,10 +5653,10 @@ uploadWebFigmaCommand.name("upload-figma-web").description("Capture figma screen
5419
5653
  }
5420
5654
  });
5421
5655
  });
5422
- uploadAppFigmaCommand.name("upload-figma-app").description("Capture figma screenshots into App Build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command10) {
5656
+ uploadAppFigmaCommand.name("upload-figma-app").description("Capture figma screenshots into App Build").argument("<file>", "figma config config file").option("--markBaseline", "Mark the uploaded images as baseline").option("--buildName <buildName>", "Name of the build").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command11) {
5423
5657
  return __async(this, null, function* () {
5424
5658
  var _a;
5425
- let ctx = ctx_default(command10.optsWithGlobals());
5659
+ let ctx = ctx_default(command11.optsWithGlobals());
5426
5660
  if (!fs5__default.default.existsSync(file)) {
5427
5661
  console.log(`Error: figma-app config file ${file} not found.`);
5428
5662
  return;
@@ -5486,10 +5720,10 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5486
5720
  ctx.isStartExec = true;
5487
5721
  let tasks = new listr2.Listr(
5488
5722
  [
5489
- auth_default(),
5723
+ authExec_default(),
5490
5724
  startServer_default(),
5491
5725
  getGitInfo_default(),
5492
- createBuild_default()
5726
+ createBuildExec_default()
5493
5727
  ],
5494
5728
  {
5495
5729
  rendererOptions: {
@@ -5504,8 +5738,10 @@ command4.name("exec:start").description("Start SmartUI server").option("-P, --po
5504
5738
  );
5505
5739
  try {
5506
5740
  yield tasks.run(ctx);
5507
- startPingPolling(ctx);
5508
- if (ctx.options.fetchResults) {
5741
+ if (ctx.build && ctx.build.id) {
5742
+ startPingPolling(ctx);
5743
+ }
5744
+ if (ctx.options.fetchResults && ctx.build && ctx.build.id) {
5509
5745
  startPolling(ctx, "", false, "");
5510
5746
  }
5511
5747
  } catch (error) {
@@ -5866,10 +6102,104 @@ command9.name("exec:pingTest").description("Ping the SmartUI server to check if
5866
6102
  });
5867
6103
  });
5868
6104
  var pingTest_default = command9;
6105
+ var uploadPdfs_default = (ctx) => {
6106
+ return {
6107
+ title: "Uploading PDFs",
6108
+ task: (ctx2, task) => __async(void 0, null, function* () {
6109
+ try {
6110
+ ctx2.task = task;
6111
+ updateLogContext({ task: "upload-pdf" });
6112
+ yield uploadPdfs(ctx2, ctx2.uploadFilePath);
6113
+ task.title = "PDFs uploaded successfully";
6114
+ } catch (error) {
6115
+ ctx2.log.debug(error);
6116
+ task.output = chalk__default.default.red(`${error.message}`);
6117
+ throw new Error("PDF upload failed");
6118
+ }
6119
+ }),
6120
+ rendererOptions: { persistentOutput: true },
6121
+ exitOnError: false
6122
+ };
6123
+ };
6124
+ function uploadPdfs(ctx, pdfPath) {
6125
+ return __async(this, null, function* () {
6126
+ const formData = new FormData__default.default();
6127
+ if (pdfPath.endsWith(".pdf")) {
6128
+ formData.append("pathToFiles", fs5__default.default.createReadStream(pdfPath));
6129
+ } else {
6130
+ const files = fs5__default.default.readdirSync(pdfPath);
6131
+ const pdfFiles = files.filter((file) => file.endsWith(".pdf"));
6132
+ pdfFiles.forEach((pdf) => {
6133
+ const filePath = path2__default.default.join(pdfPath, pdf);
6134
+ formData.append("pathToFiles", fs5__default.default.createReadStream(filePath));
6135
+ });
6136
+ }
6137
+ const buildName = ctx.options.buildName;
6138
+ if (buildName) {
6139
+ ctx.build.name = buildName;
6140
+ }
6141
+ try {
6142
+ const response = yield ctx.client.uploadPdf(ctx, formData, buildName);
6143
+ if (response && response.buildId) {
6144
+ ctx.build.id = response.buildId;
6145
+ ctx.log.debug(`PDF upload successful. Build ID: ${ctx.build.id}`);
6146
+ }
6147
+ if (response && response.projectId) {
6148
+ ctx.build.projectId = response.projectId;
6149
+ }
6150
+ } catch (error) {
6151
+ throw new Error(error.message);
6152
+ }
6153
+ });
6154
+ }
6155
+
6156
+ // src/commander/uploadPdf.ts
6157
+ var command10 = new commander.Command();
6158
+ command10.name("upload-pdf").description("Upload PDFs for visual comparison").argument("<directory>", "Path of the directory containing PDFs").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, _, command11) {
6159
+ return __async(this, null, function* () {
6160
+ const options = command11.optsWithGlobals();
6161
+ if (options.buildName === "") {
6162
+ console.log(`Error: The '--buildName' option cannot be an empty string.`);
6163
+ process.exit(1);
6164
+ }
6165
+ let ctx = ctx_default(command11.optsWithGlobals());
6166
+ if (!fs5__default.default.existsSync(directory)) {
6167
+ console.log(`Error: The provided directory ${directory} not found.`);
6168
+ process.exit(1);
6169
+ }
6170
+ ctx.uploadFilePath = directory;
6171
+ let tasks = new listr2.Listr(
6172
+ [
6173
+ auth_default(),
6174
+ uploadPdfs_default()
6175
+ ],
6176
+ {
6177
+ rendererOptions: {
6178
+ icon: {
6179
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: `\u2192`
6180
+ },
6181
+ color: {
6182
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
6183
+ }
6184
+ }
6185
+ }
6186
+ );
6187
+ try {
6188
+ yield tasks.run(ctx);
6189
+ if (ctx.options.fetchResults) {
6190
+ startPdfPolling(ctx);
6191
+ }
6192
+ } catch (error) {
6193
+ console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
6194
+ process.exit(1);
6195
+ }
6196
+ });
6197
+ });
6198
+ var uploadPdf_default = command10;
5869
6199
 
5870
6200
  // src/commander/commander.ts
5871
6201
  var program2 = new commander.Command();
5872
- 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").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);
6202
+ 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").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);
5873
6203
  var commander_default = program2;
5874
6204
  (function() {
5875
6205
  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.28",
3
+ "version": "4.1.29",
4
4
  "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
5
5
  "files": [
6
6
  "dist/**/*"