@testim/testim-cli 3.226.0 → 3.229.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/codim/codim-npm-package/package.json +1 -1
- package/codim/template.js/package.json +1 -1
- package/codim/template.ts/package.json +2 -2
- package/commons/testimDesiredCapabilitiesBuilder.js +1 -0
- package/npm-shrinkwrap.json +1189 -1764
- package/package.json +22 -22
- package/player/stepActions/inputFileStepAction.js +78 -56
- package/services/gridService.js +1 -19
- package/testRunHandler.js +491 -486
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.229.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@types/bluebird": "3.5.32",
|
|
15
|
-
"@types/fs-extra": "
|
|
15
|
+
"@types/fs-extra": "9.0.13",
|
|
16
16
|
"@types/ms": "0.7.31",
|
|
17
17
|
"@types/node": "10.17.24",
|
|
18
18
|
"@types/selenium-webdriver": "4.0.9",
|
|
19
19
|
"bundle-deps": "1.0.0",
|
|
20
|
-
"chai": "4.3.
|
|
20
|
+
"chai": "4.3.6",
|
|
21
21
|
"chai-as-promised": "7.1.1",
|
|
22
22
|
"gulp": "4.0.2",
|
|
23
23
|
"gulp-cli": "2.3.0",
|
|
24
|
-
"gulp-json-editor": "2.5.
|
|
24
|
+
"gulp-json-editor": "2.5.6",
|
|
25
25
|
"gulp-preprocess": "3.0.3",
|
|
26
26
|
"merge-stream": "2.0.0",
|
|
27
27
|
"mocha": "9.2.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"sinon-chai": "3.7.0",
|
|
33
33
|
"ts-node": "9.1.1",
|
|
34
34
|
"tsconfig-paths": "3.12.0",
|
|
35
|
-
"typescript": "4.
|
|
35
|
+
"typescript": "4.6.2"
|
|
36
36
|
},
|
|
37
37
|
"lazyDependencies": {
|
|
38
38
|
"ngrok": "3.4.0",
|
|
@@ -44,40 +44,40 @@
|
|
|
44
44
|
"istanbul-lib-coverage": "3.0.0",
|
|
45
45
|
"@bcoe/v8-coverage": "0.2.3",
|
|
46
46
|
"convert-source-map": "1.7.0",
|
|
47
|
-
"multer": "1.4.
|
|
47
|
+
"multer": "1.4.4"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@applitools/eyes-sdk-core": "13.0.
|
|
51
|
-
"@applitools/visual-grid-client": "15.
|
|
50
|
+
"@applitools/eyes-sdk-core": "13.0.6",
|
|
51
|
+
"@applitools/visual-grid-client": "15.9.0",
|
|
52
52
|
"@testim/coralogix-logger": "1.1.27-beta.1",
|
|
53
53
|
"@testim/webdriverio": "0.0.5",
|
|
54
54
|
"abort-controller": "3.0.0",
|
|
55
55
|
"ajv": "6.12.6",
|
|
56
56
|
"analytics-node": "5.0.0",
|
|
57
57
|
"appium-dom-utils": "1.0.6",
|
|
58
|
-
"archiver": "3.
|
|
58
|
+
"archiver": "5.3.0",
|
|
59
59
|
"bluebird": "3.7.2",
|
|
60
60
|
"bluebird-retry": "0.11.0",
|
|
61
61
|
"body-parser": "1.19.1",
|
|
62
|
-
"chalk": "4.1.
|
|
63
|
-
"chrome-launcher": "0.
|
|
62
|
+
"chalk": "4.1.2",
|
|
63
|
+
"chrome-launcher": "0.15.0",
|
|
64
64
|
"combine-source-map": "0.8.0",
|
|
65
65
|
"commander": "2.9.0",
|
|
66
66
|
"compression": "1.7.4",
|
|
67
67
|
"cors": "2.8.5",
|
|
68
|
-
"crypto-js": "4.
|
|
68
|
+
"crypto-js": "4.1.1",
|
|
69
69
|
"data-uri-to-buffer": "2.0.2",
|
|
70
70
|
"decompress": "4.2.1",
|
|
71
|
-
"express": "4.17.
|
|
71
|
+
"express": "4.17.3",
|
|
72
72
|
"find-root": "1.1.0",
|
|
73
|
-
"fkill": "7.
|
|
73
|
+
"fkill": "7.2.1",
|
|
74
74
|
"form-data": "3.0.0",
|
|
75
|
-
"fs-extra": "
|
|
76
|
-
"glob": "7.
|
|
75
|
+
"fs-extra": "10.0.1",
|
|
76
|
+
"glob": "7.2.0",
|
|
77
77
|
"istanbul-lib-report": "3.0.0",
|
|
78
78
|
"istanbul-reports": "3.0.2",
|
|
79
79
|
"jimp": "0.16.1",
|
|
80
|
-
"jsdom": "
|
|
80
|
+
"jsdom": "19.0.0",
|
|
81
81
|
"jsonwebtoken": "8.5.1",
|
|
82
82
|
"lodash": "4.17.21",
|
|
83
83
|
"memory-fs": "0.5.0",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"moment": "2.25.3",
|
|
87
87
|
"ms": "2.1.2",
|
|
88
88
|
"npm": "8.3.0",
|
|
89
|
-
"object-hash": "
|
|
90
|
-
"ora": "4.
|
|
89
|
+
"object-hash": "3.0.0",
|
|
90
|
+
"ora": "5.4.1",
|
|
91
91
|
"pako": "1.0.11",
|
|
92
92
|
"portfinder": "1.0.28",
|
|
93
93
|
"promise-queue": "2.2.5",
|
|
@@ -103,9 +103,9 @@
|
|
|
103
103
|
"threads": "0.12.0",
|
|
104
104
|
"ua-parser-js": "0.7.28",
|
|
105
105
|
"validate-npm-package-name": "3.0.0",
|
|
106
|
-
"winston": "3.
|
|
107
|
-
"winston-transport": "4.
|
|
108
|
-
"ws": "8.
|
|
106
|
+
"winston": "3.6.0",
|
|
107
|
+
"winston-transport": "4.5.0",
|
|
108
|
+
"ws": "8.5.0",
|
|
109
109
|
"xml2js": "0.4.23",
|
|
110
110
|
"yaml": "1.10.0"
|
|
111
111
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const StepAction = require('./stepAction');
|
|
4
|
-
const Promise = require('bluebird');
|
|
5
4
|
const _ = require('lodash');
|
|
6
5
|
const logger = require('../../commons/logger').getLogger('input-file-step-action');
|
|
7
6
|
const { codeSnippets, utils } = require('../../commons/getSessionPlayerRequire');
|
|
@@ -26,53 +25,58 @@ class InputFileStepAction extends StepAction {
|
|
|
26
25
|
return this.driver.executeJS(getVisibleElementCode, target.locatedElement);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
safariPreUploadActions(target) {
|
|
28
|
+
async safariPreUploadActions(target) {
|
|
30
29
|
const options = {
|
|
31
30
|
width: '150px',
|
|
32
31
|
height: '150px',
|
|
33
32
|
left: '10px',
|
|
34
33
|
top: '10px',
|
|
35
34
|
};
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
try {
|
|
36
|
+
return await this.forceInputToBeVisible(target, options);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
logger.error('failed to set input file in Safari recovery', { err });
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
uploadFilesAndForceVisibility(gridLocalFiles, target) {
|
|
43
|
+
async uploadFilesAndForceVisibility(gridLocalFiles, target) {
|
|
44
44
|
const preUploadStep = this.driver.isSafari() ?
|
|
45
|
-
//
|
|
45
|
+
// in safari we force the visibility ahead of time because making it visible the second time around doesn't work
|
|
46
46
|
this.safariPreUploadActions(target) :
|
|
47
47
|
Promise.resolve();
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
|
|
49
|
+
try {
|
|
50
|
+
await preUploadStep;
|
|
51
|
+
await this.uploadFiles(gridLocalFiles, target);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const edgeErrorEditableMessage = 'The element is not editable';
|
|
54
|
+
const edgeErrorFocusableMessage = 'The element is not focusable';
|
|
55
|
+
const safariErrorVisibleMessege = 'An element command could not be completed because the element is not visible on the page.';
|
|
56
|
+
const elementNotInteractable = 'element not interactable';
|
|
57
|
+
const elementNotPointerOrKeyboardInteractable = 'element is not pointer- or keyboard interactable';
|
|
58
|
+
const invalidStateMsg = 'invalid element state: Element is not currently interactable and may not be manipulated';
|
|
59
|
+
const mustBeVisibleMsg = 'Element must not be hidden, disabled or read-only';
|
|
60
|
+
const notReachableByKeyboard = 'is not reachable by keyboard';
|
|
61
|
+
const errorMsg = err ? err.message : '';
|
|
62
|
+
// Workaround move element if element is not visible or disabled
|
|
63
|
+
if (_.isEqual(errorMsg, invalidStateMsg) ||
|
|
64
|
+
_.startsWith(errorMsg, mustBeVisibleMsg) ||
|
|
65
|
+
_.startsWith(errorMsg, edgeErrorEditableMessage) ||
|
|
66
|
+
_.startsWith(errorMsg, edgeErrorFocusableMessage) ||
|
|
67
|
+
_.startsWith(errorMsg, safariErrorVisibleMessege) ||
|
|
68
|
+
_.includes(errorMsg, notReachableByKeyboard) ||
|
|
69
|
+
_.includes(errorMsg, elementNotInteractable) ||
|
|
70
|
+
_.includes(errorMsg, elementNotPointerOrKeyboardInteractable)
|
|
71
|
+
) {
|
|
72
|
+
await this.forceInputToBeVisible(target);
|
|
73
|
+
await this.uploadFiles(gridLocalFiles, target);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
logger.error('failed to set input file', { err });
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
async uploadFiles(gridLocalFiles, target) {
|
|
@@ -81,31 +85,22 @@ class InputFileStepAction extends StepAction {
|
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
performAction() {
|
|
88
|
+
async performAction() {
|
|
85
89
|
const target = this.context.data[this.step.targetId || 'targetId'];
|
|
86
90
|
const overrideAzureStorageUrl = featureFlagService.flags.overrideAzureStorageUrl.isEnabled();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.
|
|
92
|
-
overrideAzureStorageUrl,
|
|
93
|
-
logger,
|
|
94
|
-
) : Promise.resolve(this.step.fileUrls)).then((fileUrls) => {
|
|
95
|
-
const useJsInputCodeInSafari = featureFlagService.flags.useJsInputCodeInSafari.isEnabled();
|
|
96
|
-
if (this.driver.isSafari() && (useJsInputCodeInSafari || fileUrls.length > 1)) {
|
|
97
|
-
return this.driver.executeJSWithArray(`
|
|
91
|
+
|
|
92
|
+
const fileUrls = await utils.addTokenToFileUrl(this.context.project.id, this.step.fileUrls, this.stepActionUtils.testimServicesApi, overrideAzureStorageUrl, logger);
|
|
93
|
+
const useJsInputCodeInSafari = featureFlagService.flags.useJsInputCodeInSafari.isEnabled();
|
|
94
|
+
if (this.driver.isSafari() && (useJsInputCodeInSafari || fileUrls.length > 1)) {
|
|
95
|
+
await this.driver.executeJSWithArray(`
|
|
98
96
|
const getLocatedElement = ${codeSnippets.getLocatedElementCode};
|
|
99
97
|
const downloadAndUploadFile = ${downloadAndUpload()};
|
|
100
|
-
return downloadAndUploadFile.apply(null, arguments);`,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
98
|
+
return downloadAndUploadFile.apply(null, arguments);`, [target.locatedElement, fileUrls]);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
104
101
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
.then(() => Promise.resolve());
|
|
108
|
-
});
|
|
102
|
+
const gridLocalFiles = await inputFileUtils.downloadFilesAndUploadToGrid(fileUrls, this.uploadFile.bind(this));
|
|
103
|
+
await this.uploadFilesAndForceVisibility(gridLocalFiles, target);
|
|
109
104
|
}
|
|
110
105
|
}
|
|
111
106
|
|
|
@@ -138,8 +133,35 @@ function downloadAndUpload() {
|
|
|
138
133
|
throw new Error('element not found');
|
|
139
134
|
}
|
|
140
135
|
|
|
136
|
+
function getFileBlob(url) {
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
var xhr = new XMLHttpRequest();
|
|
139
|
+
xhr.open('GET', url, true);
|
|
140
|
+
xhr.responseType = 'blob';
|
|
141
|
+
|
|
142
|
+
xhr.onload = function() {
|
|
143
|
+
if (this.status === 200) {
|
|
144
|
+
resolve(this.response);
|
|
145
|
+
} else {
|
|
146
|
+
reject(new Error('Could not load file, failure status:' + this.status));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
xhr.onerror = function(e) {
|
|
150
|
+
reject(new Error("Error " + e.target.status + " occurred while loading the file."));
|
|
151
|
+
};
|
|
152
|
+
xhr.send();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
|
|
141
157
|
const fileList = await Promise.all(fileUrls.map(async ({ url, name }) => {
|
|
142
|
-
|
|
158
|
+
let blob;
|
|
159
|
+
try {
|
|
160
|
+
const res = await fetch(url)
|
|
161
|
+
blob = await res.blob();
|
|
162
|
+
} catch (err) {
|
|
163
|
+
blob = await getFileBlob(url); // Sometimes the fetch fails, try using XHR as fallback
|
|
164
|
+
}
|
|
143
165
|
return new File([blob], name, { type: blob.type });
|
|
144
166
|
}));
|
|
145
167
|
|
package/services/gridService.js
CHANGED
|
@@ -237,25 +237,7 @@ function getOptionGrid(options) {
|
|
|
237
237
|
|
|
238
238
|
async function getTestPlanGridData(options, testPlanData) {
|
|
239
239
|
const companyId = options.company.companyId;
|
|
240
|
-
|
|
241
|
-
return await getGridDataByGridId(companyId, testPlanData.gridId, options.allGrids);
|
|
242
|
-
} catch (err) {
|
|
243
|
-
if (err instanceof ArgError) {
|
|
244
|
-
// this is a fallback to an old behavior that is wrong,
|
|
245
|
-
// we should remove it in the future
|
|
246
|
-
const testPlanDatas = await servicesApi.getTestPlan(options.project, options.testPlan);
|
|
247
|
-
if (testPlanDatas.length === 0) {
|
|
248
|
-
throw new ArgError(`no test plan to run ${options.testPlan}`);
|
|
249
|
-
}
|
|
250
|
-
const testPlanGrids = testPlanDatas.map(d => options.allGrids.find(grid => grid._id === d.gridId));
|
|
251
|
-
if (testPlanGrids.includes(undefined)) {
|
|
252
|
-
throw new ArgError('failed to find one of the test plan defined grid');
|
|
253
|
-
}
|
|
254
|
-
logger.warn('getTestPlanGridData used fallback and might cause test plans run on a unintended grid', { companyId });
|
|
255
|
-
return getSerializableObject(_.first(testPlanGrids));
|
|
256
|
-
}
|
|
257
|
-
throw err;
|
|
258
|
-
}
|
|
240
|
+
return await getGridDataByGridId(companyId, testPlanData.gridId, options.allGrids);
|
|
259
241
|
}
|
|
260
242
|
|
|
261
243
|
async function getGridData(options) {
|