@lambdatest/smartui-cli 2.0.3 → 2.0.5
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 +341 -107
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8,14 +8,14 @@ var chalk = require('chalk');
|
|
|
8
8
|
var path2 = require('path');
|
|
9
9
|
var fastify = require('fastify');
|
|
10
10
|
var fs = require('fs');
|
|
11
|
-
var
|
|
11
|
+
var test = require('@playwright/test');
|
|
12
12
|
var Ajv = require('ajv');
|
|
13
13
|
var addErrors = require('ajv-errors');
|
|
14
|
+
var winston = require('winston');
|
|
14
15
|
var FormData = require('form-data');
|
|
15
16
|
var axios = require('axios');
|
|
16
17
|
var child_process = require('child_process');
|
|
17
18
|
var spawn = require('cross-spawn');
|
|
18
|
-
var test = require('@playwright/test');
|
|
19
19
|
|
|
20
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
21
|
|
|
@@ -66,6 +66,271 @@ var __async = (__this, __arguments, generator) => {
|
|
|
66
66
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
|
+
var MIN_VIEWPORT_HEIGHT = 1080;
|
|
70
|
+
var processSnapshot_default = (snapshot, ctx) => __async(void 0, null, function* () {
|
|
71
|
+
let options = snapshot.options;
|
|
72
|
+
let warnings = [];
|
|
73
|
+
let processedOptions = {};
|
|
74
|
+
if (options && Object.keys(options).length !== 0) {
|
|
75
|
+
ctx.log.debug(`Processing options: ${JSON.stringify(options)}`);
|
|
76
|
+
if (options.ignoreDOM && Object.keys(options.ignoreDOM).length !== 0 || options.selectDOM && Object.keys(options.selectDOM).length !== 0) {
|
|
77
|
+
if (!ctx.browser)
|
|
78
|
+
ctx.browser = yield test.chromium.launch({ headless: true });
|
|
79
|
+
let ignoreOrSelectDOM;
|
|
80
|
+
let ignoreOrSelectBoxes;
|
|
81
|
+
if (options.ignoreDOM && Object.keys(options.ignoreDOM).length !== 0) {
|
|
82
|
+
processedOptions.ignoreBoxes = {};
|
|
83
|
+
ignoreOrSelectDOM = "ignoreDOM";
|
|
84
|
+
ignoreOrSelectBoxes = "ignoreBoxes";
|
|
85
|
+
} else {
|
|
86
|
+
processedOptions.selectBoxes = {};
|
|
87
|
+
ignoreOrSelectDOM = "selectDOM";
|
|
88
|
+
ignoreOrSelectBoxes = "selectBoxes";
|
|
89
|
+
}
|
|
90
|
+
let selectors = [];
|
|
91
|
+
for (const [key, value] of Object.entries(options[ignoreOrSelectDOM])) {
|
|
92
|
+
switch (key) {
|
|
93
|
+
case "id":
|
|
94
|
+
selectors.push(...value.map((e) => "#" + e));
|
|
95
|
+
break;
|
|
96
|
+
case "class":
|
|
97
|
+
selectors.push(...value.map((e) => "." + e));
|
|
98
|
+
break;
|
|
99
|
+
case "xpath":
|
|
100
|
+
selectors.push(...value.map((e) => "xpath=" + e));
|
|
101
|
+
break;
|
|
102
|
+
case "cssSelector":
|
|
103
|
+
selectors.push(...value);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const vp of ctx.webConfig.viewports) {
|
|
108
|
+
const page = yield ctx.browser.newPage({ viewport: { width: vp.width, height: vp.height || MIN_VIEWPORT_HEIGHT } });
|
|
109
|
+
yield page.setContent(snapshot.dom.html);
|
|
110
|
+
let viewport = `${vp.width}${vp.height ? "x" + vp.height : ""}`;
|
|
111
|
+
if (!Array.isArray(processedOptions[ignoreOrSelectBoxes][viewport]))
|
|
112
|
+
processedOptions[ignoreOrSelectBoxes][viewport] = [];
|
|
113
|
+
let locators = [];
|
|
114
|
+
let boxes = [];
|
|
115
|
+
for (const selector of selectors) {
|
|
116
|
+
let l = yield page.locator(selector).all();
|
|
117
|
+
if (l.length === 0) {
|
|
118
|
+
warnings.push(`For snapshot ${snapshot.name}, no element found for selector ${selector}`);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
locators.push(...l);
|
|
122
|
+
}
|
|
123
|
+
for (const locator of locators) {
|
|
124
|
+
let bb = yield locator.boundingBox();
|
|
125
|
+
if (bb)
|
|
126
|
+
boxes.push({
|
|
127
|
+
left: bb.x,
|
|
128
|
+
top: bb.y,
|
|
129
|
+
right: bb.x + bb.width,
|
|
130
|
+
bottom: bb.y + bb.height
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
processedOptions[ignoreOrSelectBoxes][viewport].push(...boxes);
|
|
134
|
+
yield page.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
warnings.push(...snapshot.dom.warnings);
|
|
139
|
+
return {
|
|
140
|
+
processedSnapshot: {
|
|
141
|
+
name: snapshot.name,
|
|
142
|
+
url: snapshot.url,
|
|
143
|
+
dom: Buffer.from(snapshot.dom.html).toString("base64"),
|
|
144
|
+
options: processedOptions
|
|
145
|
+
},
|
|
146
|
+
warnings
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
var ajv = new Ajv__default.default({ allErrors: true });
|
|
150
|
+
ajv.addFormat("web-url", {
|
|
151
|
+
type: "string",
|
|
152
|
+
validate: (url) => {
|
|
153
|
+
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");
|
|
154
|
+
return urlPattern.test(url.trim());
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
addErrors__default.default(ajv);
|
|
158
|
+
var ConfigSchema = {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
web: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
browsers: {
|
|
165
|
+
type: "array",
|
|
166
|
+
items: { type: "string", enum: ["chrome", "firefox", "edge", "safari"] },
|
|
167
|
+
uniqueItems: true,
|
|
168
|
+
maxItems: 4,
|
|
169
|
+
errorMessage: "Invalid config; allowed browsers - chrome, firefox, edge, safari"
|
|
170
|
+
},
|
|
171
|
+
viewports: {
|
|
172
|
+
type: "array",
|
|
173
|
+
items: {
|
|
174
|
+
type: "array",
|
|
175
|
+
oneOf: [
|
|
176
|
+
{
|
|
177
|
+
items: [{ type: "number", minimum: 320, maximum: 7680 }],
|
|
178
|
+
minItems: 1,
|
|
179
|
+
maxItems: 1
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
items: [
|
|
183
|
+
{ type: "number", minimum: 320, maximum: 7680 },
|
|
184
|
+
{ type: "number", minimum: 320, maximum: 7680 }
|
|
185
|
+
],
|
|
186
|
+
minItems: 2,
|
|
187
|
+
maxItems: 2
|
|
188
|
+
}
|
|
189
|
+
],
|
|
190
|
+
errorMessage: "Invalid config; width/height must be >= 320 and <= 7680"
|
|
191
|
+
},
|
|
192
|
+
uniqueItems: true,
|
|
193
|
+
maxItems: 5,
|
|
194
|
+
errorMessage: "Invalid config; max unique viewports allowed - 5"
|
|
195
|
+
},
|
|
196
|
+
waitForPageRender: {
|
|
197
|
+
type: "number",
|
|
198
|
+
minimum: 0,
|
|
199
|
+
maximum: 3e5,
|
|
200
|
+
errorMessage: "Invalid config; waitForPageRender must be > 0 and <= 300000"
|
|
201
|
+
},
|
|
202
|
+
waitForTimeout: {
|
|
203
|
+
type: "number",
|
|
204
|
+
minimum: 0,
|
|
205
|
+
maximum: 3e4,
|
|
206
|
+
errorMessage: "Invalid config; waitForTimeout must be > 0 and <= 30000"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
required: ["browsers", "viewports"],
|
|
210
|
+
additionalProperties: false
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
required: ["web"],
|
|
214
|
+
additionalProperties: false
|
|
215
|
+
};
|
|
216
|
+
var WebStaticConfigSchema = {
|
|
217
|
+
type: "array",
|
|
218
|
+
items: {
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: {
|
|
221
|
+
name: {
|
|
222
|
+
type: "string",
|
|
223
|
+
minLength: 1,
|
|
224
|
+
errorMessage: "name is mandatory and cannot be empty"
|
|
225
|
+
},
|
|
226
|
+
url: {
|
|
227
|
+
type: "string",
|
|
228
|
+
format: "web-url",
|
|
229
|
+
errorMessage: "url is mandatory and must be a valid web URL"
|
|
230
|
+
},
|
|
231
|
+
waitForTimeout: {
|
|
232
|
+
type: "number",
|
|
233
|
+
nullable: true,
|
|
234
|
+
minimum: 0,
|
|
235
|
+
maximum: 3e4,
|
|
236
|
+
errorMessage: "waitForTimeout must be > 0 and <= 30000"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
required: ["name", "url"],
|
|
240
|
+
additionalProperties: false
|
|
241
|
+
},
|
|
242
|
+
uniqueItems: true
|
|
243
|
+
};
|
|
244
|
+
var SnapshotSchema = {
|
|
245
|
+
type: "object",
|
|
246
|
+
properties: {
|
|
247
|
+
name: {
|
|
248
|
+
type: "string",
|
|
249
|
+
minLength: 1,
|
|
250
|
+
errorMessage: "Invalid snapshot; name is mandatory and cannot be empty"
|
|
251
|
+
},
|
|
252
|
+
url: {
|
|
253
|
+
type: "string",
|
|
254
|
+
format: "web-url",
|
|
255
|
+
errorMessage: "Invalid snapshot; url is mandatory and must be a valid web URL"
|
|
256
|
+
},
|
|
257
|
+
dom: {
|
|
258
|
+
type: "object"
|
|
259
|
+
},
|
|
260
|
+
options: {
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: {
|
|
263
|
+
ignoreDOM: {
|
|
264
|
+
type: "object",
|
|
265
|
+
properties: {
|
|
266
|
+
id: {
|
|
267
|
+
type: "array",
|
|
268
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; id cannot be empty or have semicolon" },
|
|
269
|
+
uniqueItems: true,
|
|
270
|
+
errorMessage: "Invalid snapshot options; id array must have unique items"
|
|
271
|
+
},
|
|
272
|
+
class: {
|
|
273
|
+
type: "array",
|
|
274
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; class cannot be empty or have semicolon" },
|
|
275
|
+
uniqueItems: true,
|
|
276
|
+
errorMessage: "Invalid snapshot options; class array must have unique items"
|
|
277
|
+
},
|
|
278
|
+
cssSelector: {
|
|
279
|
+
type: "array",
|
|
280
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; cssSelector cannot be empty or have semicolon" },
|
|
281
|
+
uniqueItems: true,
|
|
282
|
+
errorMessage: "Invalid snapshot options; cssSelector array must have unique items"
|
|
283
|
+
},
|
|
284
|
+
xpath: {
|
|
285
|
+
type: "array",
|
|
286
|
+
items: { type: "string", minLength: 1 },
|
|
287
|
+
uniqueItems: true,
|
|
288
|
+
errorMessage: "Invalid snapshot options; xpath array must have unique and non-empty items"
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
selectDOM: {
|
|
293
|
+
type: "object",
|
|
294
|
+
properties: {
|
|
295
|
+
id: {
|
|
296
|
+
type: "array",
|
|
297
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; id cannot be empty or have semicolon" },
|
|
298
|
+
uniqueItems: true,
|
|
299
|
+
errorMessage: "Invalid snapshot options; id array must have unique items"
|
|
300
|
+
},
|
|
301
|
+
class: {
|
|
302
|
+
type: "array",
|
|
303
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; class cannot be empty or have semicolon" },
|
|
304
|
+
uniqueItems: true,
|
|
305
|
+
errorMessage: "Invalid snapshot options; class array must have unique items"
|
|
306
|
+
},
|
|
307
|
+
cssSelector: {
|
|
308
|
+
type: "array",
|
|
309
|
+
items: { type: "string", minLength: 1, pattern: "^[^;]*$", errorMessage: "Invalid snapshot options; cssSelector cannot be empty or have semicolon" },
|
|
310
|
+
uniqueItems: true,
|
|
311
|
+
errorMessage: "Invalid snapshot options; cssSelector array must have unique items"
|
|
312
|
+
},
|
|
313
|
+
xpath: {
|
|
314
|
+
type: "array",
|
|
315
|
+
items: { type: "string", minLength: 1 },
|
|
316
|
+
uniqueItems: true,
|
|
317
|
+
errorMessage: "Invalid snapshot options; xpath array must have unique and non-empty items"
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
additionalProperties: false
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
required: ["name", "url", "dom", "options"],
|
|
326
|
+
additionalProperties: false,
|
|
327
|
+
errorMessage: "Invalid snapshot"
|
|
328
|
+
};
|
|
329
|
+
var validateConfig = ajv.compile(ConfigSchema);
|
|
330
|
+
var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
|
|
331
|
+
var validateSnapshot = ajv.compile(SnapshotSchema);
|
|
332
|
+
|
|
333
|
+
// src/lib/server.ts
|
|
69
334
|
var server_default = (ctx) => __async(void 0, null, function* () {
|
|
70
335
|
const server = fastify__default.default({ logger: false, bodyLimit: 1e7 });
|
|
71
336
|
const opts = {};
|
|
@@ -77,15 +342,17 @@ var server_default = (ctx) => __async(void 0, null, function* () {
|
|
|
77
342
|
reply.code(200).send({ data: { dom: SMARTUI_DOM } });
|
|
78
343
|
});
|
|
79
344
|
server.post("/snapshot", opts, (request, reply) => __async(void 0, null, function* () {
|
|
80
|
-
let { snapshot, testType } = request.body;
|
|
81
|
-
snapshot.dom = Buffer.from(snapshot.dom).toString("base64");
|
|
82
345
|
try {
|
|
83
|
-
|
|
346
|
+
let { snapshot, testType } = request.body;
|
|
347
|
+
if (!validateSnapshot(snapshot))
|
|
348
|
+
throw new Error(validateSnapshot.errors[0].message);
|
|
349
|
+
let { processedSnapshot, warnings } = yield processSnapshot_default(snapshot, ctx);
|
|
350
|
+
yield ctx.client.uploadSnapshot(ctx.build.id, processedSnapshot, testType, ctx.log);
|
|
351
|
+
ctx.totalSnapshots++;
|
|
352
|
+
reply.code(200).send({ data: { message: "success", warnings } });
|
|
84
353
|
} catch (error) {
|
|
85
|
-
reply.code(500).send({ error: { message: error.message } });
|
|
354
|
+
return reply.code(500).send({ error: { message: error.message } });
|
|
86
355
|
}
|
|
87
|
-
ctx.totalSnapshots++;
|
|
88
|
-
reply.code(200).send({ data: { message: "success" } });
|
|
89
356
|
}));
|
|
90
357
|
yield server.listen({ port: 8080 });
|
|
91
358
|
let { port } = server.addresses()[0];
|
|
@@ -196,9 +463,9 @@ var DEFAULT_CONFIG = {
|
|
|
196
463
|
"edge"
|
|
197
464
|
],
|
|
198
465
|
viewports: [
|
|
199
|
-
[1920
|
|
200
|
-
[1366
|
|
201
|
-
[360
|
|
466
|
+
[1920],
|
|
467
|
+
[1366],
|
|
468
|
+
[360]
|
|
202
469
|
],
|
|
203
470
|
waitForTimeout: 1e3
|
|
204
471
|
}
|
|
@@ -237,100 +504,56 @@ function createWebStaticConfig(filepath) {
|
|
|
237
504
|
}
|
|
238
505
|
|
|
239
506
|
// package.json
|
|
240
|
-
var version = "2.0.
|
|
241
|
-
var
|
|
242
|
-
|
|
243
|
-
|
|
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);
|
|
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
|
-
items: [
|
|
268
|
-
{ type: "number", minimum: 320, maximum: 7680 },
|
|
269
|
-
{ type: "number", minimum: 320, maximum: 7680 }
|
|
270
|
-
],
|
|
271
|
-
additionalItems: false,
|
|
272
|
-
minItems: 2,
|
|
273
|
-
maxItems: 2
|
|
274
|
-
},
|
|
275
|
-
uniqueItems: true,
|
|
276
|
-
maxItems: 5,
|
|
277
|
-
errorMessage: "Invalid config; width/height must be >= 320 and <= 7680; max viewports allowed - 5"
|
|
278
|
-
},
|
|
279
|
-
waitForPageRender: {
|
|
280
|
-
type: "number",
|
|
281
|
-
minimum: 0,
|
|
282
|
-
maximum: 3e5,
|
|
283
|
-
errorMessage: "Invalid config; waitForPageRender must be > 0 and <= 300000"
|
|
284
|
-
},
|
|
285
|
-
waitForTimeout: {
|
|
286
|
-
type: "number",
|
|
287
|
-
minimum: 0,
|
|
288
|
-
maximum: 3e4,
|
|
289
|
-
errorMessage: "Invalid config; waitForTimeout must be > 0 and <= 30000"
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
required: ["browsers", "viewports"],
|
|
293
|
-
additionalProperties: false
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
required: ["web"],
|
|
297
|
-
additionalProperties: false
|
|
298
|
-
};
|
|
299
|
-
var WebStaticConfigSchema = {
|
|
300
|
-
type: "array",
|
|
301
|
-
items: {
|
|
302
|
-
type: "object",
|
|
303
|
-
properties: {
|
|
304
|
-
name: {
|
|
305
|
-
type: "string",
|
|
306
|
-
minLength: 1,
|
|
307
|
-
errorMessage: "name is mandatory and cannot be empty"
|
|
308
|
-
},
|
|
309
|
-
url: {
|
|
310
|
-
type: "string",
|
|
311
|
-
format: "web-url",
|
|
312
|
-
errorMessage: "url is mandatory and must be a valid web URL"
|
|
313
|
-
},
|
|
314
|
-
waitForTimeout: {
|
|
315
|
-
type: "number",
|
|
316
|
-
nullable: true,
|
|
317
|
-
minimum: 0,
|
|
318
|
-
maximum: 3e4,
|
|
319
|
-
errorMessage: "waitForTimeout must be > 0 and <= 30000"
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
required: ["name", "url"],
|
|
323
|
-
additionalProperties: false
|
|
324
|
-
},
|
|
325
|
-
uniqueItems: true
|
|
326
|
-
};
|
|
327
|
-
var validateConfig = ajv.compile(ConfigSchema);
|
|
328
|
-
var validateWebStaticConfig = ajv.compile(WebStaticConfigSchema);
|
|
507
|
+
var version = "2.0.5";
|
|
508
|
+
var HTTP_SCHEME = "https:";
|
|
509
|
+
var HTTP_SCHEME_PREFIX = "https://";
|
|
510
|
+
var WWW = "www.";
|
|
329
511
|
function delDir(dir) {
|
|
330
512
|
if (fs__default.default.existsSync(dir)) {
|
|
331
513
|
fs__default.default.rmSync(dir, { recursive: true });
|
|
332
514
|
}
|
|
333
515
|
}
|
|
516
|
+
function ensureHttps(urlString) {
|
|
517
|
+
try {
|
|
518
|
+
if (urlString && urlString.startsWith(WWW)) {
|
|
519
|
+
urlString = HTTP_SCHEME_PREFIX + urlString;
|
|
520
|
+
}
|
|
521
|
+
let url = new URL(urlString);
|
|
522
|
+
if (url.protocol !== HTTP_SCHEME) {
|
|
523
|
+
url.protocol = HTTP_SCHEME;
|
|
524
|
+
}
|
|
525
|
+
return url.toString();
|
|
526
|
+
} catch (error) {
|
|
527
|
+
console.error("Invalid URL: " + urlString, error);
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function scrollToBottomAndBackToTop({
|
|
532
|
+
frequency = 100,
|
|
533
|
+
timing = 8,
|
|
534
|
+
remoteWindow = window
|
|
535
|
+
} = {}) {
|
|
536
|
+
return new Promise((resolve) => {
|
|
537
|
+
let scrolls = 1;
|
|
538
|
+
let scrollLength = remoteWindow.document.body.scrollHeight / frequency;
|
|
539
|
+
(function scroll() {
|
|
540
|
+
let scrollBy = scrollLength * scrolls;
|
|
541
|
+
remoteWindow.setTimeout(() => {
|
|
542
|
+
remoteWindow.scrollTo(0, scrollBy);
|
|
543
|
+
if (scrolls < frequency) {
|
|
544
|
+
scrolls += 1;
|
|
545
|
+
scroll();
|
|
546
|
+
}
|
|
547
|
+
if (scrolls === frequency) {
|
|
548
|
+
remoteWindow.setTimeout(() => {
|
|
549
|
+
remoteWindow.scrollTo(0, 0);
|
|
550
|
+
resolve();
|
|
551
|
+
}, timing);
|
|
552
|
+
}
|
|
553
|
+
}, timing);
|
|
554
|
+
})();
|
|
555
|
+
});
|
|
556
|
+
}
|
|
334
557
|
|
|
335
558
|
// src/lib/httpClient.ts
|
|
336
559
|
var httpClient = class {
|
|
@@ -461,7 +684,7 @@ var ctx_default = (options) => {
|
|
|
461
684
|
process.exit();
|
|
462
685
|
}
|
|
463
686
|
for (let viewport of config.web.viewports)
|
|
464
|
-
viewports.push({ width: viewport[0], height: viewport[1] });
|
|
687
|
+
viewports.push({ width: viewport[0], height: viewport[1] || 0 });
|
|
465
688
|
return {
|
|
466
689
|
env,
|
|
467
690
|
log: logger_default,
|
|
@@ -629,7 +852,7 @@ var finalizeBuild_default = (ctx) => {
|
|
|
629
852
|
var command = new commander.Command();
|
|
630
853
|
command.name("exec").description("Run test commands around SmartUI").argument("<command...>", "Command supplied for running tests").action(function(execCommand, _, command3) {
|
|
631
854
|
return __async(this, null, function* () {
|
|
632
|
-
var _a;
|
|
855
|
+
var _a, _b;
|
|
633
856
|
let ctx = ctx_default(command3.optsWithGlobals());
|
|
634
857
|
if (!which__default.default.sync(execCommand[0], { nothrow: true })) {
|
|
635
858
|
console.log(`Error: Command not found "${execCommand[0]}"`);
|
|
@@ -663,6 +886,7 @@ command.name("exec").description("Run test commands around SmartUI").argument("<
|
|
|
663
886
|
console.log("\nRefer docs: https://www.lambdatest.com/support/docs/smart-visual-regression-testing/");
|
|
664
887
|
} finally {
|
|
665
888
|
yield (_a = ctx.server) == null ? void 0 : _a.close();
|
|
889
|
+
yield (_b = ctx.browser) == null ? void 0 : _b.close();
|
|
666
890
|
}
|
|
667
891
|
});
|
|
668
892
|
});
|
|
@@ -685,6 +909,7 @@ var BROWSER_FIREFOX = "firefox";
|
|
|
685
909
|
var BROWSER_EDGE = "edge";
|
|
686
910
|
var EDGE_CHANNEL = "msedge";
|
|
687
911
|
var PW_WEBKIT = "webkit";
|
|
912
|
+
var MIN_VIEWPORT_HEIGHT2 = 1080;
|
|
688
913
|
function captureScreenshots(ctx, screenshots) {
|
|
689
914
|
return __async(this, null, function* () {
|
|
690
915
|
var _a;
|
|
@@ -692,6 +917,7 @@ function captureScreenshots(ctx, screenshots) {
|
|
|
692
917
|
let totalBrowsers = ctx.webConfig.browsers.length;
|
|
693
918
|
let totalViewports = ctx.webConfig.viewports.length;
|
|
694
919
|
let totalScreenshots = screenshots.length;
|
|
920
|
+
let capturedScreenshots = 0;
|
|
695
921
|
for (let i = 0; i < totalBrowsers; i++) {
|
|
696
922
|
let browserName = (_a = ctx.webConfig.browsers[i]) == null ? void 0 : _a.toLowerCase();
|
|
697
923
|
let browser;
|
|
@@ -718,17 +944,25 @@ function captureScreenshots(ctx, screenshots) {
|
|
|
718
944
|
let screenshot = screenshots[j];
|
|
719
945
|
let screenshotId = screenshot.name.toLowerCase().replace(/\s/g, "-");
|
|
720
946
|
const page = yield context.newPage();
|
|
947
|
+
if (screenshot.url) {
|
|
948
|
+
screenshot.url = screenshot.url.trim();
|
|
949
|
+
screenshot.url = ensureHttps(screenshot.url);
|
|
950
|
+
}
|
|
721
951
|
yield page.goto(screenshot.url, pageOptions);
|
|
722
|
-
yield page.waitForTimeout(screenshot.waitForTimeout || 0);
|
|
723
952
|
for (let k = 0; k < totalViewports; k++) {
|
|
724
953
|
let { width, height } = ctx.webConfig.viewports[k];
|
|
725
954
|
let ssName = `${browserName}-${width}x${height}-${screenshotId}.png`;
|
|
726
955
|
let ssPath = `screenshots/${screenshotId}/${ssName}.png`;
|
|
727
|
-
yield page.setViewportSize({ width, height });
|
|
728
|
-
|
|
956
|
+
yield page.setViewportSize({ width, height: height || MIN_VIEWPORT_HEIGHT2 });
|
|
957
|
+
if (height === 0)
|
|
958
|
+
yield page.evaluate(scrollToBottomAndBackToTop);
|
|
959
|
+
yield page.waitForTimeout(screenshot.waitForTimeout || 0);
|
|
960
|
+
yield page.screenshot({ path: ssPath, fullPage: height ? false : true });
|
|
729
961
|
let completed = i == totalBrowsers - 1 && j == totalScreenshots - 1 && k == totalViewports - 1 ? true : false;
|
|
730
962
|
browserName = browserName === BROWSER_SAFARI ? PW_WEBKIT : browserName;
|
|
731
963
|
ctx.client.uploadScreenshot(ctx.build, ssPath, screenshot.name, browserName, `${width}x${height}`, completed);
|
|
964
|
+
capturedScreenshots++;
|
|
965
|
+
ctx.task.output = chalk__default.default.gray(`screenshots captured: ${capturedScreenshots}/${totalBrowsers * totalViewports * totalScreenshots}`);
|
|
732
966
|
}
|
|
733
967
|
yield page.close();
|
|
734
968
|
}
|
|
@@ -747,8 +981,8 @@ var captureScreenshots_default = (ctx) => {
|
|
|
747
981
|
title: "Capturing screenshots",
|
|
748
982
|
task: (ctx2, task) => __async(void 0, null, function* () {
|
|
749
983
|
try {
|
|
750
|
-
|
|
751
|
-
let totalScreenshots = yield captureScreenshots(ctx2,
|
|
984
|
+
ctx2.task = task;
|
|
985
|
+
let totalScreenshots = yield captureScreenshots(ctx2, ctx2.webStaticConfig);
|
|
752
986
|
task.title = "Screenshots captured successfully";
|
|
753
987
|
task.output = chalk__default.default.gray(`total screenshots: ${totalScreenshots}`);
|
|
754
988
|
} catch (error) {
|