@lambdatest/smartui-cli 2.0.2 → 2.0.4
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/dom-serializer.js +569 -559
- package/dist/index.cjs +275 -86
- package/package.json +7 -2
package/dist/index.cjs
CHANGED
|
@@ -9,11 +9,13 @@ var path2 = require('path');
|
|
|
9
9
|
var fastify = require('fastify');
|
|
10
10
|
var fs = require('fs');
|
|
11
11
|
var winston = require('winston');
|
|
12
|
+
var Ajv = require('ajv');
|
|
13
|
+
var addErrors = require('ajv-errors');
|
|
12
14
|
var FormData = require('form-data');
|
|
13
15
|
var axios = require('axios');
|
|
14
16
|
var child_process = require('child_process');
|
|
15
17
|
var spawn = require('cross-spawn');
|
|
16
|
-
var
|
|
18
|
+
var test = require('@playwright/test');
|
|
17
19
|
|
|
18
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
21
|
|
|
@@ -22,6 +24,8 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
|
22
24
|
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
23
25
|
var fastify__default = /*#__PURE__*/_interopDefault(fastify);
|
|
24
26
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
27
|
+
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
28
|
+
var addErrors__default = /*#__PURE__*/_interopDefault(addErrors);
|
|
25
29
|
var FormData__default = /*#__PURE__*/_interopDefault(FormData);
|
|
26
30
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
27
31
|
var spawn__default = /*#__PURE__*/_interopDefault(spawn);
|
|
@@ -80,6 +84,7 @@ var server_default = (ctx) => __async(void 0, null, function* () {
|
|
|
80
84
|
} catch (error) {
|
|
81
85
|
reply.code(500).send({ error: { message: error.message } });
|
|
82
86
|
}
|
|
87
|
+
ctx.totalSnapshots++;
|
|
83
88
|
reply.code(200).send({ data: { message: "success" } });
|
|
84
89
|
}));
|
|
85
90
|
yield server.listen({ port: 8080 });
|
|
@@ -164,6 +169,7 @@ var auth_default = (ctx) => {
|
|
|
164
169
|
task.title = "Authenticated with SmartUI";
|
|
165
170
|
} catch (error) {
|
|
166
171
|
ctx2.log.debug(error.message);
|
|
172
|
+
task.output = chalk__default.default.gray(error.message);
|
|
167
173
|
throw new Error("Authentication failed");
|
|
168
174
|
}
|
|
169
175
|
}),
|
|
@@ -181,7 +187,7 @@ var DEFAULT_WEB_STATIC_CONFIG = [
|
|
|
181
187
|
"url": "https://example.com/"
|
|
182
188
|
}
|
|
183
189
|
];
|
|
184
|
-
var
|
|
190
|
+
var DEFAULT_CONFIG = {
|
|
185
191
|
web: {
|
|
186
192
|
browsers: [
|
|
187
193
|
"chrome",
|
|
@@ -190,27 +196,28 @@ var DEFAULT_WEB_CONFIG = {
|
|
|
190
196
|
"edge"
|
|
191
197
|
],
|
|
192
198
|
viewports: [
|
|
193
|
-
[1920
|
|
194
|
-
[1366
|
|
195
|
-
[360
|
|
196
|
-
]
|
|
199
|
+
[1920],
|
|
200
|
+
[1366],
|
|
201
|
+
[360]
|
|
202
|
+
],
|
|
203
|
+
waitForTimeout: 1e3
|
|
197
204
|
}
|
|
198
205
|
};
|
|
199
|
-
function
|
|
200
|
-
filepath = filepath || "smartui
|
|
206
|
+
function createConfig(filepath) {
|
|
207
|
+
filepath = filepath || ".smartui.json";
|
|
201
208
|
let filetype = path2__default.default.extname(filepath);
|
|
202
209
|
if (filetype != ".json") {
|
|
203
210
|
console.log("Error: Config file must have .json extension");
|
|
204
211
|
return;
|
|
205
212
|
}
|
|
206
213
|
if (fs__default.default.existsSync(filepath)) {
|
|
207
|
-
console.log(`Error: SmartUI
|
|
208
|
-
console.log(`To create a new file, please specify the file name like: 'smartui config:create
|
|
214
|
+
console.log(`Error: SmartUI Config already exists: ${filepath}`);
|
|
215
|
+
console.log(`To create a new file, please specify the file name like: 'smartui config:create .smartui-config.json'`);
|
|
209
216
|
return;
|
|
210
217
|
}
|
|
211
218
|
fs__default.default.mkdirSync(path2__default.default.dirname(filepath), { recursive: true });
|
|
212
|
-
fs__default.default.writeFileSync(filepath, JSON.stringify(
|
|
213
|
-
console.log(`Created SmartUI
|
|
219
|
+
fs__default.default.writeFileSync(filepath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
|
|
220
|
+
console.log(`Created SmartUI Config: ${filepath}`);
|
|
214
221
|
}
|
|
215
222
|
function createWebStaticConfig(filepath) {
|
|
216
223
|
filepath = filepath || "url.json";
|
|
@@ -221,7 +228,7 @@ function createWebStaticConfig(filepath) {
|
|
|
221
228
|
}
|
|
222
229
|
if (fs__default.default.existsSync(filepath)) {
|
|
223
230
|
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'`);
|
|
231
|
+
console.log(`To create a new file, please specify the file name like: 'smartui config:create-web-static links.json'`);
|
|
225
232
|
return;
|
|
226
233
|
}
|
|
227
234
|
fs__default.default.mkdirSync(path2__default.default.dirname(filepath), { recursive: true });
|
|
@@ -230,12 +237,153 @@ function createWebStaticConfig(filepath) {
|
|
|
230
237
|
}
|
|
231
238
|
|
|
232
239
|
// package.json
|
|
233
|
-
var version = "2.0.
|
|
240
|
+
var version = "2.0.4";
|
|
241
|
+
var ajv = new Ajv__default.default({ allErrors: true });
|
|
242
|
+
ajv.addFormat("web-url", {
|
|
243
|
+
type: "string",
|
|
244
|
+
validate: (url) => {
|
|
245
|
+
const urlPattern = new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$", "i");
|
|
246
|
+
return urlPattern.test(url.trim());
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
addErrors__default.default(ajv);
|
|
250
|
+
var ConfigSchema = {
|
|
251
|
+
type: "object",
|
|
252
|
+
properties: {
|
|
253
|
+
web: {
|
|
254
|
+
type: "object",
|
|
255
|
+
properties: {
|
|
256
|
+
browsers: {
|
|
257
|
+
type: "array",
|
|
258
|
+
items: { type: "string", enum: ["chrome", "firefox", "edge", "safari"] },
|
|
259
|
+
uniqueItems: true,
|
|
260
|
+
maxItems: 4,
|
|
261
|
+
errorMessage: "Invalid config; allowed browsers - chrome, firefox, edge, safari"
|
|
262
|
+
},
|
|
263
|
+
viewports: {
|
|
264
|
+
type: "array",
|
|
265
|
+
items: {
|
|
266
|
+
type: "array",
|
|
267
|
+
oneOf: [
|
|
268
|
+
{
|
|
269
|
+
items: [{ type: "number", minimum: 320, maximum: 7680 }],
|
|
270
|
+
minItems: 1,
|
|
271
|
+
maxItems: 1
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
items: [
|
|
275
|
+
{ type: "number", minimum: 320, maximum: 7680 },
|
|
276
|
+
{ type: "number", minimum: 320, maximum: 7680 }
|
|
277
|
+
],
|
|
278
|
+
minItems: 2,
|
|
279
|
+
maxItems: 2
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
errorMessage: "Invalid config; width/height must be >= 320 and <= 7680"
|
|
283
|
+
},
|
|
284
|
+
uniqueItems: true,
|
|
285
|
+
maxItems: 5,
|
|
286
|
+
errorMessage: "Invalid config; max unique viewports allowed - 5"
|
|
287
|
+
},
|
|
288
|
+
waitForPageRender: {
|
|
289
|
+
type: "number",
|
|
290
|
+
minimum: 0,
|
|
291
|
+
maximum: 3e5,
|
|
292
|
+
errorMessage: "Invalid config; waitForPageRender must be > 0 and <= 300000"
|
|
293
|
+
},
|
|
294
|
+
waitForTimeout: {
|
|
295
|
+
type: "number",
|
|
296
|
+
minimum: 0,
|
|
297
|
+
maximum: 3e4,
|
|
298
|
+
errorMessage: "Invalid config; waitForTimeout must be > 0 and <= 30000"
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
required: ["browsers", "viewports"],
|
|
302
|
+
additionalProperties: false
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
required: ["web"],
|
|
306
|
+
additionalProperties: false
|
|
307
|
+
};
|
|
308
|
+
var WebStaticConfigSchema = {
|
|
309
|
+
type: "array",
|
|
310
|
+
items: {
|
|
311
|
+
type: "object",
|
|
312
|
+
properties: {
|
|
313
|
+
name: {
|
|
314
|
+
type: "string",
|
|
315
|
+
minLength: 1,
|
|
316
|
+
errorMessage: "name is mandatory and cannot be empty"
|
|
317
|
+
},
|
|
318
|
+
url: {
|
|
319
|
+
type: "string",
|
|
320
|
+
format: "web-url",
|
|
321
|
+
errorMessage: "url is mandatory and must be a valid web URL"
|
|
322
|
+
},
|
|
323
|
+
waitForTimeout: {
|
|
324
|
+
type: "number",
|
|
325
|
+
nullable: true,
|
|
326
|
+
minimum: 0,
|
|
327
|
+
maximum: 3e4,
|
|
328
|
+
errorMessage: "waitForTimeout must be > 0 and <= 30000"
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
required: ["name", "url"],
|
|
332
|
+
additionalProperties: false
|
|
333
|
+
},
|
|
334
|
+
uniqueItems: true
|
|
335
|
+
};
|
|
336
|
+
var validateConfig = ajv.compile(ConfigSchema);
|
|
337
|
+
var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
|
|
338
|
+
var HTTP_SCHEME = "https:";
|
|
339
|
+
var HTTP_SCHEME_PREFIX = "https://";
|
|
340
|
+
var WWW = "www.";
|
|
234
341
|
function delDir(dir) {
|
|
235
342
|
if (fs__default.default.existsSync(dir)) {
|
|
236
343
|
fs__default.default.rmSync(dir, { recursive: true });
|
|
237
344
|
}
|
|
238
345
|
}
|
|
346
|
+
function ensureHttps(urlString) {
|
|
347
|
+
try {
|
|
348
|
+
if (urlString && urlString.startsWith(WWW)) {
|
|
349
|
+
urlString = HTTP_SCHEME_PREFIX + urlString;
|
|
350
|
+
}
|
|
351
|
+
let url = new URL(urlString);
|
|
352
|
+
if (url.protocol !== HTTP_SCHEME) {
|
|
353
|
+
url.protocol = HTTP_SCHEME;
|
|
354
|
+
}
|
|
355
|
+
return url.toString();
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error("Invalid URL: " + urlString, error);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function scrollToBottomAndBackToTop({
|
|
362
|
+
frequency = 100,
|
|
363
|
+
timing = 8,
|
|
364
|
+
remoteWindow = window
|
|
365
|
+
} = {}) {
|
|
366
|
+
return new Promise((resolve) => {
|
|
367
|
+
let scrolls = 1;
|
|
368
|
+
let scrollLength = remoteWindow.document.body.scrollHeight / frequency;
|
|
369
|
+
(function scroll() {
|
|
370
|
+
let scrollBy = scrollLength * scrolls;
|
|
371
|
+
remoteWindow.setTimeout(() => {
|
|
372
|
+
remoteWindow.scrollTo(0, scrollBy);
|
|
373
|
+
if (scrolls < frequency) {
|
|
374
|
+
scrolls += 1;
|
|
375
|
+
scroll();
|
|
376
|
+
}
|
|
377
|
+
if (scrolls === frequency) {
|
|
378
|
+
remoteWindow.setTimeout(() => {
|
|
379
|
+
remoteWindow.scrollTo(0, 0);
|
|
380
|
+
resolve();
|
|
381
|
+
}, timing);
|
|
382
|
+
}
|
|
383
|
+
}, timing);
|
|
384
|
+
})();
|
|
385
|
+
});
|
|
386
|
+
}
|
|
239
387
|
|
|
240
388
|
// src/lib/httpClient.ts
|
|
241
389
|
var httpClient = class {
|
|
@@ -286,18 +434,21 @@ var httpClient = class {
|
|
|
286
434
|
},
|
|
287
435
|
config: {
|
|
288
436
|
browsers: config.browsers,
|
|
289
|
-
resolutions: config.viewports
|
|
437
|
+
resolutions: config.viewports,
|
|
438
|
+
waitForPageRender: config.waitForPageRender,
|
|
439
|
+
waitForTimeout: config.waitForTimeout
|
|
290
440
|
}
|
|
291
441
|
}
|
|
292
442
|
}, log);
|
|
293
443
|
}
|
|
294
|
-
finalizeBuild(buildId, log) {
|
|
444
|
+
finalizeBuild(buildId, totalSnapshots, log) {
|
|
445
|
+
let params = { buildId };
|
|
446
|
+
if (totalSnapshots > -1)
|
|
447
|
+
params.totalSnapshots = totalSnapshots;
|
|
295
448
|
return this.request({
|
|
296
449
|
url: "/build",
|
|
297
450
|
method: "DELETE",
|
|
298
|
-
params
|
|
299
|
-
buildId
|
|
300
|
-
}
|
|
451
|
+
params
|
|
301
452
|
}, log);
|
|
302
453
|
}
|
|
303
454
|
uploadSnapshot(buildId, snapshot, testType, log) {
|
|
@@ -347,26 +498,34 @@ var httpClient = class {
|
|
|
347
498
|
var ctx_default = (options) => {
|
|
348
499
|
let env = env_default();
|
|
349
500
|
let viewports = [];
|
|
350
|
-
let
|
|
501
|
+
let config = DEFAULT_CONFIG;
|
|
351
502
|
try {
|
|
352
503
|
if (options.config) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
504
|
+
config = JSON.parse(fs__default.default.readFileSync(options.config, "utf-8"));
|
|
505
|
+
if (config.web.resolutions) {
|
|
506
|
+
config.web.viewports = config.web.resolutions;
|
|
507
|
+
delete config.web.resolutions;
|
|
508
|
+
}
|
|
357
509
|
}
|
|
510
|
+
if (!validateConfig(config))
|
|
511
|
+
throw new Error(validateConfig.errors[0].message);
|
|
358
512
|
} catch (error) {
|
|
359
|
-
|
|
513
|
+
console.log(`[smartui] Error: ${error.message}`);
|
|
514
|
+
process.exit();
|
|
360
515
|
}
|
|
516
|
+
for (let viewport of config.web.viewports)
|
|
517
|
+
viewports.push({ width: viewport[0], height: viewport[1] || 0 });
|
|
361
518
|
return {
|
|
362
519
|
env,
|
|
363
520
|
log: logger_default,
|
|
364
521
|
client: new httpClient(env),
|
|
365
|
-
|
|
366
|
-
browsers:
|
|
367
|
-
viewports
|
|
522
|
+
webConfig: {
|
|
523
|
+
browsers: config.web.browsers,
|
|
524
|
+
viewports,
|
|
525
|
+
waitForPageRender: config.web.waitForPageRender || 0,
|
|
526
|
+
waitForTimeout: config.web.waitForTimeout || 0
|
|
368
527
|
},
|
|
369
|
-
|
|
528
|
+
webStaticConfig: [],
|
|
370
529
|
git: {
|
|
371
530
|
branch: "",
|
|
372
531
|
commitId: "",
|
|
@@ -382,7 +541,8 @@ var ctx_default = (options) => {
|
|
|
382
541
|
projectId: ""
|
|
383
542
|
},
|
|
384
543
|
args: {},
|
|
385
|
-
cliVersion: version
|
|
544
|
+
cliVersion: version,
|
|
545
|
+
totalSnapshots: -1
|
|
386
546
|
};
|
|
387
547
|
};
|
|
388
548
|
function executeCommand(command3) {
|
|
@@ -445,7 +605,7 @@ var createBuild_default = (ctx) => {
|
|
|
445
605
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
446
606
|
updateLogContext({ task: "createBuild" });
|
|
447
607
|
try {
|
|
448
|
-
let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.
|
|
608
|
+
let resp = yield ctx2.client.createBuild(ctx2.git, ctx2.webConfig, ctx2.log);
|
|
449
609
|
ctx2.build = {
|
|
450
610
|
id: resp.data.buildId,
|
|
451
611
|
name: resp.data.buildName,
|
|
@@ -495,21 +655,22 @@ var exec_default = (ctx) => {
|
|
|
495
655
|
}));
|
|
496
656
|
});
|
|
497
657
|
}),
|
|
498
|
-
rendererOptions: { persistentOutput: true }
|
|
658
|
+
rendererOptions: { persistentOutput: true },
|
|
659
|
+
exitOnError: false
|
|
499
660
|
};
|
|
500
661
|
};
|
|
501
|
-
var finalizeBuild_default = (ctx
|
|
662
|
+
var finalizeBuild_default = (ctx) => {
|
|
502
663
|
return {
|
|
503
664
|
title: `Finalizing build`,
|
|
504
665
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
505
666
|
try {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.log);
|
|
509
|
-
}
|
|
667
|
+
yield new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
668
|
+
yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
|
|
510
669
|
task.output = chalk__default.default.gray(`build url: ${ctx2.build.url}`);
|
|
511
670
|
task.title = "Finalized build";
|
|
512
671
|
} catch (error) {
|
|
672
|
+
ctx2.log.debug(error.message);
|
|
673
|
+
task.output = chalk__default.default.gray(error.message);
|
|
513
674
|
throw new Error("Finalize build error");
|
|
514
675
|
}
|
|
515
676
|
}),
|
|
@@ -528,6 +689,7 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
|
|
|
528
689
|
return;
|
|
529
690
|
}
|
|
530
691
|
ctx.args.execCommand = execCommand;
|
|
692
|
+
ctx.totalSnapshots = 0;
|
|
531
693
|
let tasks = new listr2.Listr(
|
|
532
694
|
[
|
|
533
695
|
auth_default(),
|
|
@@ -535,7 +697,7 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
|
|
|
535
697
|
getGitInfo_default(),
|
|
536
698
|
createBuild_default(),
|
|
537
699
|
exec_default(ctx),
|
|
538
|
-
finalizeBuild_default(
|
|
700
|
+
finalizeBuild_default()
|
|
539
701
|
],
|
|
540
702
|
{
|
|
541
703
|
rendererOptions: {
|
|
@@ -560,12 +722,12 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
|
|
|
560
722
|
var exec_default2 = command;
|
|
561
723
|
var configWeb = new commander.Command();
|
|
562
724
|
var configStatic = new commander.Command();
|
|
563
|
-
configWeb.name("config:create
|
|
725
|
+
configWeb.name("config:create").description("Create SmartUI config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
|
|
564
726
|
return __async(this, null, function* () {
|
|
565
|
-
|
|
727
|
+
createConfig(filepath);
|
|
566
728
|
});
|
|
567
729
|
});
|
|
568
|
-
configStatic.name("config:web-static").description("Create Web Static config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
|
|
730
|
+
configStatic.name("config:create-web-static").description("Create Web Static config file").argument("[filepath]", "Optional config filepath").action(function(filepath, options) {
|
|
569
731
|
return __async(this, null, function* () {
|
|
570
732
|
createWebStaticConfig(filepath);
|
|
571
733
|
});
|
|
@@ -575,51 +737,70 @@ var BROWSER_SAFARI = "safari";
|
|
|
575
737
|
var BROWSER_FIREFOX = "firefox";
|
|
576
738
|
var BROWSER_EDGE = "edge";
|
|
577
739
|
var EDGE_CHANNEL = "msedge";
|
|
740
|
+
var PW_WEBKIT = "webkit";
|
|
741
|
+
var MIN_RESOLUTION_HEIGHT = 320;
|
|
578
742
|
function captureScreenshots(ctx, screenshots) {
|
|
579
743
|
return __async(this, null, function* () {
|
|
580
744
|
var _a;
|
|
581
745
|
delDir("screenshots");
|
|
582
|
-
let totalBrowsers = ctx.
|
|
583
|
-
let totalViewports = ctx.
|
|
746
|
+
let totalBrowsers = ctx.webConfig.browsers.length;
|
|
747
|
+
let totalViewports = ctx.webConfig.viewports.length;
|
|
584
748
|
let totalScreenshots = screenshots.length;
|
|
749
|
+
let capturedScreenshots = 0;
|
|
585
750
|
for (let i = 0; i < totalBrowsers; i++) {
|
|
586
|
-
let browserName = (_a = ctx.
|
|
751
|
+
let browserName = (_a = ctx.webConfig.browsers[i]) == null ? void 0 : _a.toLowerCase();
|
|
587
752
|
let browser;
|
|
588
753
|
let launchOptions = { headless: true };
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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);
|
|
754
|
+
let pageOptions = { waitUntil: process.env.SMARTUI_PAGE_WAIT_UNTIL_EVENT || "load" };
|
|
755
|
+
try {
|
|
756
|
+
switch (browserName) {
|
|
757
|
+
case BROWSER_CHROME:
|
|
758
|
+
browser = yield test.chromium.launch(launchOptions);
|
|
759
|
+
break;
|
|
760
|
+
case BROWSER_SAFARI:
|
|
761
|
+
browser = yield test.webkit.launch(launchOptions);
|
|
762
|
+
break;
|
|
763
|
+
case BROWSER_FIREFOX:
|
|
764
|
+
browser = yield test.firefox.launch(launchOptions);
|
|
765
|
+
break;
|
|
766
|
+
case BROWSER_EDGE:
|
|
767
|
+
launchOptions.channel = EDGE_CHANNEL;
|
|
768
|
+
browser = yield test.chromium.launch(launchOptions);
|
|
769
|
+
break;
|
|
619
770
|
}
|
|
620
|
-
yield
|
|
771
|
+
const context = yield browser.newContext();
|
|
772
|
+
for (let j = 0; j < totalScreenshots; j++) {
|
|
773
|
+
let screenshot = screenshots[j];
|
|
774
|
+
let screenshotId = screenshot.name.toLowerCase().replace(/\s/g, "-");
|
|
775
|
+
const page = yield context.newPage();
|
|
776
|
+
if (screenshot.url) {
|
|
777
|
+
screenshot.url = screenshot.url.trim();
|
|
778
|
+
screenshot.url = ensureHttps(screenshot.url);
|
|
779
|
+
}
|
|
780
|
+
yield page.goto(screenshot.url, pageOptions);
|
|
781
|
+
for (let k = 0; k < totalViewports; k++) {
|
|
782
|
+
let { width, height } = ctx.webConfig.viewports[k];
|
|
783
|
+
let ssName = `${browserName}-${width}x${height}-${screenshotId}.png`;
|
|
784
|
+
let ssPath = `screenshots/${screenshotId}/${ssName}.png`;
|
|
785
|
+
yield page.setViewportSize({ width, height: height || MIN_RESOLUTION_HEIGHT });
|
|
786
|
+
if (height === 0)
|
|
787
|
+
yield page.evaluate(scrollToBottomAndBackToTop);
|
|
788
|
+
yield page.waitForTimeout(screenshot.waitForTimeout || 0);
|
|
789
|
+
yield page.screenshot({ path: ssPath, fullPage: height ? false : true });
|
|
790
|
+
let completed = i == totalBrowsers - 1 && j == totalScreenshots - 1 && k == totalViewports - 1 ? true : false;
|
|
791
|
+
browserName = browserName === BROWSER_SAFARI ? PW_WEBKIT : browserName;
|
|
792
|
+
ctx.client.uploadScreenshot(ctx.build, ssPath, screenshot.name, browserName, `${width}x${height}`, completed);
|
|
793
|
+
capturedScreenshots++;
|
|
794
|
+
ctx.task.output = chalk__default.default.gray(`screenshots captured: ${capturedScreenshots}/${totalBrowsers * totalViewports * totalScreenshots}`);
|
|
795
|
+
}
|
|
796
|
+
yield page.close();
|
|
797
|
+
}
|
|
798
|
+
yield browser.close();
|
|
799
|
+
} catch (error) {
|
|
800
|
+
if (browser)
|
|
801
|
+
yield browser.close();
|
|
802
|
+
throw error;
|
|
621
803
|
}
|
|
622
|
-
yield browser.close();
|
|
623
804
|
}
|
|
624
805
|
return totalBrowsers * totalViewports * totalScreenshots;
|
|
625
806
|
});
|
|
@@ -629,16 +810,17 @@ var captureScreenshots_default = (ctx) => {
|
|
|
629
810
|
title: "Capturing screenshots",
|
|
630
811
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
631
812
|
try {
|
|
632
|
-
|
|
633
|
-
let totalScreenshots = yield captureScreenshots(ctx2,
|
|
813
|
+
ctx2.task = task;
|
|
814
|
+
let totalScreenshots = yield captureScreenshots(ctx2, ctx2.webStaticConfig);
|
|
634
815
|
task.title = "Screenshots captured successfully";
|
|
635
816
|
task.output = chalk__default.default.gray(`total screenshots: ${totalScreenshots}`);
|
|
636
817
|
} catch (error) {
|
|
637
|
-
|
|
818
|
+
task.output = chalk__default.default.gray(`${error.message}`);
|
|
638
819
|
throw new Error("Capturing screenshots failed");
|
|
639
820
|
}
|
|
640
821
|
}),
|
|
641
|
-
rendererOptions: { persistentOutput: true }
|
|
822
|
+
rendererOptions: { persistentOutput: true },
|
|
823
|
+
exitOnError: false
|
|
642
824
|
};
|
|
643
825
|
};
|
|
644
826
|
|
|
@@ -647,13 +829,25 @@ var command2 = new commander.Command();
|
|
|
647
829
|
command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").action(function(file, _, command3) {
|
|
648
830
|
return __async(this, null, function* () {
|
|
649
831
|
let ctx = ctx_default(command3.optsWithGlobals());
|
|
832
|
+
if (!fs__default.default.existsSync(file)) {
|
|
833
|
+
console.log(`Error: Web Static Config file ${file} not found.`);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
try {
|
|
837
|
+
ctx.webStaticConfig = JSON.parse(fs__default.default.readFileSync(file, "utf8"));
|
|
838
|
+
if (!validateWebStaticConfig(ctx.webStaticConfig))
|
|
839
|
+
throw new Error(validateWebStaticConfig.errors[0].message);
|
|
840
|
+
} catch (error) {
|
|
841
|
+
console.log(`[smartui] Error: Invalid Web Static Config; ${error.message}`);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
650
844
|
let tasks = new listr2.Listr(
|
|
651
845
|
[
|
|
652
846
|
auth_default(),
|
|
653
847
|
getGitInfo_default(),
|
|
654
848
|
createBuild_default(),
|
|
655
849
|
captureScreenshots_default(),
|
|
656
|
-
finalizeBuild_default(
|
|
850
|
+
finalizeBuild_default()
|
|
657
851
|
],
|
|
658
852
|
{
|
|
659
853
|
rendererOptions: {
|
|
@@ -667,11 +861,6 @@ command2.name("capture").description("Capture screenshots of static sites").argu
|
|
|
667
861
|
}
|
|
668
862
|
);
|
|
669
863
|
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
864
|
yield tasks.run(ctx);
|
|
676
865
|
} catch (error) {
|
|
677
866
|
console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lambdatest/smartui-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "A command line interface (CLI) to run SmartUI tests on LambdaTest",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/**/*"
|
|
@@ -17,9 +17,15 @@
|
|
|
17
17
|
"author": "LambdaTest <keys@lambdatest.com>",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"@playwright/browser-chromium": "^1.40.1",
|
|
21
|
+
"@playwright/browser-firefox": "^1.40.1",
|
|
22
|
+
"@playwright/browser-webkit": "^1.40.1",
|
|
23
|
+
"@playwright/test": "^1.40.1",
|
|
20
24
|
"@types/cross-spawn": "^6.0.4",
|
|
21
25
|
"@types/node": "^20.8.9",
|
|
22
26
|
"@types/which": "^3.0.2",
|
|
27
|
+
"ajv": "^8.12.0",
|
|
28
|
+
"ajv-errors": "^3.0.0",
|
|
23
29
|
"axios": "^1.6.0",
|
|
24
30
|
"chalk": "^4.1.2",
|
|
25
31
|
"commander": "^11.1.0",
|
|
@@ -27,7 +33,6 @@
|
|
|
27
33
|
"fastify": "^4.24.3",
|
|
28
34
|
"form-data": "^4.0.0",
|
|
29
35
|
"listr2": "^7.0.1",
|
|
30
|
-
"playwright": "^1.39.0",
|
|
31
36
|
"tsup": "^7.2.0",
|
|
32
37
|
"which": "^4.0.0",
|
|
33
38
|
"winston": "^3.10.0"
|