@lambdatest/smartui-cli 1.0.3 → 2.0.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,689 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var commander = require('commander');
5
+ var which = require('which');
6
+ var listr2 = require('listr2');
7
+ var chalk = require('chalk');
8
+ var path2 = require('path');
9
+ var fastify = require('fastify');
10
+ var fs = require('fs');
11
+ var winston = require('winston');
12
+ var FormData = require('form-data');
13
+ var axios = require('axios');
14
+ var child_process = require('child_process');
15
+ var spawn = require('cross-spawn');
16
+ var playwright = require('playwright');
17
+
18
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
19
+
20
+ var which__default = /*#__PURE__*/_interopDefault(which);
21
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
22
+ var path2__default = /*#__PURE__*/_interopDefault(path2);
23
+ var fastify__default = /*#__PURE__*/_interopDefault(fastify);
24
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
25
+ var FormData__default = /*#__PURE__*/_interopDefault(FormData);
26
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
27
+ var spawn__default = /*#__PURE__*/_interopDefault(spawn);
28
+
29
+ var __defProp = Object.defineProperty;
30
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
31
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
32
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
33
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
34
+ var __spreadValues = (a, b) => {
35
+ for (var prop in b || (b = {}))
36
+ if (__hasOwnProp.call(b, prop))
37
+ __defNormalProp(a, prop, b[prop]);
38
+ if (__getOwnPropSymbols)
39
+ for (var prop of __getOwnPropSymbols(b)) {
40
+ if (__propIsEnum.call(b, prop))
41
+ __defNormalProp(a, prop, b[prop]);
42
+ }
43
+ return a;
44
+ };
45
+ var __async = (__this, __arguments, generator) => {
46
+ return new Promise((resolve, reject) => {
47
+ var fulfilled = (value) => {
48
+ try {
49
+ step(generator.next(value));
50
+ } catch (e) {
51
+ reject(e);
52
+ }
53
+ };
54
+ var rejected = (value) => {
55
+ try {
56
+ step(generator.throw(value));
57
+ } catch (e) {
58
+ reject(e);
59
+ }
60
+ };
61
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
62
+ step((generator = generator.apply(__this, __arguments)).next());
63
+ });
64
+ };
65
+ var server_default = (ctx) => __async(void 0, null, function* () {
66
+ const server = fastify__default.default({ logger: false, bodyLimit: 1e7 });
67
+ const opts = {};
68
+ const SMARTUI_DOM = fs.readFileSync(path2__default.default.resolve(__dirname, "dom-serializer.js"), "utf-8");
69
+ server.get("/healthcheck", opts, (_, reply) => {
70
+ reply.code(200).send({ cliVersion: ctx.cliVersion });
71
+ });
72
+ server.get("/domserializer", opts, (request, reply) => {
73
+ reply.code(200).send({ data: { dom: SMARTUI_DOM } });
74
+ });
75
+ server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
76
+ let { snapshot, testType } = request.body;
77
+ snapshot.dom = Buffer.from(snapshot.dom).toString("base64");
78
+ try {
79
+ yield ctx.client.uploadSnapshot(ctx.build.id, snapshot, testType, ctx.log);
80
+ } catch (error) {
81
+ reply.code(500).send({ error: { message: error.message } });
82
+ }
83
+ reply.code(200).send({ data: { message: "success" } });
84
+ }));
85
+ yield server.listen({ port: 8080 });
86
+ let { address, port } = server.addresses()[0];
87
+ process.env.SMARTUI_SERVER_ADDRESS = `http://${address}:${port}`;
88
+ return server;
89
+ });
90
+
91
+ // src/lib/env.ts
92
+ var env_default = () => {
93
+ const {
94
+ PROJECT_TOKEN = "",
95
+ SMARTUI_CLIENT_API_URL = "https://api.lambdatest.com/visualui/1.0",
96
+ SMARTUI_LOG_LEVEL,
97
+ SMARTUI_DEBUG
98
+ } = process.env;
99
+ return {
100
+ PROJECT_TOKEN,
101
+ SMARTUI_CLIENT_API_URL,
102
+ SMARTUI_LOG_LEVEL,
103
+ SMARTUI_DEBUG
104
+ };
105
+ };
106
+
107
+ // src/lib/logger.ts
108
+ var logContext = {};
109
+ function updateLogContext(newContext) {
110
+ logContext = __spreadValues(__spreadValues({}, logContext), newContext);
111
+ }
112
+ var logLevel = () => {
113
+ let env = env_default();
114
+ let debug = env.SMARTUI_DEBUG === "true" ? "debug" : void 0;
115
+ return debug || env.SMARTUI_LOG_LEVEL || "info";
116
+ };
117
+ var logger = winston.createLogger({
118
+ level: logLevel(),
119
+ format: winston.format.combine(
120
+ winston.format.timestamp(),
121
+ winston.format.printf((info) => {
122
+ let contextString;
123
+ if (logContext && Object.keys(logContext).length) {
124
+ contextString = Object.values(logContext).join(" | ");
125
+ }
126
+ let message = `[${contextString}:${info.level}] `;
127
+ message += info.message === "object" ? JSON.stringify(info.message) : info.message;
128
+ return message;
129
+ })
130
+ ),
131
+ transports: [new winston.transports.File({ filename: "smartui.log" })]
132
+ });
133
+ var logger_default = logger;
134
+
135
+ // src/tasks/startServer.ts
136
+ var startServer_default = (ctx) => {
137
+ return {
138
+ title: `Setting up SmartUI server`,
139
+ task: (ctx2, task) => __async(void 0, null, function* () {
140
+ var _a;
141
+ updateLogContext({ task: "startServer" });
142
+ try {
143
+ ctx2.server = yield server_default(ctx2);
144
+ task.output = chalk__default.default.gray(`listening on port ${(_a = ctx2.server.addresses()[0]) == null ? void 0 : _a.port}`);
145
+ task.title = "SmartUI started";
146
+ } catch (error) {
147
+ if (error.code === "EADDRINUSE") {
148
+ task.output = chalk__default.default.gray(`port 8080 is already in use`);
149
+ }
150
+ throw new Error("SmartUI server setup failed");
151
+ }
152
+ }),
153
+ rendererOptions: { persistentOutput: true }
154
+ };
155
+ };
156
+ var auth_default = (ctx) => {
157
+ return {
158
+ title: `Authenticating with SmartUI`,
159
+ task: (ctx2, task) => __async(void 0, null, function* () {
160
+ updateLogContext({ task: "auth" });
161
+ try {
162
+ yield ctx2.client.auth(ctx2.log);
163
+ task.output = chalk__default.default.gray(`using project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
164
+ task.title = "Authenticated with SmartUI";
165
+ } catch (error) {
166
+ ctx2.log.debug(error.message);
167
+ throw new Error("Authentication failed");
168
+ }
169
+ }),
170
+ rendererOptions: { persistentOutput: true }
171
+ };
172
+ };
173
+ var DEFAULT_WEB_STATIC_CONFIG = [
174
+ {
175
+ "name": "lambdatest-home-page",
176
+ "url": "https://www.lambdatest.com",
177
+ "waitForTimeout": 1e3
178
+ },
179
+ {
180
+ "name": "example-page",
181
+ "url": "https://example.com/"
182
+ }
183
+ ];
184
+ var DEFAULT_WEB_CONFIG = {
185
+ web: {
186
+ browsers: [
187
+ "chrome",
188
+ "firefox",
189
+ "safari",
190
+ "edge"
191
+ ],
192
+ viewports: [
193
+ [1920, 1080],
194
+ [1366, 768],
195
+ [360, 640]
196
+ ]
197
+ }
198
+ };
199
+ function createWebConfig(filepath) {
200
+ filepath = filepath || "smartui-web.json";
201
+ let filetype = path2__default.default.extname(filepath);
202
+ if (filetype != ".json") {
203
+ console.log("Error: Config file must have .json extension");
204
+ return;
205
+ }
206
+ if (fs__default.default.existsSync(filepath)) {
207
+ console.log(`Error: SmartUI Web Config already exists: ${filepath}`);
208
+ console.log(`To create a new file, please specify the file name like: 'smartui config:create-web webConfig.json'`);
209
+ return;
210
+ }
211
+ fs__default.default.mkdirSync(path2__default.default.dirname(filepath), { recursive: true });
212
+ fs__default.default.writeFileSync(filepath, JSON.stringify(DEFAULT_WEB_CONFIG, null, 2) + "\n");
213
+ console.log(`Created SmartUI Web Config: ${filepath}`);
214
+ }
215
+ function createWebStaticConfig(filepath) {
216
+ filepath = filepath || "url.json";
217
+ let filetype = path2__default.default.extname(filepath);
218
+ if (filetype != ".json") {
219
+ console.log("Error: Config file must have .json extension");
220
+ return;
221
+ }
222
+ if (fs__default.default.existsSync(filepath)) {
223
+ console.log(`Error: web-static config already exists: ${filepath}`);
224
+ console.log(`To create a new file, please specify the file name like: 'smartui config:create-web links.json'`);
225
+ return;
226
+ }
227
+ fs__default.default.mkdirSync(path2__default.default.dirname(filepath), { recursive: true });
228
+ fs__default.default.writeFileSync(filepath, JSON.stringify(DEFAULT_WEB_STATIC_CONFIG, null, 2) + "\n");
229
+ console.log(`Created web-static config: ${filepath}`);
230
+ }
231
+
232
+ // package.json
233
+ var version = "2.0.1";
234
+ function delDir(dir) {
235
+ if (fs__default.default.existsSync(dir)) {
236
+ fs__default.default.rmSync(dir, { recursive: true });
237
+ }
238
+ }
239
+
240
+ // src/lib/httpClient.ts
241
+ var httpClient = class {
242
+ constructor({ SMARTUI_CLIENT_API_URL, PROJECT_TOKEN }) {
243
+ this.axiosInstance = axios__default.default.create({
244
+ baseURL: SMARTUI_CLIENT_API_URL,
245
+ headers: { "projectToken": PROJECT_TOKEN }
246
+ });
247
+ }
248
+ request(config, log) {
249
+ return __async(this, null, function* () {
250
+ log.debug(`http request: ${JSON.stringify(config)}`);
251
+ return this.axiosInstance.request(config).then((resp) => {
252
+ log.debug(`http response: ${JSON.stringify({
253
+ status: resp.status,
254
+ headers: resp.headers,
255
+ body: resp.data
256
+ })}`);
257
+ return resp.data;
258
+ }).catch((error) => {
259
+ if (error.response) {
260
+ throw new Error(JSON.stringify(error.response.data));
261
+ }
262
+ if (error.request) {
263
+ throw new Error(error.toJSON().message);
264
+ }
265
+ throw new Error(error.message);
266
+ });
267
+ });
268
+ }
269
+ auth(log) {
270
+ return this.request({
271
+ url: "/token/verify",
272
+ method: "GET"
273
+ }, log);
274
+ }
275
+ createBuild({ branch, commitId, commitAuthor, commitMessage, githubURL }, config, log) {
276
+ return this.request({
277
+ url: "/build",
278
+ method: "POST",
279
+ data: {
280
+ git: {
281
+ branch,
282
+ commitId,
283
+ commitAuthor,
284
+ commitMessage,
285
+ githubURL
286
+ },
287
+ config: {
288
+ browsers: config.browsers,
289
+ resolutions: config.viewports
290
+ }
291
+ }
292
+ }, log);
293
+ }
294
+ finalizeBuild(buildId, log) {
295
+ return this.request({
296
+ url: "/build",
297
+ method: "DELETE",
298
+ params: {
299
+ buildId
300
+ }
301
+ }, log);
302
+ }
303
+ uploadSnapshot(buildId, snapshot, testType, log) {
304
+ return this.request({
305
+ url: `/builds/${buildId}/snapshot`,
306
+ method: "POST",
307
+ headers: { "Content-Type": "application/json" },
308
+ data: {
309
+ snapshot,
310
+ test: {
311
+ type: testType,
312
+ source: "cli"
313
+ }
314
+ }
315
+ }, log);
316
+ }
317
+ uploadScreenshot({ id: buildId, name: buildName, baseline }, ssPath, ssName, browserName, viewport, completed) {
318
+ const file = fs__default.default.readFileSync(ssPath);
319
+ const form = new FormData__default.default();
320
+ form.append("screenshots", file, { filename: `${ssName}.png`, contentType: "image/png" });
321
+ form.append("browser", browserName);
322
+ form.append("resolution", viewport);
323
+ form.append("buildId", buildId);
324
+ form.append("buildName", buildName);
325
+ form.append("screenshotName", ssName);
326
+ form.append("baseline", baseline.toString());
327
+ form.append("completed", completed.toString());
328
+ return this.axiosInstance.request({
329
+ url: `/screenshot`,
330
+ method: "POST",
331
+ headers: form.getHeaders(),
332
+ data: form
333
+ }).then(() => {
334
+ if (completed)
335
+ delDir("screenshots");
336
+ }).catch((error) => {
337
+ if (error.response) {
338
+ throw new Error(JSON.stringify(error.response.data));
339
+ }
340
+ if (error.request) {
341
+ throw new Error(error.toJSON().message);
342
+ }
343
+ throw new Error(error.message);
344
+ });
345
+ }
346
+ };
347
+ var ctx_default = (options) => {
348
+ let env = env_default();
349
+ let viewports = [];
350
+ let webConfig = DEFAULT_WEB_CONFIG;
351
+ try {
352
+ if (options.config) {
353
+ webConfig = JSON.parse(fs__default.default.readFileSync(options.config, "utf-8"));
354
+ }
355
+ for (let viewport of webConfig.web.viewports) {
356
+ viewports.push({ width: viewport[0], height: viewport[1] });
357
+ }
358
+ } catch (error) {
359
+ throw new Error(error.message);
360
+ }
361
+ return {
362
+ env,
363
+ log: logger_default,
364
+ client: new httpClient(env),
365
+ config: {
366
+ browsers: webConfig.web.browsers,
367
+ viewports
368
+ },
369
+ staticConfig: [],
370
+ git: {
371
+ branch: "",
372
+ commitId: "",
373
+ commitAuthor: "",
374
+ commitMessage: "",
375
+ githubURL: ""
376
+ },
377
+ build: {
378
+ id: "",
379
+ name: "",
380
+ baseline: false,
381
+ url: "",
382
+ projectId: ""
383
+ },
384
+ args: {},
385
+ cliVersion: version
386
+ };
387
+ };
388
+ function executeCommand(command3) {
389
+ let dst = process.cwd();
390
+ try {
391
+ return child_process.execSync(command3, {
392
+ cwd: dst,
393
+ stdio: ["ignore"],
394
+ encoding: "utf-8"
395
+ });
396
+ } catch (error) {
397
+ throw new Error(error.message);
398
+ }
399
+ }
400
+ function isGitRepo() {
401
+ try {
402
+ executeCommand("git status");
403
+ return true;
404
+ } catch (error) {
405
+ return false;
406
+ }
407
+ }
408
+ var git_default = () => {
409
+ const splitCharacter = "<##>";
410
+ const prettyFormat = ["%h", "%H", "%s", "%f", "%b", "%at", "%ct", "%an", "%ae", "%cn", "%ce", "%N", ""];
411
+ const command3 = 'git log -1 --pretty=format:"' + prettyFormat.join(splitCharacter) + '" && git rev-parse --abbrev-ref HEAD && git tag --contains HEAD';
412
+ let res = executeCommand(command3).split(splitCharacter);
413
+ var branchAndTags = res[res.length - 1].split("\n").filter((n) => n);
414
+ var branch = branchAndTags[0];
415
+ branchAndTags.slice(1);
416
+ return {
417
+ branch,
418
+ commitId: res[0] || "",
419
+ commitMessage: res[2] || "",
420
+ commitAuthor: res[7] || ""
421
+ };
422
+ };
423
+ var getGitInfo_default = (ctx) => {
424
+ return {
425
+ title: `Fetching git repo details`,
426
+ skip: (ctx2) => {
427
+ return !isGitRepo() ? "[SKIPPED] Fetching git repo details; not a git repo" : "";
428
+ },
429
+ task: (ctx2, task) => __async(void 0, null, function* () {
430
+ try {
431
+ ctx2.git = git_default();
432
+ task.output = chalk__default.default.gray(`branch: ${ctx2.git.branch}, commit: ${ctx2.git.commitId}, author: ${ctx2.git.commitAuthor}`);
433
+ task.title = "Fetched git information";
434
+ } catch (error) {
435
+ task.output = chalk__default.default.gray(`${error.message}`);
436
+ throw new Error("Error fetching git repo details");
437
+ }
438
+ }),
439
+ rendererOptions: { persistentOutput: true }
440
+ };
441
+ };
442
+ var createBuild_default = (ctx) => {
443
+ return {
444
+ title: `Creating SmartUI build`,
445
+ task: (ctx2, task) => __async(void 0, null, function* () {
446
+ updateLogContext({ task: "createBuild" });
447
+ try {
448
+ let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.config, ctx2.log);
449
+ ctx2.build = {
450
+ id: resp.data.buildId,
451
+ name: resp.data.buildName,
452
+ url: resp.buildURL,
453
+ baseline: resp.data.baseline || false,
454
+ projectId: resp.data.projectId
455
+ };
456
+ task.output = chalk__default.default.gray(`build id: ${resp.data.buildId}`);
457
+ task.title = "SmartUI build created";
458
+ } catch (error) {
459
+ task.output = chalk__default.default.gray(JSON.parse(error.message).message);
460
+ throw new Error("SmartUI build creation failed");
461
+ }
462
+ }),
463
+ rendererOptions: { persistentOutput: true }
464
+ };
465
+ };
466
+ var exec_default = (ctx) => {
467
+ var _a;
468
+ return {
469
+ title: `Executing '${(_a = ctx.args.execCommand) == null ? void 0 : _a.join(" ")}'`,
470
+ task: (ctx2, task) => __async(void 0, null, function* () {
471
+ updateLogContext({ task: "exec" });
472
+ return new Promise((resolve, reject) => {
473
+ var _a2, _b, _c;
474
+ const childProcess = spawn__default.default(ctx2.args.execCommand[0], (_a2 = ctx2.args.execCommand) == null ? void 0 : _a2.slice(1));
475
+ let totalOutput = "";
476
+ const output = listr2.createWritable((chunk) => {
477
+ totalOutput += chunk;
478
+ task.output = chalk__default.default.gray(totalOutput);
479
+ });
480
+ (_b = childProcess.stdout) == null ? void 0 : _b.pipe(output);
481
+ (_c = childProcess.stderr) == null ? void 0 : _c.pipe(output);
482
+ childProcess.on("error", (error) => {
483
+ var _a3;
484
+ task.output = chalk__default.default.gray(`error: ${error.message}`);
485
+ throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' failed`);
486
+ });
487
+ childProcess.on("close", (code, signal) => __async(void 0, null, function* () {
488
+ var _a3;
489
+ if (code !== null) {
490
+ task.title = `Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' completed; exited with code ${code}`;
491
+ } else if (signal !== null) {
492
+ throw new Error(`Child process killed with signal ${signal}`);
493
+ }
494
+ resolve();
495
+ }));
496
+ });
497
+ }),
498
+ rendererOptions: { persistentOutput: true }
499
+ };
500
+ };
501
+ var finalizeBuild_default = (ctx, waitTime) => {
502
+ return {
503
+ title: `Finalizing build`,
504
+ task: (ctx2, task) => __async(void 0, null, function* () {
505
+ try {
506
+ if (waitTime > 0) {
507
+ yield new Promise((resolve) => setTimeout(resolve, waitTime));
508
+ yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.log);
509
+ }
510
+ task.output = chalk__default.default.gray(`build url: ${ctx2.build.url}`);
511
+ task.title = "Finalized build";
512
+ } catch (error) {
513
+ throw new Error("Finalize build error");
514
+ }
515
+ }),
516
+ rendererOptions: { persistentOutput: true }
517
+ };
518
+ };
519
+
520
+ // src/commander/exec.ts
521
+ var command = new commander.Command();
522
+ command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").action(function(execCommand, _, command3) {
523
+ return __async(this, null, function* () {
524
+ var _a;
525
+ let ctx = ctx_default(command3.optsWithGlobals());
526
+ if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
527
+ console.log(`Error: Command not found "${execCommand[0]}"`);
528
+ return;
529
+ }
530
+ ctx.args.execCommand = execCommand;
531
+ let tasks = new listr2.Listr(
532
+ [
533
+ auth_default(),
534
+ startServer_default(),
535
+ getGitInfo_default(),
536
+ createBuild_default(),
537
+ exec_default(ctx),
538
+ finalizeBuild_default(ctx, 3e4)
539
+ ],
540
+ {
541
+ rendererOptions: {
542
+ icon: {
543
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: `\u2192`
544
+ },
545
+ color: {
546
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
547
+ }
548
+ }
549
+ }
550
+ );
551
+ try {
552
+ yield tasks.run(ctx);
553
+ } catch (error) {
554
+ console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
555
+ } finally {
556
+ yield (_a = ctx.server) == null ? void 0 : _a.close();
557
+ }
558
+ });
559
+ });
560
+ var exec_default2 = command;
561
+ var configWeb = new commander.Command();
562
+ var configStatic = new commander.Command();
563
+ configWeb.name("config:create-web").description("Create SmartUI Web config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
564
+ return __async(this, null, function* () {
565
+ createWebConfig(filepath);
566
+ });
567
+ });
568
+ configStatic.name("config:web-static").description("Create Web Static config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
569
+ return __async(this, null, function* () {
570
+ createWebStaticConfig(filepath);
571
+ });
572
+ });
573
+ var BROWSER_CHROME = "chrome";
574
+ var BROWSER_SAFARI = "safari";
575
+ var BROWSER_FIREFOX = "firefox";
576
+ var BROWSER_EDGE = "edge";
577
+ var EDGE_CHANNEL = "msedge";
578
+ function captureScreenshots(ctx, screenshots) {
579
+ return __async(this, null, function* () {
580
+ var _a;
581
+ delDir("screenshots");
582
+ let totalBrowsers = ctx.config.browsers.length;
583
+ let totalViewports = ctx.config.viewports.length;
584
+ let totalScreenshots = screenshots.length;
585
+ for (let i = 0; i < totalBrowsers; i++) {
586
+ let browserName = (_a = ctx.config.browsers[i]) == null ? void 0 : _a.toLowerCase();
587
+ let browser;
588
+ let launchOptions = { headless: true };
589
+ switch (browserName) {
590
+ case BROWSER_CHROME:
591
+ browser = yield playwright.chromium.launch(launchOptions);
592
+ break;
593
+ case BROWSER_SAFARI:
594
+ browser = yield playwright.webkit.launch(launchOptions);
595
+ break;
596
+ case BROWSER_FIREFOX:
597
+ browser = yield playwright.firefox.launch(launchOptions);
598
+ break;
599
+ case BROWSER_EDGE:
600
+ launchOptions.channel = EDGE_CHANNEL;
601
+ browser = yield playwright.chromium.launch(launchOptions);
602
+ break;
603
+ }
604
+ const context = yield browser.newContext();
605
+ for (let j = 0; j < totalScreenshots; j++) {
606
+ let screenshot = screenshots[j];
607
+ let screenshotId = screenshot.name.toLowerCase().replace(/\s/g, "-");
608
+ const page = yield context.newPage();
609
+ yield page.goto(screenshot.url);
610
+ yield page.waitForTimeout(screenshot.waitForTimeout || 0);
611
+ for (let k = 0; k < totalViewports; k++) {
612
+ let { width, height } = ctx.config.viewports[k];
613
+ let ssName = `${browserName}-${width}x${height}-${screenshotId}.png`;
614
+ let ssPath = `screenshots/${screenshotId}/${ssName}.png`;
615
+ yield page.setViewportSize({ width, height });
616
+ yield page.screenshot({ path: ssPath, fullPage: true });
617
+ let completed = i == totalBrowsers - 1 && j == totalScreenshots - 1 && k == totalViewports - 1 ? true : false;
618
+ ctx.client.uploadScreenshot(ctx.build, ssPath, screenshot.name, browserName, `${width}x${height}`, completed);
619
+ }
620
+ yield page.close();
621
+ }
622
+ yield browser.close();
623
+ }
624
+ return totalBrowsers * totalViewports * totalScreenshots;
625
+ });
626
+ }
627
+ var captureScreenshots_default = (ctx) => {
628
+ return {
629
+ title: "Capturing screenshots",
630
+ task: (ctx2, task) => __async(void 0, null, function* () {
631
+ try {
632
+ let { staticConfig: screenshots } = ctx2;
633
+ let totalScreenshots = yield captureScreenshots(ctx2, screenshots);
634
+ task.title = "Screenshots captured successfully";
635
+ task.output = chalk__default.default.gray(`total screenshots: ${totalScreenshots}`);
636
+ } catch (error) {
637
+ console.error(error);
638
+ throw new Error("Capturing screenshots failed");
639
+ }
640
+ }),
641
+ rendererOptions: { persistentOutput: true }
642
+ };
643
+ };
644
+
645
+ // src/commander/capture.ts
646
+ var command2 = new commander.Command();
647
+ command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").action(function(file, _, command3) {
648
+ return __async(this, null, function* () {
649
+ let ctx = ctx_default(command3.optsWithGlobals());
650
+ let tasks = new listr2.Listr(
651
+ [
652
+ auth_default(),
653
+ getGitInfo_default(),
654
+ createBuild_default(),
655
+ captureScreenshots_default(),
656
+ finalizeBuild_default(ctx, 0)
657
+ ],
658
+ {
659
+ rendererOptions: {
660
+ icon: {
661
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: `\u2192`
662
+ },
663
+ color: {
664
+ [listr2.ListrDefaultRendererLogLevels.OUTPUT]: listr2.color.gray
665
+ }
666
+ }
667
+ }
668
+ );
669
+ try {
670
+ if (!fs__default.default.existsSync(file)) {
671
+ console.log(`Error: Config file ${file} not found.`);
672
+ return;
673
+ }
674
+ ctx.staticConfig = JSON.parse(fs__default.default.readFileSync(file, "utf8"));
675
+ yield tasks.run(ctx);
676
+ } catch (error) {
677
+ console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
678
+ }
679
+ });
680
+ });
681
+ var capture_default = command2;
682
+
683
+ // src/commander/commander.ts
684
+ var program = new commander.Command();
685
+ 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);
686
+ var commander_default = program;
687
+
688
+ // src/index.ts
689
+ commander_default.parse();