@lambdatest/smartui-cli 4.0.6 → 4.0.8
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 +680 -190
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
var commander = require('commander');
|
|
5
5
|
var which = require('which');
|
|
6
6
|
var listr2 = require('listr2');
|
|
7
|
-
var
|
|
7
|
+
var chalk6 = require('chalk');
|
|
8
8
|
var path2 = require('path');
|
|
9
9
|
var fastify = require('fastify');
|
|
10
10
|
var fs5 = require('fs');
|
|
@@ -21,7 +21,7 @@ var sharp = require('sharp');
|
|
|
21
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
22
|
|
|
23
23
|
var which__default = /*#__PURE__*/_interopDefault(which);
|
|
24
|
-
var
|
|
24
|
+
var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
|
|
25
25
|
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
26
26
|
var fastify__default = /*#__PURE__*/_interopDefault(fastify);
|
|
27
27
|
var fs5__default = /*#__PURE__*/_interopDefault(fs5);
|
|
@@ -187,6 +187,9 @@ var constants_default = {
|
|
|
187
187
|
MOBILE_OS_IOS: "ios",
|
|
188
188
|
MOBILE_ORIENTATION_PORTRAIT: "portrait",
|
|
189
189
|
MOBILE_ORIENTATION_LANDSCAPE: "landscape",
|
|
190
|
+
// build status
|
|
191
|
+
BUILD_COMPLETE: "completed",
|
|
192
|
+
BUILD_ERROR: "error",
|
|
190
193
|
// CI
|
|
191
194
|
GITHUB_API_HOST: "https://api.github.com",
|
|
192
195
|
// log file path
|
|
@@ -536,6 +539,10 @@ var ConfigSchema = {
|
|
|
536
539
|
errorMessage: "Invalid config; password is mandatory"
|
|
537
540
|
}
|
|
538
541
|
}
|
|
542
|
+
},
|
|
543
|
+
delayedUpload: {
|
|
544
|
+
type: "boolean",
|
|
545
|
+
errorMessage: "Invalid config; delayedUpload must be true/false"
|
|
539
546
|
}
|
|
540
547
|
},
|
|
541
548
|
anyOf: [
|
|
@@ -672,6 +679,64 @@ var SnapshotSchema = {
|
|
|
672
679
|
errorMessage: "Invalid snapshot options; selectDOM xpath array must have unique and non-empty items"
|
|
673
680
|
}
|
|
674
681
|
}
|
|
682
|
+
},
|
|
683
|
+
web: {
|
|
684
|
+
type: "object",
|
|
685
|
+
properties: {
|
|
686
|
+
browsers: {
|
|
687
|
+
type: "array",
|
|
688
|
+
items: {
|
|
689
|
+
type: "string",
|
|
690
|
+
enum: [constants_default.CHROME, constants_default.FIREFOX, constants_default.SAFARI, constants_default.EDGE],
|
|
691
|
+
minLength: 1
|
|
692
|
+
},
|
|
693
|
+
uniqueItems: true,
|
|
694
|
+
errorMessage: `Invalid snapshot options; allowed browsers - ${constants_default.CHROME}, ${constants_default.FIREFOX}, ${constants_default.SAFARI}, ${constants_default.EDGE}`
|
|
695
|
+
},
|
|
696
|
+
viewports: {
|
|
697
|
+
type: "array",
|
|
698
|
+
items: {
|
|
699
|
+
type: "array",
|
|
700
|
+
items: {
|
|
701
|
+
type: "number",
|
|
702
|
+
minimum: 1
|
|
703
|
+
},
|
|
704
|
+
minItems: 1,
|
|
705
|
+
maxItems: 2,
|
|
706
|
+
errorMessage: "Invalid snapshot options; each viewport array must contain either a single width or a width and height tuple with positive values."
|
|
707
|
+
},
|
|
708
|
+
uniqueItems: true,
|
|
709
|
+
errorMessage: "Invalid snapshot options; viewports must be an array of unique arrays."
|
|
710
|
+
}
|
|
711
|
+
},
|
|
712
|
+
required: ["viewports"],
|
|
713
|
+
errorMessage: "Invalid snapshot options; web must include viewports property."
|
|
714
|
+
},
|
|
715
|
+
mobile: {
|
|
716
|
+
type: "object",
|
|
717
|
+
properties: {
|
|
718
|
+
devices: {
|
|
719
|
+
type: "array",
|
|
720
|
+
items: {
|
|
721
|
+
type: "string",
|
|
722
|
+
enum: Object.keys(constants_default.SUPPORTED_MOBILE_DEVICES),
|
|
723
|
+
minLength: 1
|
|
724
|
+
},
|
|
725
|
+
uniqueItems: true,
|
|
726
|
+
errorMessage: "Invalid snapshot options; devices must be an array of unique supported mobile devices."
|
|
727
|
+
},
|
|
728
|
+
fullPage: {
|
|
729
|
+
type: "boolean",
|
|
730
|
+
errorMessage: "Invalid snapshot options; fullPage must be a boolean."
|
|
731
|
+
},
|
|
732
|
+
orientation: {
|
|
733
|
+
type: "string",
|
|
734
|
+
enum: [constants_default.MOBILE_ORIENTATION_PORTRAIT, constants_default.MOBILE_ORIENTATION_LANDSCAPE],
|
|
735
|
+
errorMessage: "Invalid snapshot options; orientation must be either 'portrait' or 'landscape'."
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
required: ["devices"],
|
|
739
|
+
errorMessage: "Invalid snapshot options; mobile must include devices property."
|
|
675
740
|
}
|
|
676
741
|
},
|
|
677
742
|
additionalProperties: false
|
|
@@ -826,7 +891,7 @@ var logger = winston.createLogger({
|
|
|
826
891
|
let message = typeof info.message === "object" ? JSON.stringify(info.message).trim() : info.message.trim();
|
|
827
892
|
switch (info.level) {
|
|
828
893
|
case "warn":
|
|
829
|
-
message =
|
|
894
|
+
message = chalk6__default.default.yellow(message);
|
|
830
895
|
break;
|
|
831
896
|
}
|
|
832
897
|
return info.level === "info" ? message : `[${contextString}:${info.level}] ` + message;
|
|
@@ -853,11 +918,11 @@ var startServer_default = (ctx) => {
|
|
|
853
918
|
updateLogContext({ task: "startServer" });
|
|
854
919
|
try {
|
|
855
920
|
ctx2.server = yield server_default(ctx2);
|
|
856
|
-
task.output =
|
|
921
|
+
task.output = chalk6__default.default.gray(`listening on port ${(_a = ctx2.server.addresses()[0]) == null ? void 0 : _a.port}`);
|
|
857
922
|
task.title = "SmartUI started";
|
|
858
923
|
} catch (error) {
|
|
859
924
|
ctx2.log.debug(error);
|
|
860
|
-
task.output =
|
|
925
|
+
task.output = chalk6__default.default.gray(error.message);
|
|
861
926
|
throw new Error("SmartUI server setup failed");
|
|
862
927
|
}
|
|
863
928
|
}),
|
|
@@ -871,11 +936,11 @@ var auth_default = (ctx) => {
|
|
|
871
936
|
updateLogContext({ task: "auth" });
|
|
872
937
|
try {
|
|
873
938
|
yield ctx2.client.auth(ctx2.log);
|
|
874
|
-
task.output =
|
|
939
|
+
task.output = chalk6__default.default.gray(`using project token '******#${ctx2.env.PROJECT_TOKEN.split("#").pop()}'`);
|
|
875
940
|
task.title = "Authenticated with SmartUI";
|
|
876
941
|
} catch (error) {
|
|
877
942
|
ctx2.log.debug(error);
|
|
878
|
-
task.output =
|
|
943
|
+
task.output = chalk6__default.default.gray(error.message);
|
|
879
944
|
throw new Error("Authentication failed");
|
|
880
945
|
}
|
|
881
946
|
}),
|
|
@@ -884,7 +949,7 @@ var auth_default = (ctx) => {
|
|
|
884
949
|
};
|
|
885
950
|
|
|
886
951
|
// package.json
|
|
887
|
-
var version = "4.0.
|
|
952
|
+
var version = "4.0.8";
|
|
888
953
|
var package_default = {
|
|
889
954
|
name: "@lambdatest/smartui-cli",
|
|
890
955
|
version,
|
|
@@ -985,6 +1050,13 @@ var httpClient = class {
|
|
|
985
1050
|
}
|
|
986
1051
|
}, log2);
|
|
987
1052
|
}
|
|
1053
|
+
getScreenshotData(buildId, baseline, log2) {
|
|
1054
|
+
return this.request({
|
|
1055
|
+
url: "/screenshot",
|
|
1056
|
+
method: "GET",
|
|
1057
|
+
params: { buildId, baseline }
|
|
1058
|
+
}, log2);
|
|
1059
|
+
}
|
|
988
1060
|
finalizeBuild(buildId, totalSnapshots, log2) {
|
|
989
1061
|
let params = { buildId };
|
|
990
1062
|
if (totalSnapshots > -1)
|
|
@@ -1096,7 +1168,7 @@ var httpClient = class {
|
|
|
1096
1168
|
}
|
|
1097
1169
|
};
|
|
1098
1170
|
var ctx_default = (options) => {
|
|
1099
|
-
var _a, _b, _c, _d, _e, _f;
|
|
1171
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1100
1172
|
let env = env_default();
|
|
1101
1173
|
let webConfig;
|
|
1102
1174
|
let mobileConfig;
|
|
@@ -1107,6 +1179,8 @@ var ctx_default = (options) => {
|
|
|
1107
1179
|
let extensionFiles;
|
|
1108
1180
|
let ignoreStripExtension;
|
|
1109
1181
|
let ignoreFilePattern;
|
|
1182
|
+
let fetchResultObj;
|
|
1183
|
+
let fetchResultsFileObj;
|
|
1110
1184
|
try {
|
|
1111
1185
|
if (options.config) {
|
|
1112
1186
|
config = JSON.parse(fs5__default.default.readFileSync(options.config, "utf-8"));
|
|
@@ -1126,6 +1200,17 @@ var ctx_default = (options) => {
|
|
|
1126
1200
|
extensionFiles = options.files || ["png", "jpeg", "jpg"];
|
|
1127
1201
|
ignoreStripExtension = options.removeExtensions || false;
|
|
1128
1202
|
ignoreFilePattern = options.ignoreDir || [];
|
|
1203
|
+
if (options.fetchResults) {
|
|
1204
|
+
if (options.fetchResults !== true && !options.fetchResults.endsWith(".json")) {
|
|
1205
|
+
console.error("Error: The file extension for --fetch-results must be .json");
|
|
1206
|
+
process.exit(1);
|
|
1207
|
+
}
|
|
1208
|
+
fetchResultObj = true;
|
|
1209
|
+
fetchResultsFileObj = options.fetchResults === true ? "results.json" : options.fetchResults;
|
|
1210
|
+
} else {
|
|
1211
|
+
fetchResultObj = false;
|
|
1212
|
+
fetchResultsFileObj = "";
|
|
1213
|
+
}
|
|
1129
1214
|
} catch (error) {
|
|
1130
1215
|
console.log(`[smartui] Error: ${error.message}`);
|
|
1131
1216
|
process.exit();
|
|
@@ -1159,7 +1244,8 @@ var ctx_default = (options) => {
|
|
|
1159
1244
|
scrollTime: config.scrollTime || constants_default.DEFAULT_SCROLL_TIME,
|
|
1160
1245
|
allowedHostnames: config.allowedHostnames || [],
|
|
1161
1246
|
basicAuthorization: basicAuthObj,
|
|
1162
|
-
smartIgnore: (_f = config.smartIgnore) != null ? _f : false
|
|
1247
|
+
smartIgnore: (_f = config.smartIgnore) != null ? _f : false,
|
|
1248
|
+
delayedUpload: (_g = config.delayedUpload) != null ? _g : false
|
|
1163
1249
|
},
|
|
1164
1250
|
uploadFilePath: "",
|
|
1165
1251
|
webStaticConfig: [],
|
|
@@ -1185,7 +1271,9 @@ var ctx_default = (options) => {
|
|
|
1185
1271
|
ignoreResolutions: resolutionOff,
|
|
1186
1272
|
fileExtension: extensionFiles,
|
|
1187
1273
|
stripExtension: ignoreStripExtension,
|
|
1188
|
-
ignorePattern: ignoreFilePattern
|
|
1274
|
+
ignorePattern: ignoreFilePattern,
|
|
1275
|
+
fetchResults: fetchResultObj,
|
|
1276
|
+
fetchResultsFileName: fetchResultsFileObj
|
|
1189
1277
|
},
|
|
1190
1278
|
cliVersion: version,
|
|
1191
1279
|
totalSnapshots: -1
|
|
@@ -1252,11 +1340,11 @@ var getGitInfo_default = (ctx) => {
|
|
|
1252
1340
|
}
|
|
1253
1341
|
try {
|
|
1254
1342
|
ctx2.git = git_default(ctx2);
|
|
1255
|
-
task.output =
|
|
1343
|
+
task.output = chalk6__default.default.gray(`branch: ${ctx2.git.branch}, commit: ${ctx2.git.commitId}, author: ${ctx2.git.commitAuthor}`);
|
|
1256
1344
|
task.title = "Fetched git information";
|
|
1257
1345
|
} catch (error) {
|
|
1258
1346
|
ctx2.log.debug(error);
|
|
1259
|
-
task.output =
|
|
1347
|
+
task.output = chalk6__default.default.gray(`${error.message}`);
|
|
1260
1348
|
throw new Error("Error fetching git repo details");
|
|
1261
1349
|
}
|
|
1262
1350
|
}),
|
|
@@ -1276,123 +1364,18 @@ var createBuild_default = (ctx) => {
|
|
|
1276
1364
|
url: resp.data.buildURL,
|
|
1277
1365
|
baseline: resp.data.baseline
|
|
1278
1366
|
};
|
|
1279
|
-
task.output =
|
|
1367
|
+
task.output = chalk6__default.default.gray(`build id: ${resp.data.buildId}`);
|
|
1280
1368
|
task.title = "SmartUI build created";
|
|
1281
1369
|
} catch (error) {
|
|
1282
1370
|
ctx2.log.debug(error);
|
|
1283
|
-
task.output =
|
|
1371
|
+
task.output = chalk6__default.default.gray(error.message);
|
|
1284
1372
|
throw new Error("SmartUI build creation failed");
|
|
1285
1373
|
}
|
|
1286
1374
|
}),
|
|
1287
1375
|
rendererOptions: { persistentOutput: true }
|
|
1288
1376
|
};
|
|
1289
1377
|
};
|
|
1290
|
-
var
|
|
1291
|
-
var _a;
|
|
1292
|
-
return {
|
|
1293
|
-
title: `Executing '${(_a = ctx.args.execCommand) == null ? void 0 : _a.join(" ")}'`,
|
|
1294
|
-
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1295
|
-
updateLogContext({ task: "exec" });
|
|
1296
|
-
return new Promise((resolve, reject) => {
|
|
1297
|
-
var _a2, _b, _c;
|
|
1298
|
-
const childProcess = spawn__default.default(ctx2.args.execCommand[0], (_a2 = ctx2.args.execCommand) == null ? void 0 : _a2.slice(1));
|
|
1299
|
-
let totalOutput = "";
|
|
1300
|
-
const output = listr2.createWritable((chunk) => {
|
|
1301
|
-
totalOutput += chunk;
|
|
1302
|
-
task.output = chalk7__default.default.gray(totalOutput);
|
|
1303
|
-
});
|
|
1304
|
-
(_b = childProcess.stdout) == null ? void 0 : _b.pipe(output);
|
|
1305
|
-
(_c = childProcess.stderr) == null ? void 0 : _c.pipe(output);
|
|
1306
|
-
childProcess.on("error", (error) => {
|
|
1307
|
-
var _a3;
|
|
1308
|
-
task.output = chalk7__default.default.gray(`error: ${error.message}`);
|
|
1309
|
-
throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' failed`);
|
|
1310
|
-
});
|
|
1311
|
-
childProcess.on("close", (code, signal) => __async(void 0, null, function* () {
|
|
1312
|
-
var _a3;
|
|
1313
|
-
if (code !== null) {
|
|
1314
|
-
task.title = `Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' completed; exited with code ${code}`;
|
|
1315
|
-
} else if (signal !== null) {
|
|
1316
|
-
throw new Error(`Child process killed with signal ${signal}`);
|
|
1317
|
-
}
|
|
1318
|
-
resolve();
|
|
1319
|
-
}));
|
|
1320
|
-
});
|
|
1321
|
-
}),
|
|
1322
|
-
rendererOptions: { persistentOutput: true },
|
|
1323
|
-
exitOnError: false
|
|
1324
|
-
};
|
|
1325
|
-
};
|
|
1326
|
-
var processSnapshot_default = (ctx) => {
|
|
1327
|
-
return {
|
|
1328
|
-
title: `Processing snapshots`,
|
|
1329
|
-
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1330
|
-
var _a;
|
|
1331
|
-
try {
|
|
1332
|
-
yield new Promise((resolve) => {
|
|
1333
|
-
let output2 = "";
|
|
1334
|
-
const intervalId = setInterval(() => {
|
|
1335
|
-
var _a2, _b, _c;
|
|
1336
|
-
if (((_a2 = ctx2.snapshotQueue) == null ? void 0 : _a2.isEmpty()) && !((_b = ctx2.snapshotQueue) == null ? void 0 : _b.isProcessing())) {
|
|
1337
|
-
clearInterval(intervalId);
|
|
1338
|
-
resolve();
|
|
1339
|
-
} else {
|
|
1340
|
-
task.title = `Processing snapshot ${(_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessingSnapshot()}`;
|
|
1341
|
-
}
|
|
1342
|
-
}, 500);
|
|
1343
|
-
});
|
|
1344
|
-
let output = "";
|
|
1345
|
-
for (let snapshot of (_a = ctx2.snapshotQueue) == null ? void 0 : _a.getProcessedSnapshots()) {
|
|
1346
|
-
if (snapshot.error)
|
|
1347
|
-
output += `${chalk7__default.default.red("\u2717")} ${chalk7__default.default.gray(`${snapshot.name}
|
|
1348
|
-
[error] ${snapshot.error}`)}
|
|
1349
|
-
`;
|
|
1350
|
-
else
|
|
1351
|
-
output += `${chalk7__default.default.green("\u2713")} ${chalk7__default.default.gray(snapshot.name)}
|
|
1352
|
-
${snapshot.warnings.length ? chalk7__default.default.gray(`[warning] ${snapshot.warnings.join("\n[warning] ")}
|
|
1353
|
-
`) : ""}`;
|
|
1354
|
-
}
|
|
1355
|
-
task.output = output;
|
|
1356
|
-
task.title = "Processed snapshots";
|
|
1357
|
-
} catch (error) {
|
|
1358
|
-
ctx2.log.debug(error);
|
|
1359
|
-
task.output = chalk7__default.default.gray(error.message);
|
|
1360
|
-
throw new Error("Processing of snapshots failed");
|
|
1361
|
-
}
|
|
1362
|
-
}),
|
|
1363
|
-
rendererOptions: { persistentOutput: true }
|
|
1364
|
-
};
|
|
1365
|
-
};
|
|
1366
|
-
var finalizeBuild_default = (ctx) => {
|
|
1367
|
-
return {
|
|
1368
|
-
title: `Finalizing build`,
|
|
1369
|
-
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1370
|
-
var _a, _b;
|
|
1371
|
-
updateLogContext({ task: "finalizeBuild" });
|
|
1372
|
-
try {
|
|
1373
|
-
yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
|
|
1374
|
-
task.output = chalk7__default.default.gray(`build url: ${ctx2.build.url}`);
|
|
1375
|
-
task.title = "Finalized build";
|
|
1376
|
-
} catch (error) {
|
|
1377
|
-
ctx2.log.debug(error);
|
|
1378
|
-
task.output = chalk7__default.default.gray(error.message);
|
|
1379
|
-
throw new Error("Finalize build failed");
|
|
1380
|
-
}
|
|
1381
|
-
try {
|
|
1382
|
-
yield (_a = ctx2.browser) == null ? void 0 : _a.close();
|
|
1383
|
-
ctx2.log.debug(`Closed browser`);
|
|
1384
|
-
yield (_b = ctx2.server) == null ? void 0 : _b.close();
|
|
1385
|
-
ctx2.log.debug(`Closed server`);
|
|
1386
|
-
let resp = yield ctx2.client.getS3PreSignedURL(ctx2);
|
|
1387
|
-
yield ctx2.client.uploadLogs(ctx2, resp.data.url);
|
|
1388
|
-
fs5.unlinkSync(constants_default.LOG_FILE_PATH);
|
|
1389
|
-
} catch (error) {
|
|
1390
|
-
ctx2.log.debug(error);
|
|
1391
|
-
}
|
|
1392
|
-
}),
|
|
1393
|
-
rendererOptions: { persistentOutput: true }
|
|
1394
|
-
};
|
|
1395
|
-
};
|
|
1378
|
+
var isPollingActive = false;
|
|
1396
1379
|
function delDir(dir) {
|
|
1397
1380
|
if (fs5__default.default.existsSync(dir)) {
|
|
1398
1381
|
fs5__default.default.rmSync(dir, { recursive: true });
|
|
@@ -1478,6 +1461,28 @@ function getWebRenderViewports(ctx) {
|
|
|
1478
1461
|
}
|
|
1479
1462
|
return webRenderViewports;
|
|
1480
1463
|
}
|
|
1464
|
+
function getWebRenderViewportsForOptions(options) {
|
|
1465
|
+
let webRenderViewports = [];
|
|
1466
|
+
if (options.web && Array.isArray(options.web.viewports)) {
|
|
1467
|
+
for (const viewport of options.web.viewports) {
|
|
1468
|
+
if (Array.isArray(viewport) && viewport.length > 0) {
|
|
1469
|
+
let viewportObj = {
|
|
1470
|
+
width: viewport[0]
|
|
1471
|
+
};
|
|
1472
|
+
if (viewport.length > 1) {
|
|
1473
|
+
viewportObj.height = viewport[1];
|
|
1474
|
+
}
|
|
1475
|
+
webRenderViewports.push({
|
|
1476
|
+
viewport: viewportObj,
|
|
1477
|
+
viewportString: `${viewport[0]}${viewport[1] ? "x" + viewport[1] : ""}`,
|
|
1478
|
+
fullPage: viewport.length === 1,
|
|
1479
|
+
device: false
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
return webRenderViewports;
|
|
1485
|
+
}
|
|
1481
1486
|
function getMobileRenderViewports(ctx) {
|
|
1482
1487
|
var _a;
|
|
1483
1488
|
let mobileRenderViewports = {};
|
|
@@ -1499,6 +1504,34 @@ function getMobileRenderViewports(ctx) {
|
|
|
1499
1504
|
}
|
|
1500
1505
|
return mobileRenderViewports;
|
|
1501
1506
|
}
|
|
1507
|
+
function getMobileRenderViewportsForOptions(options) {
|
|
1508
|
+
var _a;
|
|
1509
|
+
let mobileRenderViewports = {};
|
|
1510
|
+
mobileRenderViewports[constants_default.MOBILE_OS_IOS] = [];
|
|
1511
|
+
mobileRenderViewports[constants_default.MOBILE_OS_ANDROID] = [];
|
|
1512
|
+
if (options.mobile) {
|
|
1513
|
+
for (const device of options.mobile.devices) {
|
|
1514
|
+
let os = constants_default.SUPPORTED_MOBILE_DEVICES[device].os;
|
|
1515
|
+
let { width, height } = constants_default.SUPPORTED_MOBILE_DEVICES[device].viewport;
|
|
1516
|
+
let orientation = options.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
1517
|
+
let portrait = orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
1518
|
+
let fullPage;
|
|
1519
|
+
if (options.mobile.fullPage === void 0 || options.mobile.fullPage) {
|
|
1520
|
+
fullPage = true;
|
|
1521
|
+
} else {
|
|
1522
|
+
fullPage = false;
|
|
1523
|
+
}
|
|
1524
|
+
(_a = mobileRenderViewports[os]) == null ? void 0 : _a.push({
|
|
1525
|
+
viewport: { width: portrait ? width : height, height: portrait ? height : width },
|
|
1526
|
+
viewportString: `${device} (${orientation})`,
|
|
1527
|
+
fullPage,
|
|
1528
|
+
device: true,
|
|
1529
|
+
os
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
return mobileRenderViewports;
|
|
1534
|
+
}
|
|
1502
1535
|
function getRenderViewports(ctx) {
|
|
1503
1536
|
let mobileRenderViewports = getMobileRenderViewports(ctx);
|
|
1504
1537
|
let webRenderViewports = getWebRenderViewports(ctx);
|
|
@@ -1508,69 +1541,211 @@ function getRenderViewports(ctx) {
|
|
|
1508
1541
|
...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
|
|
1509
1542
|
];
|
|
1510
1543
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
if (!this.processing) {
|
|
1527
|
-
this.processing = true;
|
|
1528
|
-
this.processNext();
|
|
1529
|
-
}
|
|
1544
|
+
function getRenderViewportsForOptions(options) {
|
|
1545
|
+
let mobileRenderViewports = getMobileRenderViewportsForOptions(options);
|
|
1546
|
+
let webRenderViewports = getWebRenderViewportsForOptions(options);
|
|
1547
|
+
return [
|
|
1548
|
+
...webRenderViewports,
|
|
1549
|
+
...mobileRenderViewports[constants_default.MOBILE_OS_IOS],
|
|
1550
|
+
...mobileRenderViewports[constants_default.MOBILE_OS_ANDROID]
|
|
1551
|
+
];
|
|
1552
|
+
}
|
|
1553
|
+
process.on("SIGINT", () => {
|
|
1554
|
+
if (isPollingActive) {
|
|
1555
|
+
console.log("Fetching results interrupted. Exiting...");
|
|
1556
|
+
isPollingActive = false;
|
|
1557
|
+
} else {
|
|
1558
|
+
console.log("\nExiting gracefully...");
|
|
1530
1559
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1560
|
+
process.exit(0);
|
|
1561
|
+
});
|
|
1562
|
+
function startPolling(ctx, task) {
|
|
1563
|
+
return __async(this, null, function* () {
|
|
1564
|
+
ctx.log.info("Fetching results in progress....");
|
|
1565
|
+
isPollingActive = true;
|
|
1566
|
+
const intervalId = setInterval(() => __async(this, null, function* () {
|
|
1567
|
+
if (!isPollingActive) {
|
|
1568
|
+
clearInterval(intervalId);
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
try {
|
|
1572
|
+
const resp = yield ctx.client.getScreenshotData(ctx.build.id, ctx.build.baseline, ctx.log);
|
|
1573
|
+
if (!resp.build) {
|
|
1574
|
+
ctx.log.info("Error: Build data is null.");
|
|
1575
|
+
clearInterval(intervalId);
|
|
1576
|
+
isPollingActive = false;
|
|
1544
1577
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1578
|
+
fs5__default.default.writeFileSync(ctx.options.fetchResultsFileName, JSON.stringify(resp, null, 2));
|
|
1579
|
+
ctx.log.debug(`Updated results in ${ctx.options.fetchResultsFileName}`);
|
|
1580
|
+
if (resp.build.build_status_ind === constants_default.BUILD_COMPLETE || resp.build.build_status_ind === constants_default.BUILD_ERROR) {
|
|
1581
|
+
clearInterval(intervalId);
|
|
1582
|
+
ctx.log.info(`Fetching results completed. Final results written to ${ctx.options.fetchResultsFileName}`);
|
|
1583
|
+
isPollingActive = false;
|
|
1584
|
+
let totalScreenshotsWithMismatches = 0;
|
|
1585
|
+
let totalVariantsWithMismatches = 0;
|
|
1586
|
+
const totalScreenshots = Object.keys(resp.screenshots || {}).length;
|
|
1587
|
+
let totalVariants = 0;
|
|
1588
|
+
for (const [screenshot, variants] of Object.entries(resp.screenshots || {})) {
|
|
1589
|
+
let screenshotHasMismatch = false;
|
|
1590
|
+
let variantMismatchCount = 0;
|
|
1591
|
+
totalVariants += variants.length;
|
|
1592
|
+
for (const variant of variants) {
|
|
1593
|
+
if (variant.mismatch_percentage > 0) {
|
|
1594
|
+
screenshotHasMismatch = true;
|
|
1595
|
+
variantMismatchCount++;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (screenshotHasMismatch) {
|
|
1599
|
+
totalScreenshotsWithMismatches++;
|
|
1600
|
+
totalVariantsWithMismatches += variantMismatchCount;
|
|
1550
1601
|
}
|
|
1551
|
-
yield context.close();
|
|
1552
|
-
this.ctx.log.debug(`Closed browser context for snapshot ${snapshot.name}`);
|
|
1553
1602
|
}
|
|
1603
|
+
ctx.log.info(
|
|
1604
|
+
chalk6__default.default.green.bold(
|
|
1605
|
+
`
|
|
1606
|
+
Summary of Mismatches:
|
|
1607
|
+
${chalk6__default.default.yellow("Total Variants with Mismatches:")} ${chalk6__default.default.white(totalVariantsWithMismatches)} out of ${chalk6__default.default.white(totalVariants)}
|
|
1608
|
+
${chalk6__default.default.yellow("Total Screenshots with Mismatches:")} ${chalk6__default.default.white(totalScreenshotsWithMismatches)} out of ${chalk6__default.default.white(totalScreenshots)}
|
|
1609
|
+
${chalk6__default.default.yellow("Branch Name:")} ${chalk6__default.default.white(resp.build.branch)}
|
|
1610
|
+
${chalk6__default.default.yellow("Project Name:")} ${chalk6__default.default.white(resp.project.name)}
|
|
1611
|
+
${chalk6__default.default.yellow("Build ID:")} ${chalk6__default.default.white(resp.build.build_id)}
|
|
1612
|
+
`
|
|
1613
|
+
)
|
|
1614
|
+
);
|
|
1554
1615
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1616
|
+
} catch (error) {
|
|
1617
|
+
if (error.message.includes("ENOTFOUND")) {
|
|
1618
|
+
ctx.log.error("Error: Network error occurred while fetching build results. Please check your connection and try again.");
|
|
1619
|
+
clearInterval(intervalId);
|
|
1620
|
+
} else {
|
|
1621
|
+
ctx.log.error(`Error fetching screenshot data: ${error.message}`);
|
|
1622
|
+
}
|
|
1623
|
+
clearInterval(intervalId);
|
|
1624
|
+
isPollingActive = false;
|
|
1558
1625
|
}
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1626
|
+
}), 5e3);
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
// src/tasks/exec.ts
|
|
1631
|
+
var exec_default = (ctx) => {
|
|
1632
|
+
var _a;
|
|
1633
|
+
return {
|
|
1634
|
+
title: `Executing '${(_a = ctx.args.execCommand) == null ? void 0 : _a.join(" ")}'`,
|
|
1635
|
+
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1636
|
+
if (ctx2.options.fetchResults) {
|
|
1637
|
+
startPolling(ctx2);
|
|
1638
|
+
}
|
|
1639
|
+
updateLogContext({ task: "exec" });
|
|
1640
|
+
return new Promise((resolve, reject) => {
|
|
1641
|
+
var _a2, _b, _c;
|
|
1642
|
+
const childProcess = spawn__default.default(ctx2.args.execCommand[0], (_a2 = ctx2.args.execCommand) == null ? void 0 : _a2.slice(1));
|
|
1643
|
+
let totalOutput = "";
|
|
1644
|
+
const output = listr2.createWritable((chunk) => {
|
|
1645
|
+
totalOutput += chunk;
|
|
1646
|
+
task.output = chalk6__default.default.gray(totalOutput);
|
|
1647
|
+
});
|
|
1648
|
+
(_b = childProcess.stdout) == null ? void 0 : _b.pipe(output);
|
|
1649
|
+
(_c = childProcess.stderr) == null ? void 0 : _c.pipe(output);
|
|
1650
|
+
childProcess.on("error", (error) => {
|
|
1651
|
+
var _a3;
|
|
1652
|
+
task.output = chalk6__default.default.gray(`error: ${error.message}`);
|
|
1653
|
+
throw new Error(`Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' failed`);
|
|
1654
|
+
});
|
|
1655
|
+
childProcess.on("close", (code, signal) => __async(void 0, null, function* () {
|
|
1656
|
+
var _a3;
|
|
1657
|
+
if (code !== null) {
|
|
1658
|
+
task.title = `Execution of '${(_a3 = ctx2.args.execCommand) == null ? void 0 : _a3.join(" ")}' completed; exited with code ${code}`;
|
|
1659
|
+
} else if (signal !== null) {
|
|
1660
|
+
throw new Error(`Child process killed with signal ${signal}`);
|
|
1661
|
+
}
|
|
1662
|
+
resolve();
|
|
1663
|
+
}));
|
|
1664
|
+
});
|
|
1665
|
+
}),
|
|
1666
|
+
rendererOptions: { persistentOutput: true },
|
|
1667
|
+
exitOnError: false
|
|
1668
|
+
};
|
|
1669
|
+
};
|
|
1670
|
+
var processSnapshot_default = (ctx) => {
|
|
1671
|
+
return {
|
|
1672
|
+
title: `Processing snapshots`,
|
|
1673
|
+
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1674
|
+
var _a, _b;
|
|
1675
|
+
try {
|
|
1676
|
+
if (ctx2.config.delayedUpload) {
|
|
1677
|
+
ctx2.log.debug("started after processing because of delayedUpload");
|
|
1678
|
+
(_a = ctx2.snapshotQueue) == null ? void 0 : _a.startProcessingfunc();
|
|
1679
|
+
}
|
|
1680
|
+
yield new Promise((resolve) => {
|
|
1681
|
+
let output2 = "";
|
|
1682
|
+
const intervalId = setInterval(() => {
|
|
1683
|
+
var _a2, _b2, _c;
|
|
1684
|
+
if (((_a2 = ctx2.snapshotQueue) == null ? void 0 : _a2.isEmpty()) && !((_b2 = ctx2.snapshotQueue) == null ? void 0 : _b2.isProcessing())) {
|
|
1685
|
+
clearInterval(intervalId);
|
|
1686
|
+
resolve();
|
|
1687
|
+
} else {
|
|
1688
|
+
task.title = `Processing snapshot ${(_c = ctx2.snapshotQueue) == null ? void 0 : _c.getProcessingSnapshot()}`;
|
|
1689
|
+
}
|
|
1690
|
+
}, 500);
|
|
1691
|
+
});
|
|
1692
|
+
let output = "";
|
|
1693
|
+
for (let snapshot of (_b = ctx2.snapshotQueue) == null ? void 0 : _b.getProcessedSnapshots()) {
|
|
1694
|
+
if (snapshot.error)
|
|
1695
|
+
output += `${chalk6__default.default.red("\u2717")} ${chalk6__default.default.gray(`${snapshot.name}
|
|
1696
|
+
[error] ${snapshot.error}`)}
|
|
1697
|
+
`;
|
|
1698
|
+
else
|
|
1699
|
+
output += `${chalk6__default.default.green("\u2713")} ${chalk6__default.default.gray(snapshot.name)}
|
|
1700
|
+
${snapshot.warnings.length ? chalk6__default.default.gray(`[warning] ${snapshot.warnings.join("\n[warning] ")}
|
|
1701
|
+
`) : ""}`;
|
|
1702
|
+
}
|
|
1703
|
+
task.output = output;
|
|
1704
|
+
task.title = "Processed snapshots";
|
|
1705
|
+
} catch (error) {
|
|
1706
|
+
ctx2.log.debug(error);
|
|
1707
|
+
task.output = chalk6__default.default.gray(error.message);
|
|
1708
|
+
throw new Error("Processing of snapshots failed");
|
|
1709
|
+
}
|
|
1710
|
+
}),
|
|
1711
|
+
rendererOptions: { persistentOutput: true }
|
|
1712
|
+
};
|
|
1713
|
+
};
|
|
1714
|
+
var finalizeBuild_default = (ctx) => {
|
|
1715
|
+
return {
|
|
1716
|
+
title: `Finalizing build`,
|
|
1717
|
+
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
1718
|
+
var _a, _b;
|
|
1719
|
+
updateLogContext({ task: "finalizeBuild" });
|
|
1720
|
+
try {
|
|
1721
|
+
yield ctx2.client.finalizeBuild(ctx2.build.id, ctx2.totalSnapshots, ctx2.log);
|
|
1722
|
+
task.output = chalk6__default.default.gray(`build url: ${ctx2.build.url}`);
|
|
1723
|
+
task.title = "Finalized build";
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
ctx2.log.debug(error);
|
|
1726
|
+
task.output = chalk6__default.default.gray(error.message);
|
|
1727
|
+
throw new Error("Finalize build failed");
|
|
1728
|
+
}
|
|
1729
|
+
try {
|
|
1730
|
+
yield (_a = ctx2.browser) == null ? void 0 : _a.close();
|
|
1731
|
+
ctx2.log.debug(`Closed browser`);
|
|
1732
|
+
yield (_b = ctx2.server) == null ? void 0 : _b.close();
|
|
1733
|
+
ctx2.log.debug(`Closed server`);
|
|
1734
|
+
let resp = yield ctx2.client.getS3PreSignedURL(ctx2);
|
|
1735
|
+
yield ctx2.client.uploadLogs(ctx2, resp.data.url);
|
|
1736
|
+
fs5.unlinkSync(constants_default.LOG_FILE_PATH);
|
|
1737
|
+
} catch (error) {
|
|
1738
|
+
ctx2.log.debug(error);
|
|
1739
|
+
}
|
|
1740
|
+
}),
|
|
1741
|
+
rendererOptions: { persistentOutput: true }
|
|
1742
|
+
};
|
|
1573
1743
|
};
|
|
1744
|
+
var MAX_RESOURCE_SIZE = 15 * 1024 ** 2;
|
|
1745
|
+
var ALLOWED_RESOURCES = ["document", "stylesheet", "image", "media", "font", "other"];
|
|
1746
|
+
var ALLOWED_STATUSES = [200, 201];
|
|
1747
|
+
var REQUEST_TIMEOUT = 1e4;
|
|
1748
|
+
var MIN_VIEWPORT_HEIGHT = 1080;
|
|
1574
1749
|
function processSnapshot(snapshot, ctx) {
|
|
1575
1750
|
return __async(this, null, function* () {
|
|
1576
1751
|
var _a;
|
|
@@ -1719,6 +1894,33 @@ function processSnapshot(snapshot, ctx) {
|
|
|
1719
1894
|
return true;
|
|
1720
1895
|
return false;
|
|
1721
1896
|
};
|
|
1897
|
+
if (options.web && Object.keys(options.web).length) {
|
|
1898
|
+
processedOptions.web = {};
|
|
1899
|
+
if (options.web.viewports && options.web.viewports.length > 0) {
|
|
1900
|
+
processedOptions.web.viewports = options.web.viewports.filter(
|
|
1901
|
+
(viewport) => Array.isArray(viewport) && viewport.length > 0
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
if (options.web.browsers && options.web.browsers.length > 0) {
|
|
1905
|
+
processedOptions.web.browsers = options.web.browsers;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
if (options.mobile && Object.keys(options.mobile).length) {
|
|
1909
|
+
processedOptions.mobile = {};
|
|
1910
|
+
if (options.mobile.devices && options.mobile.devices.length > 0) {
|
|
1911
|
+
processedOptions.mobile.devices = options.mobile.devices;
|
|
1912
|
+
}
|
|
1913
|
+
if (options.mobile.hasOwnProperty("fullPage") && typeof options.mobile.fullPage === "boolean") {
|
|
1914
|
+
processedOptions.mobile.fullPage = options.mobile.fullPage;
|
|
1915
|
+
} else {
|
|
1916
|
+
processedOptions.mobile.fullPage = true;
|
|
1917
|
+
}
|
|
1918
|
+
if (options.mobile.hasOwnProperty("orientation") && (options.mobile.orientation === constants_default.MOBILE_ORIENTATION_PORTRAIT || options.mobile.orientation === constants_default.MOBILE_ORIENTATION_LANDSCAPE)) {
|
|
1919
|
+
processedOptions.mobile.orientation = options.mobile.orientation;
|
|
1920
|
+
} else {
|
|
1921
|
+
processedOptions.mobile.orientation = constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1722
1924
|
if (options.element && Object.keys(options.element).length) {
|
|
1723
1925
|
if (options.element.id)
|
|
1724
1926
|
processedOptions.element = "#" + options.element.id;
|
|
@@ -1758,7 +1960,12 @@ function processSnapshot(snapshot, ctx) {
|
|
|
1758
1960
|
}
|
|
1759
1961
|
let navigated = false;
|
|
1760
1962
|
let previousDeviceType = null;
|
|
1761
|
-
let renderViewports
|
|
1963
|
+
let renderViewports;
|
|
1964
|
+
if (snapshot.options && snapshot.options.web || snapshot.options && snapshot.options.mobile) {
|
|
1965
|
+
renderViewports = getRenderViewportsForOptions(snapshot.options);
|
|
1966
|
+
} else {
|
|
1967
|
+
renderViewports = getRenderViewports(ctx);
|
|
1968
|
+
}
|
|
1762
1969
|
for (const { viewport, viewportString, fullPage, device } of renderViewports) {
|
|
1763
1970
|
if (previousDeviceType !== null && previousDeviceType !== device) {
|
|
1764
1971
|
navigated = false;
|
|
@@ -1817,6 +2024,7 @@ function processSnapshot(snapshot, ctx) {
|
|
|
1817
2024
|
});
|
|
1818
2025
|
}
|
|
1819
2026
|
}
|
|
2027
|
+
ctx.log.debug(`Processed options: ${JSON.stringify(processedOptions)}`);
|
|
1820
2028
|
}
|
|
1821
2029
|
return {
|
|
1822
2030
|
processedSnapshot: {
|
|
@@ -1831,9 +2039,285 @@ function processSnapshot(snapshot, ctx) {
|
|
|
1831
2039
|
});
|
|
1832
2040
|
}
|
|
1833
2041
|
|
|
2042
|
+
// src/lib/snapshotQueue.ts
|
|
2043
|
+
var Queue = class {
|
|
2044
|
+
constructor(ctx) {
|
|
2045
|
+
this.snapshots = [];
|
|
2046
|
+
this.processedSnapshots = [];
|
|
2047
|
+
this.processing = false;
|
|
2048
|
+
this.processingSnapshot = "";
|
|
2049
|
+
this.snapshotNames = [];
|
|
2050
|
+
this.variants = [];
|
|
2051
|
+
this.ctx = ctx;
|
|
2052
|
+
}
|
|
2053
|
+
enqueue(item) {
|
|
2054
|
+
this.snapshots.push(item);
|
|
2055
|
+
if (!this.ctx.config.delayedUpload) {
|
|
2056
|
+
if (!this.processing) {
|
|
2057
|
+
this.processing = true;
|
|
2058
|
+
this.processNext();
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
startProcessingfunc() {
|
|
2063
|
+
if (!this.processing) {
|
|
2064
|
+
this.processing = true;
|
|
2065
|
+
this.processNext();
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
processGenerateVariants(snapshot) {
|
|
2069
|
+
if (snapshot.options) {
|
|
2070
|
+
if (snapshot.options.web) {
|
|
2071
|
+
this.generateWebVariants(snapshot, snapshot.options.web);
|
|
2072
|
+
}
|
|
2073
|
+
if (snapshot.options.mobile) {
|
|
2074
|
+
this.generateMobileVariants(snapshot, snapshot.options.mobile);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
if (!snapshot.options || snapshot.options && !snapshot.options.web && !snapshot.options.mobile) {
|
|
2078
|
+
this.generateVariants(snapshot, this.ctx.config);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
generateVariants(snapshot, config) {
|
|
2082
|
+
if (config.web) {
|
|
2083
|
+
const browsers = config.web.browsers || [];
|
|
2084
|
+
const viewports = config.web.viewports || [];
|
|
2085
|
+
for (const browser of browsers) {
|
|
2086
|
+
for (const viewport of viewports) {
|
|
2087
|
+
const width = viewport.width;
|
|
2088
|
+
const height = viewport.height || 0;
|
|
2089
|
+
const variant = `${snapshot.name}_${browser}_viewport[${width}]_viewport[${height}]`;
|
|
2090
|
+
this.variants.push(variant);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (config.mobile) {
|
|
2095
|
+
const devices = config.mobile.devices || [];
|
|
2096
|
+
const orientation = config.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
2097
|
+
for (const device of devices) {
|
|
2098
|
+
const variant = `${snapshot.name}_${device}_${orientation}`;
|
|
2099
|
+
this.variants.push(variant);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
generateWebVariants(snapshot, webConfig) {
|
|
2104
|
+
var _a, _b, _c;
|
|
2105
|
+
const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? void 0 : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
|
|
2106
|
+
const viewports = webConfig.viewports || [];
|
|
2107
|
+
for (const browser of browsers) {
|
|
2108
|
+
for (const viewport of viewports) {
|
|
2109
|
+
const width = viewport[0];
|
|
2110
|
+
const height = viewport[1] || 0;
|
|
2111
|
+
const variant = `${snapshot.name}_${browser}_viewport[${width}]_viewport[${height}]`;
|
|
2112
|
+
this.variants.push(variant);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
generateMobileVariants(snapshot, mobileConfig) {
|
|
2117
|
+
var _a, _b, _c;
|
|
2118
|
+
const devices = mobileConfig.devices || [];
|
|
2119
|
+
const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? void 0 : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
2120
|
+
for (const device of devices) {
|
|
2121
|
+
const variant = `${snapshot.name}_${device}_${orientation}`;
|
|
2122
|
+
this.variants.push(variant);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
filterExistingVariants(snapshot, config) {
|
|
2126
|
+
let drop = true;
|
|
2127
|
+
if (snapshot.options && snapshot.options.web) {
|
|
2128
|
+
const webDrop = this.filterWebVariants(snapshot, snapshot.options.web);
|
|
2129
|
+
if (!webDrop)
|
|
2130
|
+
drop = false;
|
|
2131
|
+
}
|
|
2132
|
+
if (snapshot.options && snapshot.options.mobile) {
|
|
2133
|
+
const mobileDrop = this.filterMobileVariants(snapshot, snapshot.options.mobile);
|
|
2134
|
+
if (!mobileDrop)
|
|
2135
|
+
drop = false;
|
|
2136
|
+
}
|
|
2137
|
+
if (!snapshot.options || snapshot.options && !snapshot.options.web && !snapshot.options.mobile) {
|
|
2138
|
+
const configDrop = this.filterVariants(snapshot, config);
|
|
2139
|
+
if (!configDrop)
|
|
2140
|
+
drop = false;
|
|
2141
|
+
}
|
|
2142
|
+
return drop;
|
|
2143
|
+
}
|
|
2144
|
+
filterVariants(snapshot, config) {
|
|
2145
|
+
var _a;
|
|
2146
|
+
let allVariantsDropped = true;
|
|
2147
|
+
if (config.web) {
|
|
2148
|
+
const browsers = config.web.browsers || [];
|
|
2149
|
+
const viewports = config.web.viewports || [];
|
|
2150
|
+
for (const browser of browsers) {
|
|
2151
|
+
for (const viewport of viewports) {
|
|
2152
|
+
const width = viewport.width;
|
|
2153
|
+
const height = viewport.height || 0;
|
|
2154
|
+
const variant = `${snapshot.name}_${browser}_viewport[${width}]_viewport[${height}]`;
|
|
2155
|
+
if (!this.variants.includes(variant)) {
|
|
2156
|
+
allVariantsDropped = false;
|
|
2157
|
+
if (!snapshot.options)
|
|
2158
|
+
snapshot.options = {};
|
|
2159
|
+
if (!snapshot.options.web)
|
|
2160
|
+
snapshot.options.web = { browsers: [], viewports: [] };
|
|
2161
|
+
if (!snapshot.options.web.browsers.includes(browser)) {
|
|
2162
|
+
snapshot.options.web.browsers.push(browser);
|
|
2163
|
+
}
|
|
2164
|
+
const viewportExists = snapshot.options.web.viewports.some(
|
|
2165
|
+
(existingViewport) => existingViewport[0] === width && (existingViewport.length < 2 || existingViewport[1] === height)
|
|
2166
|
+
);
|
|
2167
|
+
if (!viewportExists) {
|
|
2168
|
+
if (height > 0) {
|
|
2169
|
+
snapshot.options.web.viewports.push([width, height]);
|
|
2170
|
+
} else {
|
|
2171
|
+
snapshot.options.web.viewports.push([width]);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
if (config.mobile) {
|
|
2179
|
+
const devices = config.mobile.devices || [];
|
|
2180
|
+
const orientation = config.mobile.orientation || constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
2181
|
+
const fullPage = (_a = config.mobile.fullPage) != null ? _a : true;
|
|
2182
|
+
for (const device of devices) {
|
|
2183
|
+
const variant = `${snapshot.name}_${device}_${orientation}`;
|
|
2184
|
+
if (!this.variants.includes(variant)) {
|
|
2185
|
+
allVariantsDropped = false;
|
|
2186
|
+
if (!snapshot.options)
|
|
2187
|
+
snapshot.options = {};
|
|
2188
|
+
if (!snapshot.options.mobile)
|
|
2189
|
+
snapshot.options.mobile = { devices: [], orientation: constants_default.MOBILE_ORIENTATION_PORTRAIT, fullPage };
|
|
2190
|
+
if (!snapshot.options.mobile.devices.includes(device)) {
|
|
2191
|
+
snapshot.options.mobile.devices.push(device);
|
|
2192
|
+
}
|
|
2193
|
+
snapshot.options.mobile.orientation = orientation;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
return allVariantsDropped;
|
|
2198
|
+
}
|
|
2199
|
+
filterWebVariants(snapshot, webConfig) {
|
|
2200
|
+
var _a, _b, _c;
|
|
2201
|
+
const browsers = (_c = (_b = webConfig.browsers) != null ? _b : (_a = this.ctx.config.web) == null ? void 0 : _a.browsers) != null ? _c : [constants_default.CHROME, constants_default.EDGE, constants_default.FIREFOX, constants_default.SAFARI];
|
|
2202
|
+
const viewports = webConfig.viewports || [];
|
|
2203
|
+
let allVariantsDropped = true;
|
|
2204
|
+
if (!snapshot.options) {
|
|
2205
|
+
snapshot.options = {};
|
|
2206
|
+
}
|
|
2207
|
+
snapshot.options.web = { browsers: [], viewports: [] };
|
|
2208
|
+
for (const browser of browsers) {
|
|
2209
|
+
for (const viewport of viewports) {
|
|
2210
|
+
const width = viewport[0];
|
|
2211
|
+
const height = viewport[1] || 0;
|
|
2212
|
+
const variant = `${snapshot.name}_${browser}_viewport[${width}]_viewport[${height}]`;
|
|
2213
|
+
if (!this.variants.includes(variant)) {
|
|
2214
|
+
allVariantsDropped = false;
|
|
2215
|
+
if (!snapshot.options.web.browsers.includes(browser)) {
|
|
2216
|
+
snapshot.options.web.browsers.push(browser);
|
|
2217
|
+
}
|
|
2218
|
+
const viewportExists = snapshot.options.web.viewports.some(
|
|
2219
|
+
(existingViewport) => existingViewport[0] === width && (existingViewport.length < 2 || existingViewport[1] === height)
|
|
2220
|
+
);
|
|
2221
|
+
if (!viewportExists) {
|
|
2222
|
+
if (height > 0) {
|
|
2223
|
+
snapshot.options.web.viewports.push([width, height]);
|
|
2224
|
+
} else {
|
|
2225
|
+
snapshot.options.web.viewports.push([width]);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
return allVariantsDropped;
|
|
2232
|
+
}
|
|
2233
|
+
filterMobileVariants(snapshot, mobileConfig) {
|
|
2234
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2235
|
+
if (!snapshot.options) {
|
|
2236
|
+
snapshot.options = {};
|
|
2237
|
+
}
|
|
2238
|
+
const devices = mobileConfig.devices || [];
|
|
2239
|
+
const orientation = (_c = (_b = mobileConfig.orientation) != null ? _b : (_a = this.ctx.config.mobile) == null ? void 0 : _a.orientation) != null ? _c : constants_default.MOBILE_ORIENTATION_PORTRAIT;
|
|
2240
|
+
const fullPage = (_f = (_e = mobileConfig.fullPage) != null ? _e : (_d = this.ctx.config.mobile) == null ? void 0 : _d.fullPage) != null ? _f : true;
|
|
2241
|
+
let allVariantsDropped = true;
|
|
2242
|
+
snapshot.options.mobile = { devices: [], orientation: constants_default.MOBILE_ORIENTATION_PORTRAIT, fullPage };
|
|
2243
|
+
for (const device of devices) {
|
|
2244
|
+
const variant = `${snapshot.name}_${device}_${orientation}`;
|
|
2245
|
+
if (!this.variants.includes(variant)) {
|
|
2246
|
+
allVariantsDropped = false;
|
|
2247
|
+
snapshot.options.mobile.devices.push(device);
|
|
2248
|
+
snapshot.options.mobile.orientation = orientation;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return allVariantsDropped;
|
|
2252
|
+
}
|
|
2253
|
+
processNext() {
|
|
2254
|
+
return __async(this, null, function* () {
|
|
2255
|
+
if (!this.isEmpty()) {
|
|
2256
|
+
let snapshot;
|
|
2257
|
+
if (this.ctx.config.delayedUpload) {
|
|
2258
|
+
snapshot = this.snapshots.pop();
|
|
2259
|
+
} else {
|
|
2260
|
+
snapshot = this.snapshots.shift();
|
|
2261
|
+
}
|
|
2262
|
+
try {
|
|
2263
|
+
this.processingSnapshot = snapshot == null ? void 0 : snapshot.name;
|
|
2264
|
+
let drop = false;
|
|
2265
|
+
if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {
|
|
2266
|
+
drop = true;
|
|
2267
|
+
this.ctx.log.info(`Skipping duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'delayedUploads' configuration as true in your config file.`);
|
|
2268
|
+
}
|
|
2269
|
+
if (this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {
|
|
2270
|
+
drop = this.filterExistingVariants(snapshot, this.ctx.config);
|
|
2271
|
+
}
|
|
2272
|
+
if (snapshot && snapshot.name && !this.snapshotNames.includes(snapshot.name) && !drop) {
|
|
2273
|
+
this.snapshotNames.push(snapshot.name);
|
|
2274
|
+
}
|
|
2275
|
+
if (this.ctx.config.delayedUpload && snapshot && !drop) {
|
|
2276
|
+
this.processGenerateVariants(snapshot);
|
|
2277
|
+
}
|
|
2278
|
+
if (!drop) {
|
|
2279
|
+
let { processedSnapshot, warnings } = yield processSnapshot(snapshot, this.ctx);
|
|
2280
|
+
yield this.ctx.client.uploadSnapshot(this.ctx, processedSnapshot);
|
|
2281
|
+
this.ctx.totalSnapshots++;
|
|
2282
|
+
this.processedSnapshots.push({ name: snapshot.name, warnings });
|
|
2283
|
+
}
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
this.ctx.log.debug(`snapshot failed; ${error}`);
|
|
2286
|
+
this.processedSnapshots.push({ name: snapshot.name, error: error.message });
|
|
2287
|
+
}
|
|
2288
|
+
if (this.ctx.browser) {
|
|
2289
|
+
for (let context of this.ctx.browser.contexts()) {
|
|
2290
|
+
for (let page of context.pages()) {
|
|
2291
|
+
yield page.close();
|
|
2292
|
+
this.ctx.log.debug(`Closed browser page for snapshot ${snapshot.name}`);
|
|
2293
|
+
}
|
|
2294
|
+
yield context.close();
|
|
2295
|
+
this.ctx.log.debug(`Closed browser context for snapshot ${snapshot.name}`);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
this.processNext();
|
|
2299
|
+
} else {
|
|
2300
|
+
this.processing = false;
|
|
2301
|
+
}
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
isProcessing() {
|
|
2305
|
+
return this.processing;
|
|
2306
|
+
}
|
|
2307
|
+
getProcessingSnapshot() {
|
|
2308
|
+
return this.processingSnapshot;
|
|
2309
|
+
}
|
|
2310
|
+
getProcessedSnapshots() {
|
|
2311
|
+
return this.processedSnapshots;
|
|
2312
|
+
}
|
|
2313
|
+
isEmpty() {
|
|
2314
|
+
return this.snapshots && this.snapshots.length ? false : true;
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
|
|
1834
2318
|
// src/commander/exec.ts
|
|
1835
2319
|
var command = new commander.Command();
|
|
1836
|
-
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").action(function(execCommand, _, command5) {
|
|
2320
|
+
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").action(function(execCommand, _, command5) {
|
|
1837
2321
|
return __async(this, null, function* () {
|
|
1838
2322
|
let ctx = ctx_default(command5.optsWithGlobals());
|
|
1839
2323
|
if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
|
|
@@ -2037,13 +2521,13 @@ function captureScreenshots(ctx) {
|
|
|
2037
2521
|
else
|
|
2038
2522
|
yield captureScreenshotsSync(ctx, staticConfig, browsers);
|
|
2039
2523
|
delDir(`screenshots/${staticConfig.name.toLowerCase().replace(/\s/g, "_")}`);
|
|
2040
|
-
output += `${
|
|
2524
|
+
output += `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.green("\u2713")}
|
|
2041
2525
|
`;
|
|
2042
2526
|
ctx.task.output = output;
|
|
2043
2527
|
capturedScreenshots++;
|
|
2044
2528
|
} catch (error) {
|
|
2045
2529
|
ctx.log.debug(`screenshot capture failed for ${JSON.stringify(staticConfig)}; error: ${error}`);
|
|
2046
|
-
output += `${
|
|
2530
|
+
output += `${chalk6__default.default.gray(staticConfig.name)} ${chalk6__default.default.red("\u2717")}
|
|
2047
2531
|
`;
|
|
2048
2532
|
ctx.task.output = output;
|
|
2049
2533
|
}
|
|
@@ -2161,6 +2645,9 @@ var captureScreenshots_default = (ctx) => {
|
|
|
2161
2645
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
2162
2646
|
try {
|
|
2163
2647
|
ctx2.task = task;
|
|
2648
|
+
if (ctx2.options.fetchResults) {
|
|
2649
|
+
startPolling(ctx2, task);
|
|
2650
|
+
}
|
|
2164
2651
|
updateLogContext({ task: "capture" });
|
|
2165
2652
|
let { capturedScreenshots, output } = yield captureScreenshots(ctx2);
|
|
2166
2653
|
if (capturedScreenshots != ctx2.webStaticConfig.length) {
|
|
@@ -2169,7 +2656,7 @@ var captureScreenshots_default = (ctx) => {
|
|
|
2169
2656
|
task.title = "Screenshots captured successfully";
|
|
2170
2657
|
} catch (error) {
|
|
2171
2658
|
ctx2.log.debug(error);
|
|
2172
|
-
task.output =
|
|
2659
|
+
task.output = chalk6__default.default.gray(`${error.message}`);
|
|
2173
2660
|
throw new Error("Capturing screenshots failed");
|
|
2174
2661
|
}
|
|
2175
2662
|
}),
|
|
@@ -2180,7 +2667,7 @@ var captureScreenshots_default = (ctx) => {
|
|
|
2180
2667
|
|
|
2181
2668
|
// src/commander/capture.ts
|
|
2182
2669
|
var command2 = new commander.Command();
|
|
2183
|
-
command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("--parallel", "Capture parallely on all browsers").action(function(file, _, command5) {
|
|
2670
|
+
command2.name("capture").description("Capture screenshots of static sites").argument("<file>", "Web static config file").option("--parallel", "Capture parallely on all browsers").option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(file, _, command5) {
|
|
2184
2671
|
return __async(this, null, function* () {
|
|
2185
2672
|
let ctx = ctx_default(command5.optsWithGlobals());
|
|
2186
2673
|
if (!fs5__default.default.existsSync(file)) {
|
|
@@ -2228,12 +2715,15 @@ var uploadScreenshots_default = (ctx) => {
|
|
|
2228
2715
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
2229
2716
|
try {
|
|
2230
2717
|
ctx2.task = task;
|
|
2718
|
+
if (ctx2.options.fetchResults) {
|
|
2719
|
+
startPolling(ctx2, task);
|
|
2720
|
+
}
|
|
2231
2721
|
updateLogContext({ task: "upload" });
|
|
2232
2722
|
yield uploadScreenshots(ctx2);
|
|
2233
2723
|
task.title = "Screenshots uploaded successfully";
|
|
2234
2724
|
} catch (error) {
|
|
2235
2725
|
ctx2.log.debug(error);
|
|
2236
|
-
task.output =
|
|
2726
|
+
task.output = chalk6__default.default.gray(`${error.message}`);
|
|
2237
2727
|
throw new Error("Uploading screenshots failed");
|
|
2238
2728
|
}
|
|
2239
2729
|
}),
|
|
@@ -2248,7 +2738,7 @@ command3.name("upload").description("Upload screenshots from given directory").a
|
|
|
2248
2738
|
return val.split(",").map((ext) => ext.trim().toLowerCase());
|
|
2249
2739
|
}).option("-E, --removeExtensions", "Strips file extensions from snapshot names").option("-i, --ignoreDir <patterns>", "Comma-separated list of directories to ignore", (val) => {
|
|
2250
2740
|
return val.split(",").map((pattern) => pattern.trim());
|
|
2251
|
-
}).action(function(directory, _, command5) {
|
|
2741
|
+
}).option("--fetch-results [filename]", "Fetch results and optionally specify an output file, e.g., <filename>.json").action(function(directory, _, command5) {
|
|
2252
2742
|
return __async(this, null, function* () {
|
|
2253
2743
|
let ctx = ctx_default(command5.optsWithGlobals());
|
|
2254
2744
|
if (!fs5__default.default.existsSync(directory)) {
|
|
@@ -2328,7 +2818,7 @@ var uploadFigmaDesigns_default2 = (ctx) => {
|
|
|
2328
2818
|
ctx2.log.debug(`Figma designs processed: ${results}`);
|
|
2329
2819
|
} catch (error) {
|
|
2330
2820
|
ctx2.log.debug(error);
|
|
2331
|
-
task.output =
|
|
2821
|
+
task.output = chalk6__default.default.gray(`${error.message}`);
|
|
2332
2822
|
throw new Error("Uploading Figma designs failed");
|
|
2333
2823
|
}
|
|
2334
2824
|
}),
|
|
@@ -2394,16 +2884,16 @@ var commander_default = program;
|
|
|
2394
2884
|
let { data: { latestVersion, deprecated, additionalDescription } } = yield client.checkUpdate(log2);
|
|
2395
2885
|
log2.info(`
|
|
2396
2886
|
LambdaTest SmartUI CLI v${package_default.version}`);
|
|
2397
|
-
log2.info(
|
|
2887
|
+
log2.info(chalk6__default.default.yellow(`${additionalDescription}`));
|
|
2398
2888
|
if (deprecated) {
|
|
2399
2889
|
log2.warn(`This version is deprecated. A new version ${latestVersion} is available!`);
|
|
2400
2890
|
} else if (package_default.version !== latestVersion) {
|
|
2401
|
-
log2.info(
|
|
2891
|
+
log2.info(chalk6__default.default.green(`A new version ${latestVersion} is available!`));
|
|
2402
2892
|
} else
|
|
2403
|
-
log2.info(
|
|
2893
|
+
log2.info(chalk6__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
|
|
2404
2894
|
} catch (error) {
|
|
2405
2895
|
log2.debug(error);
|
|
2406
|
-
log2.info(
|
|
2896
|
+
log2.info(chalk6__default.default.gray("https://www.npmjs.com/package/@lambdatest/smartui-cli\n"));
|
|
2407
2897
|
}
|
|
2408
2898
|
commander_default.parse();
|
|
2409
2899
|
});
|