@testim/testim-cli 3.254.0 → 3.256.0
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/agent/routers/cliJsCode/service.js +11 -8
- package/agent/routers/codim/router.test.js +9 -12
- package/agent/routers/codim/service.js +16 -16
- package/agent/routers/playground/service.js +5 -7
- package/cli.js +6 -6
- package/cliAgentMode.js +11 -10
- package/codim/codim-cli.js +14 -9
- package/commons/featureFlags.js +29 -7
- package/commons/httpRequest.js +5 -1
- package/commons/httpRequestCounters.js +21 -10
- package/commons/initializeUserWithAuth.js +7 -4
- package/commons/lazyRequire.js +4 -3
- package/commons/preloadTests.js +6 -3
- package/commons/prepareRunner.js +7 -5
- package/commons/prepareRunnerAndTestimStartUtils.js +51 -45
- package/commons/runnerFileCache.js +10 -2
- package/commons/testimServicesApi.js +36 -5
- package/commons/testimTunnel.test.js +2 -1
- package/coverage/SummaryToObjectReport.js +0 -1
- package/coverage/jsCoverage.js +12 -10
- package/inputFileUtils.js +11 -9
- package/npm-shrinkwrap.json +214 -471
- package/package.json +4 -3
- package/player/services/tabService.js +15 -1
- package/player/stepActions/apiStepAction.js +49 -43
- package/player/stepActions/baseCliJsStepAction.js +19 -14
- package/player/stepActions/baseJsStepAction.js +9 -8
- package/player/stepActions/dropFileStepAction.js +1 -3
- package/player/stepActions/inputFileStepAction.js +10 -8
- package/player/stepActions/locateStepAction.js +2 -0
- package/player/stepActions/mouseStepAction.js +21 -22
- package/player/stepActions/nodePackageStepAction.js +34 -35
- package/player/stepActions/stepAction.js +1 -0
- package/player/utils/imageCaptureUtils.js +133 -172
- package/player/utils/screenshotUtils.js +16 -13
- package/player/utils/windowUtils.js +20 -8
- package/player/webdriver.js +25 -22
- package/processHandler.js +4 -0
- package/reports/junitReporter.js +6 -7
- package/reports/reporter.js +34 -39
- package/runOptions.d.ts +286 -0
- package/runOptions.js +60 -45
- package/runner.js +64 -24
- package/runners/ParallelWorkerManager.js +12 -12
- package/runners/TestPlanRunner.js +14 -15
- package/runners/buildCodeTests.js +1 -0
- package/runners/runnerUtils.js +11 -2
- package/services/branchService.js +11 -5
- package/services/gridService.js +36 -40
- package/services/localRCASaver.js +4 -0
- package/testRunStatus.js +8 -5
- package/utils/argsUtils.js +86 -0
- package/utils/argsUtils.test.js +32 -0
- package/utils/fsUtils.js +154 -0
- package/utils/index.js +10 -161
- package/utils/promiseUtils.js +13 -2
- package/utils/stringUtils.js +4 -2
- package/utils/stringUtils.test.js +22 -0
- package/utils/timeUtils.js +25 -0
- package/utils/utils.test.js +0 -41
- package/workers/WorkerExtension.js +6 -7
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
|
-
const
|
|
5
|
+
const _ = require('lodash');
|
|
4
6
|
const Jimp = require('jimp');
|
|
7
|
+
const utils = require('../../utils');
|
|
5
8
|
|
|
6
9
|
const logger = require('../../commons/logger').getLogger('image-capture-utils');
|
|
7
10
|
|
|
@@ -13,22 +16,17 @@ class RectIsOutsideOfImageError extends Error {
|
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.screenshotUtils = screenshotUtils;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function cropImageFromImageData(imageData, imageInfo) {
|
|
22
|
-
const image = imageInfo.image || imageInfo;
|
|
19
|
+
async function cropImageFromImageData(imageData, imageInfo) {
|
|
20
|
+
const _image = imageInfo.image || imageInfo;
|
|
23
21
|
const pixelRatio = imageInfo.devicePixelRatio;
|
|
24
22
|
|
|
25
|
-
if (!
|
|
26
|
-
|
|
23
|
+
if (!_image) {
|
|
24
|
+
throw new Error('Failed to get image');
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
const imageRegExMatch =
|
|
27
|
+
const imageRegExMatch = _image.match(/^data\:[^;]*\;base64,(.*)$/);
|
|
30
28
|
if (!imageRegExMatch) {
|
|
31
|
-
|
|
29
|
+
throw new Error('Image is not in base64 format');
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
// chromeCropImage2
|
|
@@ -39,108 +37,74 @@ function cropImageFromImageData(imageData, imageInfo) {
|
|
|
39
37
|
|
|
40
38
|
// elementImage
|
|
41
39
|
if (!imageData.elementRect) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return Promise.resolve({});
|
|
40
|
+
logger.warn('missing elementRect', _.omit(imageData, 'image'));
|
|
41
|
+
return {};
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
const { elementRect } = imageData;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (x < 0) {
|
|
60
|
-
width += x;
|
|
61
|
-
width = width < 0 ? 0 : width;
|
|
62
|
-
x = 0;
|
|
63
|
-
}
|
|
45
|
+
const image = await Jimp.read(Buffer.from(imageRegExMatch[1], 'base64'));
|
|
46
|
+
let x = elementRect.left * pixelRatio + offset.left * pixelRatio;
|
|
47
|
+
let y = elementRect.top * pixelRatio + offset.top * pixelRatio;
|
|
48
|
+
let width = elementRect.width * pixelRatio;
|
|
49
|
+
let height = elementRect.height * pixelRatio;
|
|
50
|
+
|
|
51
|
+
if (x < 0) {
|
|
52
|
+
width += x;
|
|
53
|
+
width = width < 0 ? 0 : width;
|
|
54
|
+
x = 0;
|
|
55
|
+
}
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
if (y < 0) {
|
|
58
|
+
height += y;
|
|
59
|
+
height = height < 0 ? 0 : height;
|
|
60
|
+
y = 0;
|
|
61
|
+
}
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
63
|
+
const imageWidth = image.bitmap.width;
|
|
64
|
+
const imageHeight = image.bitmap.height;
|
|
65
|
+
if ((x + width) > imageWidth) {
|
|
66
|
+
width = imageWidth - x;
|
|
67
|
+
}
|
|
76
68
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
if ((y + height) > imageHeight) {
|
|
70
|
+
height = imageHeight - y;
|
|
71
|
+
}
|
|
80
72
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
73
|
+
if (height <= 0 || width <= 0) {
|
|
74
|
+
throw new RectIsOutsideOfImageError('height or width is equal or lower than zero');
|
|
75
|
+
}
|
|
85
76
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return reject(err);
|
|
90
|
-
}
|
|
91
|
-
resolve({
|
|
92
|
-
elementImage: base64,
|
|
93
|
-
});
|
|
94
|
-
return undefined;
|
|
95
|
-
});
|
|
96
|
-
return undefined;
|
|
97
|
-
} catch (err) {
|
|
98
|
-
return reject(err);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
});
|
|
77
|
+
const cImage = image.crop(x, y, width, height);
|
|
78
|
+
const base64 = await cImage.getBase64Async(Jimp.MIME_PNG);
|
|
79
|
+
return { elementImage: base64 };
|
|
102
80
|
}
|
|
103
81
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
fullImage.composite(partImage, part.position.left, part.position.top, (err, image) => {
|
|
119
|
-
if (err) {
|
|
120
|
-
return reject(err);
|
|
121
|
-
}
|
|
122
|
-
resolve(image);
|
|
123
|
-
return undefined;
|
|
124
|
-
});
|
|
125
|
-
return undefined;
|
|
126
|
-
});
|
|
127
|
-
})).then(() => {
|
|
128
|
-
fullImage.getBase64(Jimp.MIME_PNG, (err, base64) => {
|
|
129
|
-
if (err) {
|
|
130
|
-
return reject(err);
|
|
131
|
-
}
|
|
132
|
-
resolve(base64);
|
|
133
|
-
return undefined;
|
|
134
|
-
});
|
|
82
|
+
async function chromeStitchImage(fullSize, parts) {
|
|
83
|
+
const fullImage = await Jimp.read(fullSize.width, fullSize.height);
|
|
84
|
+
|
|
85
|
+
for (const part of parts) {
|
|
86
|
+
const imageRegExMatch = part.image.match(/^data\:[^;]*\;base64,(.*)$/);
|
|
87
|
+
const partImage = await Jimp.read(Buffer.from(imageRegExMatch[1], 'base64'));
|
|
88
|
+
// From the code or types doesn't seem like `fullImage.composite` has an async Promise API
|
|
89
|
+
await new Promise((resolve, reject) => {
|
|
90
|
+
fullImage.composite(partImage, part.position.left, part.position.top, (err) => {
|
|
91
|
+
if (err) {
|
|
92
|
+
reject(err);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
resolve();
|
|
135
96
|
});
|
|
136
|
-
})
|
|
137
|
-
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const base64 = await fullImage.getBase64Async(Jimp.MIME_PNG);
|
|
100
|
+
return base64;
|
|
138
101
|
}
|
|
139
102
|
|
|
140
103
|
function stitchImage(fullSize, parts) {
|
|
141
104
|
return chromeStitchImage(fullSize, parts);
|
|
142
105
|
}
|
|
143
106
|
|
|
107
|
+
// ???????????
|
|
144
108
|
function uploadDataUrl() {
|
|
145
109
|
return Promise.resolve();
|
|
146
110
|
}
|
|
@@ -175,94 +139,89 @@ function getElementAbsoluteRectangle(elementRect, pixelRatio) {
|
|
|
175
139
|
};
|
|
176
140
|
}
|
|
177
141
|
|
|
178
|
-
ImageCaptureUtils
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
142
|
+
class ImageCaptureUtils {
|
|
143
|
+
/**
|
|
144
|
+
* @param {unknown} _unusedId
|
|
145
|
+
* @param {import('./windowUtils')} windowUtils
|
|
146
|
+
* @param {import('./screenshotUtils')} screenshotUtils
|
|
147
|
+
* */
|
|
148
|
+
constructor(_unusedId, windowUtils, screenshotUtils) {
|
|
149
|
+
this.windowUtils = windowUtils;
|
|
150
|
+
this.screenshotUtils = screenshotUtils;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async takeViewPortImage() {
|
|
154
|
+
const imageInfo = await this.screenshotUtils.takeScreenshot();
|
|
155
|
+
return ((typeof imageInfo === 'string') ? imageInfo : imageInfo.image);
|
|
156
|
+
}
|
|
183
157
|
|
|
184
158
|
takeImageForComparison() {
|
|
185
159
|
return this.takeViewPortImage();
|
|
186
|
-
}
|
|
160
|
+
}
|
|
187
161
|
|
|
188
|
-
takeAreaDataUrl(areas, format) {
|
|
162
|
+
async takeAreaDataUrl(areas, format) {
|
|
189
163
|
// Future changes in clickim will pass parameters to this function as a single object
|
|
190
164
|
if (areas.areas) {
|
|
191
165
|
areas = areas.areas;
|
|
192
166
|
}
|
|
193
167
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return Promise.resolve(result);
|
|
201
|
-
}));
|
|
202
|
-
},
|
|
168
|
+
const imageInfo = await this.screenshotUtils.takeScreenshot(format);
|
|
169
|
+
const result = await cropImageFromImageData(areas, imageInfo);
|
|
170
|
+
result.screenImage = imageInfo.image;
|
|
171
|
+
result.absoluteScreenHighlight = getElementAbsoluteRectangle(areas.elementRect, imageInfo.devicePixelRatio);
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
203
174
|
|
|
204
|
-
takeArea(areas) {
|
|
175
|
+
async takeArea(areas) {
|
|
205
176
|
// Future changes in clickim will pass parameters to this function as a single object
|
|
206
177
|
if (areas.areas) {
|
|
207
178
|
areas = areas.areas;
|
|
208
179
|
}
|
|
209
180
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
imageInfo.devicePixelRatio);
|
|
217
|
-
return Promise.resolve(result);
|
|
218
|
-
}).then(uploadAllDataUrls);
|
|
219
|
-
},
|
|
181
|
+
const imageInfo = await this.screenshotUtils.takeScreenshot();
|
|
182
|
+
return uploadAllDataUrls({
|
|
183
|
+
screenImage: imageInfo.image,
|
|
184
|
+
absoluteScreenHighlight: getElementAbsoluteRectangle(areas.elementRect, imageInfo.devicePixelRatio),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
220
187
|
|
|
221
188
|
forcePixelRatio(forceRatio) {
|
|
222
189
|
return this.screenshotUtils.forcePixelRatio(forceRatio);
|
|
223
|
-
}
|
|
190
|
+
}
|
|
224
191
|
|
|
225
192
|
getCurrentDevicePixelRatio() {
|
|
226
193
|
return this.screenshotUtils.getCurrentDevicePixelRatio();
|
|
227
|
-
}
|
|
194
|
+
}
|
|
228
195
|
|
|
229
|
-
takeStitchedDataUrl(useImprovedScreenshotStitching) {
|
|
230
|
-
const
|
|
231
|
-
const getCurrentScrollPosition = windowUtil.getCurrentScrollPosition.bind(windowUtil);
|
|
196
|
+
async takeStitchedDataUrl(useImprovedScreenshotStitching) {
|
|
197
|
+
const { windowUtils, screenshotUtils } = this;
|
|
232
198
|
|
|
233
|
-
const
|
|
234
|
-
const stabilize = () => new Promise(resolve => {
|
|
235
|
-
setTimeout(resolve, 250);
|
|
236
|
-
});
|
|
199
|
+
const stabilize = () => utils.delay(250);
|
|
237
200
|
const usingImprovedStitching = Boolean(useImprovedScreenshotStitching);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
position: { left: position.x + crop.left, top: position.y + crop.top },
|
|
254
|
-
size: { width: crop.width, height: crop.height },
|
|
255
|
-
image: cropResult.elementImage,
|
|
256
|
-
}));
|
|
201
|
+
|
|
202
|
+
async function createPart(position, crop) {
|
|
203
|
+
if (usingImprovedStitching) {
|
|
204
|
+
await windowUtils.scrollToPositionWithoutAnimation(position);
|
|
205
|
+
} else {
|
|
206
|
+
await windowUtils.scrollToPosition(position);
|
|
207
|
+
}
|
|
208
|
+
await stabilize();
|
|
209
|
+
const imageInfo = await screenshotUtils.takeScreenshot();
|
|
210
|
+
const cropResult = await cropImageFromImageData({ elementRect: crop }, imageInfo);
|
|
211
|
+
return ({
|
|
212
|
+
position: { left: position.x + crop.left, top: position.y + crop.top },
|
|
213
|
+
size: { width: crop.width, height: crop.height },
|
|
214
|
+
image: cropResult.elementImage,
|
|
215
|
+
});
|
|
257
216
|
}
|
|
258
217
|
|
|
259
|
-
function takeAllParts(positionsData) {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
return
|
|
218
|
+
async function takeAllParts(positionsData) {
|
|
219
|
+
const allParts = [];
|
|
220
|
+
for (const nextPos of positionsData) {
|
|
221
|
+
const part = await createPart(nextPos.scrollPos, nextPos.cropData);
|
|
222
|
+
allParts.push(part);
|
|
223
|
+
}
|
|
224
|
+
return allParts;
|
|
266
225
|
}
|
|
267
226
|
|
|
268
227
|
function getPartsPositions(fullPageSize, viewPortSize) {
|
|
@@ -270,37 +229,39 @@ ImageCaptureUtils.prototype = {
|
|
|
270
229
|
const VPW = viewPortSize.width;
|
|
271
230
|
const FPH = Math.max(fullPageSize.height, viewPortSize.height);
|
|
272
231
|
const VPH = viewPortSize.height;
|
|
273
|
-
const Ws =
|
|
232
|
+
const Ws = Array.from({ length: Math.ceil(FPW / VPW) }, (__, i) => ({
|
|
274
233
|
scrollX: Math.min(i * VPW, FPW - VPW),
|
|
275
234
|
cropX: i * VPW - Math.min(i * VPW, FPW - VPW),
|
|
276
235
|
cropW: VPW - (i * VPW - Math.min(i * VPW, FPW - VPW)),
|
|
277
236
|
}));
|
|
278
|
-
const Hs =
|
|
237
|
+
const Hs = Array.from({ length: Math.ceil(FPH / VPH) }, (__, i) => ({
|
|
279
238
|
scrollY: Math.min(i * VPH, FPH - VPH),
|
|
280
239
|
cropY: i * VPH - Math.min(i * VPH, FPH - VPH),
|
|
281
240
|
cropH: VPH - (i * VPH - Math.min(i * VPH, FPH - VPH)),
|
|
282
241
|
}));
|
|
283
|
-
|
|
242
|
+
return Ws.flatMap(w => Hs.map(h => ({
|
|
284
243
|
scrollPos: { x: w.scrollX, y: h.scrollY },
|
|
285
244
|
cropData: {
|
|
286
|
-
top: h.cropY,
|
|
245
|
+
top: h.cropY,
|
|
246
|
+
left: w.cropX,
|
|
247
|
+
width: w.cropW,
|
|
248
|
+
height: h.cropH,
|
|
287
249
|
},
|
|
288
|
-
}))
|
|
289
|
-
|
|
250
|
+
}))
|
|
251
|
+
);
|
|
290
252
|
}
|
|
291
253
|
|
|
292
254
|
async function createStitchImage(fullPageSize, viewPortSize) {
|
|
293
|
-
const originalPosition = await getCurrentScrollPosition();
|
|
255
|
+
const originalPosition = await windowUtils.getCurrentScrollPosition();
|
|
294
256
|
const positions = getPartsPositions(fullPageSize, viewPortSize);
|
|
295
257
|
const parts = await takeAllParts(positions);
|
|
296
|
-
await
|
|
297
|
-
parts.shift();
|
|
258
|
+
await windowUtils.scrollToPosition(originalPosition);
|
|
298
259
|
return stitchImage(fullPageSize, parts);
|
|
299
260
|
}
|
|
300
261
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
}
|
|
262
|
+
const [fullPageSize, viewPortSize] = await Promise.all([windowUtils.getFullPageSize(), windowUtils.getViewportSize()]);
|
|
263
|
+
return await createStitchImage(fullPageSize, viewPortSize);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
305
266
|
|
|
306
267
|
module.exports = ImageCaptureUtils;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const Promise = require('bluebird');
|
|
4
6
|
const pRetry = require('p-retry');
|
|
5
7
|
|
|
6
8
|
class ScreenshotUtils {
|
|
9
|
+
/**
|
|
10
|
+
* @param {any} tabId
|
|
11
|
+
* @param {import('../webdriver')} driver
|
|
12
|
+
*/
|
|
7
13
|
constructor(tabId, driver, options = { takeScreenshots: true }) {
|
|
8
14
|
this.tabId = tabId;
|
|
9
15
|
this.driver = driver;
|
|
@@ -21,23 +27,21 @@ class ScreenshotUtils {
|
|
|
21
27
|
return this.options.takeScreenshots;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
takeScreenshot() {
|
|
30
|
+
async takeScreenshot() {
|
|
25
31
|
if (!this.shouldTakeScreenshots()) {
|
|
26
|
-
return
|
|
32
|
+
return { devicePixelRatio: 1, image: '' };
|
|
27
33
|
}
|
|
28
34
|
const MAX_RETRY_COUNT = 3;
|
|
29
35
|
const SCREENSHOT_RETRY_DELAY = 2000;
|
|
30
36
|
const devicePixelRatioPromise = this.currentDevicePixelRatio ? Promise.resolve(this.currentDevicePixelRatio) : this.getDevicePixelRatio();
|
|
31
37
|
const getScreenshot = () => Promise.all([devicePixelRatioPromise, this.driver.takeScreenshot()]);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
40
|
-
});
|
|
38
|
+
const [devicePixelRatio, image] = await pRetry(getScreenshot, { retries: MAX_RETRY_COUNT, minTimeout: SCREENSHOT_RETRY_DELAY });
|
|
39
|
+
const base64 = image ? image.value : '';
|
|
40
|
+
const dataUrl = `data:image/png;base64,${this.base64AddPadding(base64.replace(/[\r\n]/g, ''))}`;
|
|
41
|
+
return {
|
|
42
|
+
image: dataUrl,
|
|
43
|
+
devicePixelRatio,
|
|
44
|
+
};
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
getDevicePixelRatio() {
|
|
@@ -49,7 +53,7 @@ class ScreenshotUtils {
|
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
return this.driver.executeJS(devicePixelRatioJS).then(result =>
|
|
56
|
+
return this.driver.executeJS(devicePixelRatioJS).then(result => result.value);
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
forcePixelRatio(forceRatio = 1) {
|
|
@@ -63,4 +67,3 @@ class ScreenshotUtils {
|
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
module.exports = ScreenshotUtils;
|
|
66
|
-
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const Promise = require('bluebird');
|
|
@@ -7,6 +9,10 @@ const { PageNotAvailableError } = require('../../errors');
|
|
|
7
9
|
const logger = require('../../commons/logger').getLogger('window-utils');
|
|
8
10
|
|
|
9
11
|
class WindowUtils {
|
|
12
|
+
/**
|
|
13
|
+
* @param {number} id tab or worker id
|
|
14
|
+
* @param {import('../webdriver')} driver
|
|
15
|
+
* */
|
|
10
16
|
constructor(id, driver) {
|
|
11
17
|
this.id = id;
|
|
12
18
|
this.driver = driver;
|
|
@@ -131,12 +137,12 @@ class WindowUtils {
|
|
|
131
137
|
});
|
|
132
138
|
}
|
|
133
139
|
|
|
134
|
-
setViewportSize(size) {
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
async setViewportSize(size) {
|
|
141
|
+
await this.driver.setViewportSize(size.width, size.height);
|
|
142
|
+
return await this.checkSize(size);
|
|
137
143
|
}
|
|
138
144
|
|
|
139
|
-
validatePageIsAvailable() {
|
|
145
|
+
async validatePageIsAvailable() {
|
|
140
146
|
/* eslint-disable */
|
|
141
147
|
function pageIsAvailable() {
|
|
142
148
|
var locationObj;
|
|
@@ -153,7 +159,8 @@ class WindowUtils {
|
|
|
153
159
|
}
|
|
154
160
|
/* eslint-enable */
|
|
155
161
|
|
|
156
|
-
|
|
162
|
+
const result = await this.driver.executeJS(pageIsAvailable);
|
|
163
|
+
return await (result.value ? Promise.resolve() : Promise.reject(new PageNotAvailableError()));
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
focusTab() {
|
|
@@ -164,9 +171,14 @@ class WindowUtils {
|
|
|
164
171
|
return undefined;
|
|
165
172
|
}
|
|
166
173
|
|
|
167
|
-
getOsAndBrowser() {
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
async getOsAndBrowser() {
|
|
175
|
+
const osAndBrowser = await pRetry(() => this.driver.getBrowserAndOS(), { retries: 3 });
|
|
176
|
+
return {
|
|
177
|
+
uaBrowserName: osAndBrowser.browser,
|
|
178
|
+
uaOs: osAndBrowser.os,
|
|
179
|
+
userAgent: osAndBrowser.userAgent,
|
|
180
|
+
browserVersion: osAndBrowser.browserVersion,
|
|
181
|
+
};
|
|
170
182
|
}
|
|
171
183
|
|
|
172
184
|
getUserAgentInfo() {
|