@testim/testim-cli 3.254.0 → 3.255.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/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 +4 -4
- package/cliAgentMode.js +4 -3
- package/codim/codim-cli.js +10 -8
- package/commons/featureFlags.js +8 -0
- package/commons/httpRequest.js +5 -1
- package/commons/httpRequestCounters.js +21 -10
- package/commons/lazyRequire.js +4 -3
- package/commons/preloadTests.js +2 -2
- package/commons/prepareRunner.js +4 -2
- package/commons/prepareRunnerAndTestimStartUtils.js +40 -41
- package/commons/runnerFileCache.js +1 -1
- 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 +187 -444
- package/package.json +4 -3
- package/player/services/tabService.js +15 -1
- package/player/stepActions/locateStepAction.js +2 -0
- package/player/utils/imageCaptureUtils.js +81 -120
- package/player/webdriver.js +25 -22
- package/reports/junitReporter.js +6 -7
- package/reports/reporter.js +34 -39
- package/runOptions.d.ts +260 -0
- package/runOptions.js +53 -38
- package/runner.js +2 -1
- package/runners/ParallelWorkerManager.js +9 -10
- package/runners/TestPlanRunner.js +5 -9
- package/services/gridService.js +36 -40
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.255.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"npm": "8.19.2",
|
|
84
84
|
"object-hash": "3.0.0",
|
|
85
85
|
"ora": "5.4.1",
|
|
86
|
+
"p-limit": "4.0.0",
|
|
86
87
|
"p-retry": "4.6.2",
|
|
87
88
|
"pako": "1.0.11",
|
|
88
89
|
"portfinder": "1.0.28",
|
|
@@ -111,8 +112,8 @@
|
|
|
111
112
|
"testim": "cli.js"
|
|
112
113
|
},
|
|
113
114
|
"scripts": {
|
|
114
|
-
"test": "
|
|
115
|
-
"test:
|
|
115
|
+
"test": "yarn test:pattern './src/**/*.test.js'",
|
|
116
|
+
"test:pattern": "IS_UNIT_TEST=1 ../../node_modules/mocha/bin/_mocha --timeout 2000 --exit --recursive --exclude ./src/codim/template.js/tests/examples/**/*.test.js --watch-files 'src'",
|
|
116
117
|
"test:cov": "nyc --reporter=lcov --reporter=text yarn test",
|
|
117
118
|
"upload-bundle-s3": "ts-node-transpile-only scripts/upload.js",
|
|
118
119
|
"prepare-version": "rm -rf ./deploy && mkdir -p deploy && gulp prepare-version-on-prem",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const sessionPlayer = require('../../commons/getSessionPlayerRequire');
|
|
@@ -36,8 +38,20 @@ const logger = require('../../commons/logger').getLogger('tab-service');
|
|
|
36
38
|
* from: any;
|
|
37
39
|
* isMain: any;
|
|
38
40
|
* openerStepId: any;
|
|
41
|
+
* openerOriginalStepId?: any;
|
|
42
|
+
* isClosed?: boolean;
|
|
43
|
+
* currentUrl?: any;
|
|
44
|
+
* lastUpdatedUrl?: any;
|
|
39
45
|
* }} TabInfo
|
|
40
46
|
*/
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {{
|
|
49
|
+
* tabCount: number;
|
|
50
|
+
* tabInfos: Record<string, TabInfo>;
|
|
51
|
+
* lastActiveTabInfo?: any;
|
|
52
|
+
* currentTab?: any;
|
|
53
|
+
* }} SessionTab
|
|
54
|
+
*/
|
|
41
55
|
|
|
42
56
|
class TabService {
|
|
43
57
|
/** @param {import('../webdriver')} driver */
|
|
@@ -45,7 +59,7 @@ class TabService {
|
|
|
45
59
|
this.driver = driver;
|
|
46
60
|
/** @type {Record<string, TabUtil>} */
|
|
47
61
|
this._utils = {};
|
|
48
|
-
/** @type {Record<string,
|
|
62
|
+
/** @type {Record<string, SessionTab>} */
|
|
49
63
|
this.sessionTabs = {};
|
|
50
64
|
/** @type {Record<string, string>} */
|
|
51
65
|
this.pendingTabs = {};
|
|
@@ -33,6 +33,7 @@ function createUtils(driver) {
|
|
|
33
33
|
return Promise.resolve([frameHandler.frameOffset || {}]);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** @type {typeof import('clickim/src/background/stepActions/locateStepAction').LocateStepAction['htmlStringToDom']} */
|
|
36
37
|
static htmlStringToDom(htmlString, url, nonBodyElements, bodyTagName, setDomTimeout = true) {
|
|
37
38
|
const virtualConsole = new VirtualConsole();
|
|
38
39
|
const jsdom = new JSDOM(htmlString, {
|
|
@@ -74,6 +75,7 @@ function createUtils(driver) {
|
|
|
74
75
|
return true;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/** @type {typeof import('clickim/src/background/stepActions/locateStepAction').LocateStepAction['isVisible']} */
|
|
77
79
|
static isVisible(target, targetElement, rect, locateStep, frameHandler, allOffsets, dom) {
|
|
78
80
|
const skipVisibilityCheck =
|
|
79
81
|
featureFlags.flags.disableEdgeVisibilityChecks.isEnabled() && driver.isEdge();
|
|
@@ -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,27 @@ class RectIsOutsideOfImageError extends Error {
|
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @param {never} tabId
|
|
21
|
+
* @param {import('./windowUtils')} windowUtils
|
|
22
|
+
* @param {import('./screenshotUtils')} screenshotUtils
|
|
23
|
+
* */
|
|
16
24
|
const ImageCaptureUtils = function (tabId, windowUtils, screenshotUtils) {
|
|
17
25
|
this.windowUtils = windowUtils;
|
|
18
26
|
this.screenshotUtils = screenshotUtils;
|
|
19
27
|
};
|
|
20
28
|
|
|
21
|
-
function cropImageFromImageData(imageData, imageInfo) {
|
|
22
|
-
const
|
|
29
|
+
async function cropImageFromImageData(imageData, imageInfo) {
|
|
30
|
+
const _image = imageInfo.image || imageInfo;
|
|
23
31
|
const pixelRatio = imageInfo.devicePixelRatio;
|
|
24
32
|
|
|
25
|
-
if (!
|
|
26
|
-
|
|
33
|
+
if (!_image) {
|
|
34
|
+
throw new Error('Failed to get image');
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
const imageRegExMatch =
|
|
37
|
+
const imageRegExMatch = _image.match(/^data\:[^;]*\;base64,(.*)$/);
|
|
30
38
|
if (!imageRegExMatch) {
|
|
31
|
-
|
|
39
|
+
throw new Error('Image is not in base64 format');
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
// chromeCropImage2
|
|
@@ -39,102 +47,67 @@ function cropImageFromImageData(imageData, imageInfo) {
|
|
|
39
47
|
|
|
40
48
|
// elementImage
|
|
41
49
|
if (!imageData.elementRect) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return Promise.resolve({});
|
|
50
|
+
logger.warn('missing elementRect', _.omit(imageData, 'image'));
|
|
51
|
+
return {};
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
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
|
-
}
|
|
55
|
+
const image = await Jimp.read(Buffer.from(imageRegExMatch[1], 'base64'));
|
|
56
|
+
let x = elementRect.left * pixelRatio + offset.left * pixelRatio;
|
|
57
|
+
let y = elementRect.top * pixelRatio + offset.top * pixelRatio;
|
|
58
|
+
let width = elementRect.width * pixelRatio;
|
|
59
|
+
let height = elementRect.height * pixelRatio;
|
|
60
|
+
|
|
61
|
+
if (x < 0) {
|
|
62
|
+
width += x;
|
|
63
|
+
width = width < 0 ? 0 : width;
|
|
64
|
+
x = 0;
|
|
65
|
+
}
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
if (y < 0) {
|
|
68
|
+
height += y;
|
|
69
|
+
height = height < 0 ? 0 : height;
|
|
70
|
+
y = 0;
|
|
71
|
+
}
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
const imageWidth = image.bitmap.width;
|
|
74
|
+
const imageHeight = image.bitmap.height;
|
|
75
|
+
if ((x + width) > imageWidth) {
|
|
76
|
+
width = imageWidth - x;
|
|
77
|
+
}
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
if ((y + height) > imageHeight) {
|
|
80
|
+
height = imageHeight - y;
|
|
81
|
+
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
83
|
+
if (height <= 0 || width <= 0) {
|
|
84
|
+
throw new RectIsOutsideOfImageError('height or width is equal or lower than zero');
|
|
85
|
+
}
|
|
85
86
|
|
|
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
|
-
});
|
|
87
|
+
const cImage = image.crop(x, y, width, height);
|
|
88
|
+
const base64 = await cImage.getBase64Async(Jimp.MIME_PNG);
|
|
89
|
+
return { elementImage: base64 };
|
|
102
90
|
}
|
|
103
91
|
|
|
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
|
-
});
|
|
92
|
+
async function chromeStitchImage(fullSize, parts) {
|
|
93
|
+
const fullImage = await Jimp.read(fullSize.width, fullSize.height);
|
|
94
|
+
|
|
95
|
+
for (const part of parts) {
|
|
96
|
+
const imageRegExMatch = part.image.match(/^data\:[^;]*\;base64,(.*)$/);
|
|
97
|
+
const partImage = await Jimp.read(Buffer.from(imageRegExMatch[1], 'base64'));
|
|
98
|
+
// From the code or types doesn't seem like `fullImage.composite` has an async Promise API
|
|
99
|
+
await new Promise((resolve, reject) => {
|
|
100
|
+
fullImage.composite(partImage, part.position.left, part.position.top, (err) => {
|
|
101
|
+
if (err) {
|
|
102
|
+
reject(err);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
resolve();
|
|
135
106
|
});
|
|
136
|
-
})
|
|
137
|
-
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const base64 = await fullImage.getBase64Async(Jimp.MIME_PNG);
|
|
110
|
+
return base64;
|
|
138
111
|
}
|
|
139
112
|
|
|
140
113
|
function stitchImage(fullSize, parts) {
|
|
@@ -194,10 +167,8 @@ ImageCaptureUtils.prototype = {
|
|
|
194
167
|
return this.screenshotUtils.takeScreenshot(format)
|
|
195
168
|
.then((imageInfo) => cropImageFromImageData(areas, imageInfo).then((result) => {
|
|
196
169
|
result.screenImage = imageInfo.image;
|
|
197
|
-
result.absoluteScreenHighlight = getElementAbsoluteRectangle(
|
|
198
|
-
|
|
199
|
-
imageInfo.devicePixelRatio);
|
|
200
|
-
return Promise.resolve(result);
|
|
170
|
+
result.absoluteScreenHighlight = getElementAbsoluteRectangle(areas.elementRect, imageInfo.devicePixelRatio);
|
|
171
|
+
return result;
|
|
201
172
|
}));
|
|
202
173
|
},
|
|
203
174
|
|
|
@@ -211,10 +182,8 @@ ImageCaptureUtils.prototype = {
|
|
|
211
182
|
.then((imageInfo) => {
|
|
212
183
|
const result = {};
|
|
213
184
|
result.screenImage = imageInfo.image;
|
|
214
|
-
result.absoluteScreenHighlight = getElementAbsoluteRectangle(
|
|
215
|
-
|
|
216
|
-
imageInfo.devicePixelRatio);
|
|
217
|
-
return Promise.resolve(result);
|
|
185
|
+
result.absoluteScreenHighlight = getElementAbsoluteRectangle(areas.elementRect, imageInfo.devicePixelRatio);
|
|
186
|
+
return result;
|
|
218
187
|
}).then(uploadAllDataUrls);
|
|
219
188
|
},
|
|
220
189
|
|
|
@@ -226,14 +195,12 @@ ImageCaptureUtils.prototype = {
|
|
|
226
195
|
return this.screenshotUtils.getCurrentDevicePixelRatio();
|
|
227
196
|
},
|
|
228
197
|
|
|
229
|
-
takeStitchedDataUrl(useImprovedScreenshotStitching) {
|
|
198
|
+
async takeStitchedDataUrl(useImprovedScreenshotStitching) {
|
|
230
199
|
const windowUtil = this.windowUtils;
|
|
231
200
|
const getCurrentScrollPosition = windowUtil.getCurrentScrollPosition.bind(windowUtil);
|
|
232
201
|
|
|
233
202
|
const that = this;
|
|
234
|
-
const stabilize = () =>
|
|
235
|
-
setTimeout(resolve, 250);
|
|
236
|
-
});
|
|
203
|
+
const stabilize = () => utils.delay(250);
|
|
237
204
|
const usingImprovedStitching = Boolean(useImprovedScreenshotStitching);
|
|
238
205
|
const scroll = usingImprovedStitching ?
|
|
239
206
|
(pos) => windowUtil.scrollToPositionWithoutAnimation.bind(windowUtil)(pos) :
|
|
@@ -243,12 +210,7 @@ ImageCaptureUtils.prototype = {
|
|
|
243
210
|
return scroll(position)
|
|
244
211
|
.then(stabilize)
|
|
245
212
|
.then(() => that.screenshotUtils.takeScreenshot())
|
|
246
|
-
.then(imageInfo => {
|
|
247
|
-
const imageData = {
|
|
248
|
-
elementRect: crop,
|
|
249
|
-
};
|
|
250
|
-
return cropImageFromImageData(imageData, imageInfo);
|
|
251
|
-
})
|
|
213
|
+
.then(imageInfo => cropImageFromImageData({ elementRect: crop }, imageInfo))
|
|
252
214
|
.then(cropResult => ({
|
|
253
215
|
position: { left: position.x + crop.left, top: position.y + crop.top },
|
|
254
216
|
size: { width: crop.width, height: crop.height },
|
|
@@ -256,13 +218,13 @@ ImageCaptureUtils.prototype = {
|
|
|
256
218
|
}));
|
|
257
219
|
}
|
|
258
220
|
|
|
259
|
-
function takeAllParts(positionsData) {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
return
|
|
221
|
+
async function takeAllParts(positionsData) {
|
|
222
|
+
const allParts = [];
|
|
223
|
+
for (const nextPos of positionsData) {
|
|
224
|
+
const part = await createPart(nextPos.scrollPos, nextPos.cropData);
|
|
225
|
+
allParts.push(part);
|
|
226
|
+
}
|
|
227
|
+
return allParts;
|
|
266
228
|
}
|
|
267
229
|
|
|
268
230
|
function getPartsPositions(fullPageSize, viewPortSize) {
|
|
@@ -294,12 +256,11 @@ ImageCaptureUtils.prototype = {
|
|
|
294
256
|
const positions = getPartsPositions(fullPageSize, viewPortSize);
|
|
295
257
|
const parts = await takeAllParts(positions);
|
|
296
258
|
await windowUtil.scrollToPosition(originalPosition);
|
|
297
|
-
parts.shift();
|
|
298
259
|
return stitchImage(fullPageSize, parts);
|
|
299
260
|
}
|
|
300
261
|
|
|
301
|
-
|
|
302
|
-
|
|
262
|
+
const [fullPageSize, viewPortSize] = await Promise.all([windowUtil.getFullPageSize(), windowUtil.getViewportSize()]);
|
|
263
|
+
return await createStitchImage(fullPageSize, viewPortSize);
|
|
303
264
|
},
|
|
304
265
|
};
|
|
305
266
|
|
package/player/webdriver.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/* eslint-disable no-var */
|
|
1
|
+
/* eslint-disable arrow-body-style, no-shadow, @typescript-eslint/prefer-optional-chain, comma-spacing, no-empty, padded-blocks, semi, indent, unicorn/no-useless-promise-resolve-reject, default-param-last, comma-dangle, semi-style, consistent-return, radix, prefer-template, prefer-const, object-shorthand, no-trailing-spaces, operator-linebreak, no-else-return, unicorn/prefer-includes, prefer-arrow-callback, max-len, no-var */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
+
const _ = require('lodash');
|
|
5
6
|
const logger = require('../commons/logger').getLogger('webdriver');
|
|
6
|
-
const Promise = require('bluebird');
|
|
7
7
|
const parser = require('ua-parser-js');
|
|
8
8
|
const desiredCapabilitiesBuilder = require('../commons/testimDesiredCapabilitiesBuilder');
|
|
9
9
|
const { SeleniumError, SeleniumCrashError, IeError } = require('../errors');
|
|
@@ -13,7 +13,7 @@ const doubleClick = require('./stepActions/scripts/doubleClick');
|
|
|
13
13
|
const dispatchFocus = require('./stepActions/scripts/focusElement');
|
|
14
14
|
const { isOldProtocol } = require('./webDriverUtils');
|
|
15
15
|
const featureFlags = require('../commons/featureFlags');
|
|
16
|
-
const
|
|
16
|
+
const { W3C_ELEMENT_ID } = require('./constants');
|
|
17
17
|
|
|
18
18
|
const [LEFT, RIGHT] = [0, 2];
|
|
19
19
|
const { extractElementId, getCdpAddressForHost } = utils;
|
|
@@ -202,7 +202,8 @@ class WebDriver extends WebDriverApi {
|
|
|
202
202
|
switchToLocatedFrame(locatedElement) {
|
|
203
203
|
return this.getElement(locatedElement)
|
|
204
204
|
.then(async el => {
|
|
205
|
-
|
|
205
|
+
const elementId = extractElementId(el.value);
|
|
206
|
+
await this.switchToFrame({ ELEMENT: elementId, [W3C_ELEMENT_ID]: elementId });
|
|
206
207
|
return el;
|
|
207
208
|
});
|
|
208
209
|
}
|
|
@@ -213,7 +214,7 @@ class WebDriver extends WebDriverApi {
|
|
|
213
214
|
|
|
214
215
|
switchToTopFrame() {
|
|
215
216
|
return this.frame().catch(err => {
|
|
216
|
-
if (err.message
|
|
217
|
+
if (err.message?.includes('ECONNREFUSED')) {
|
|
217
218
|
throw new SeleniumCrashError();
|
|
218
219
|
}
|
|
219
220
|
throw err;
|
|
@@ -221,11 +222,11 @@ class WebDriver extends WebDriverApi {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
/**
|
|
224
|
-
* @returns {Promise<{ value: HTMLElement }>}
|
|
225
|
+
* @returns {Promise<{ value: HTMLElement | { [W3C_ELEMENT_ID]: string } | { ELEMENT: string } }>}
|
|
225
226
|
*/
|
|
226
227
|
getElement(locatedElement) {
|
|
227
228
|
const perfId = this.seleniumPerfStats.markStart(SELENIUM_PERF_MARKS.GET_ELEMENT);
|
|
228
|
-
if (typeof locatedElement === 'string' || typeof locatedElement === 'number') { // support testimId in the meanwhile for backwards
|
|
229
|
+
if (typeof locatedElement === 'string' || typeof locatedElement === 'number') { // support testimId in the meanwhile for backwards compatibility
|
|
229
230
|
return this.getElementBySelector(`[testim_dom_element_id='${locatedElement}']`)
|
|
230
231
|
.finally(() => this.seleniumPerfStats.markEnd(perfId, SELENIUM_PERF_MARKS.GET_ELEMENT));
|
|
231
232
|
}
|
|
@@ -452,10 +453,10 @@ class WebDriver extends WebDriverApi {
|
|
|
452
453
|
throw testimInternalError;
|
|
453
454
|
}
|
|
454
455
|
return this.executeJS('return navigator.userAgent;')
|
|
455
|
-
.catch(() =>
|
|
456
|
+
.catch(() => { throw testimInternalError; })
|
|
456
457
|
.then(ua => {
|
|
457
458
|
const error = this.isUsingUnsupportedCompabilityMode(ua.value) ? this.getIeError('Can’t run test in IE compatibility mode') : testimInternalError;
|
|
458
|
-
|
|
459
|
+
throw error;
|
|
459
460
|
});
|
|
460
461
|
});
|
|
461
462
|
}
|
|
@@ -586,7 +587,7 @@ class WebDriver extends WebDriverApi {
|
|
|
586
587
|
userAgent: rawUserAgent,
|
|
587
588
|
browserVersion: parse.browser.version
|
|
588
589
|
};
|
|
589
|
-
return
|
|
590
|
+
return this.browserAndOS;
|
|
590
591
|
});
|
|
591
592
|
}
|
|
592
593
|
|
|
@@ -690,7 +691,7 @@ class WebDriver extends WebDriverApi {
|
|
|
690
691
|
this.unsupportedActions.move = true;
|
|
691
692
|
return this.rightClickWithActionsAPI(element, offsets);
|
|
692
693
|
}
|
|
693
|
-
|
|
694
|
+
throw err;
|
|
694
695
|
});
|
|
695
696
|
}
|
|
696
697
|
|
|
@@ -704,7 +705,7 @@ class WebDriver extends WebDriverApi {
|
|
|
704
705
|
this.unsupportedActions.move = true;
|
|
705
706
|
return this.leftClickWithActionsAPI(element, offsets);
|
|
706
707
|
}
|
|
707
|
-
|
|
708
|
+
throw err;
|
|
708
709
|
});
|
|
709
710
|
}
|
|
710
711
|
|
|
@@ -826,7 +827,7 @@ class WebDriver extends WebDriverApi {
|
|
|
826
827
|
this.unsupportedActions.move = true;
|
|
827
828
|
return this.dragWithActionsAPI(seleniumElement, xDiff, yDiff, midXRelative, midYRelative);
|
|
828
829
|
}
|
|
829
|
-
|
|
830
|
+
throw err;
|
|
830
831
|
});
|
|
831
832
|
});
|
|
832
833
|
}
|
|
@@ -857,15 +858,17 @@ class WebDriver extends WebDriverApi {
|
|
|
857
858
|
}, [{ x: Math.round(startLeft), y: Math.round(startTop) }]);
|
|
858
859
|
}
|
|
859
860
|
|
|
860
|
-
dragAndDropWithGeneratedMoves(sourceSeleniumElement, destinationSeleniumElement, rectsAndOffsets) {
|
|
861
|
+
async dragAndDropWithGeneratedMoves(sourceSeleniumElement, destinationSeleniumElement, rectsAndOffsets) {
|
|
861
862
|
const { fromRect, fromX, fromY, toRect, toX, toY } = rectsAndOffsets;
|
|
862
863
|
const moveSequence = this.getMoveRelativeSequence(fromRect.left + fromX, fromRect.top + fromY, toRect.left + toX, toRect.top + toY);
|
|
863
864
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
865
|
+
await this.moveTo(extractElementId(sourceSeleniumElement), Math.round(fromX), Math.round(fromY));
|
|
866
|
+
await this.buttonDown();
|
|
867
|
+
for (const movePosition of moveSequence) {
|
|
868
|
+
await this.moveTo(null, movePosition.x, movePosition.y);
|
|
869
|
+
}
|
|
870
|
+
await this.moveTo(extractElementId(destinationSeleniumElement), Math.round(toX), Math.round(toY));
|
|
871
|
+
return await this.buttonUp();
|
|
869
872
|
}
|
|
870
873
|
|
|
871
874
|
dragAndDropWithActionsAPIWithGeneratedMoves(rectsAndOffsets) {
|
|
@@ -900,7 +903,7 @@ class WebDriver extends WebDriverApi {
|
|
|
900
903
|
this.unsupportedActions.move = true;
|
|
901
904
|
return this.dragAndDropWithActionsAPIWithGeneratedMoves(rectsAndOffsets);
|
|
902
905
|
}
|
|
903
|
-
|
|
906
|
+
throw err;
|
|
904
907
|
});
|
|
905
908
|
}
|
|
906
909
|
if (this.unsupportedActions.move) {
|
|
@@ -912,7 +915,7 @@ class WebDriver extends WebDriverApi {
|
|
|
912
915
|
this.unsupportedActions.move = true;
|
|
913
916
|
return this.dragAndDropWithActionsAPI(rectsAndOffsets);
|
|
914
917
|
}
|
|
915
|
-
|
|
918
|
+
throw err;
|
|
916
919
|
});
|
|
917
920
|
}
|
|
918
921
|
|
|
@@ -934,7 +937,7 @@ class WebDriver extends WebDriverApi {
|
|
|
934
937
|
this.unsupportedActions.move = true;
|
|
935
938
|
return this.doubleClickFallback(element, eventData, offsets);
|
|
936
939
|
}
|
|
937
|
-
|
|
940
|
+
throw err;
|
|
938
941
|
});
|
|
939
942
|
}
|
|
940
943
|
|
package/reports/junitReporter.js
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
5
|
const xml2js = require('xml2js');
|
|
6
|
-
const
|
|
7
|
-
const fs = Promise.promisifyAll(require('fs'));
|
|
6
|
+
const fsPromises = require('fs/promises');
|
|
8
7
|
const utils = require('../utils');
|
|
9
8
|
const {
|
|
10
9
|
isAbortedTest, isSkippedTest, getFailedTests, isFailedTest, getFailureEvaluatingCount, getSkippedCount, getAbortedTests,
|
|
@@ -34,7 +33,7 @@ class JunitReporter {
|
|
|
34
33
|
return undefined;
|
|
35
34
|
}
|
|
36
35
|
try {
|
|
37
|
-
await
|
|
36
|
+
await fsPromises.writeFile(reportFile, reportText);
|
|
38
37
|
console.log('JUnit XML file saved to', reportFile);
|
|
39
38
|
return testResults;
|
|
40
39
|
} catch (err) {
|
|
@@ -55,7 +54,7 @@ function getPrintName(testResult) {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
async function report(editorUrl, testPlanResults, projectId, branch, classname, options) {
|
|
58
|
-
function createTestCaseObject(testResult
|
|
57
|
+
function createTestCaseObject(testResult) {
|
|
59
58
|
const testResultUrl = utils.getTestUrl(editorUrl, projectId, testResult.testId, testResult.resultId, branch);
|
|
60
59
|
const testResultObject = {
|
|
61
60
|
$: {
|
|
@@ -102,7 +101,7 @@ async function report(editorUrl, testPlanResults, projectId, branch, classname,
|
|
|
102
101
|
}
|
|
103
102
|
return {
|
|
104
103
|
$: testSuiteAttributes,
|
|
105
|
-
testcase: Object.keys(testResults).map(resultId => createTestCaseObject(testResults[resultId]
|
|
104
|
+
testcase: Object.keys(testResults).map(resultId => createTestCaseObject(testResults[resultId])),
|
|
106
105
|
};
|
|
107
106
|
}
|
|
108
107
|
|
|
@@ -130,9 +129,9 @@ async function report(editorUrl, testPlanResults, projectId, branch, classname,
|
|
|
130
129
|
try {
|
|
131
130
|
const builder = new xml2js.Builder();
|
|
132
131
|
const jUnitXmlReporter = builder.buildObject(testResultObject);
|
|
133
|
-
return
|
|
132
|
+
return jUnitXmlReporter;
|
|
134
133
|
} catch (err) {
|
|
135
|
-
return
|
|
134
|
+
return createErrorjUnitReporter(err);
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
137
|
|