@testim/testim-cli 3.228.0 → 3.231.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.231.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -47,8 +47,8 @@
|
|
|
47
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.2.0",
|
|
51
|
+
"@applitools/visual-grid-client": "15.11.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",
|
|
@@ -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
|
|
|
@@ -9,6 +9,24 @@ const { makeSDK } = require('@applitools/eyes-sdk-core');
|
|
|
9
9
|
const { W3C_ELEMENT_ID } = require('../constants');
|
|
10
10
|
const _ = require('lodash');
|
|
11
11
|
|
|
12
|
+
let packageJson;
|
|
13
|
+
// There is a difference in the folder structure in prod vs. dev
|
|
14
|
+
try {
|
|
15
|
+
// PRODUCTION
|
|
16
|
+
// eslint-disable-next-line import/no-unresolved
|
|
17
|
+
packageJson = require('../../package.json');
|
|
18
|
+
} catch (e) {
|
|
19
|
+
//pass
|
|
20
|
+
}
|
|
21
|
+
if (!packageJson) {
|
|
22
|
+
try {
|
|
23
|
+
// in dev, they are one level up
|
|
24
|
+
packageJson = require('../../../package.json');
|
|
25
|
+
} catch (e) {
|
|
26
|
+
//pass
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
12
30
|
const LEGACY_ELEMENT_ID = 'ELEMENT';
|
|
13
31
|
|
|
14
32
|
function extractElementId(element) {
|
|
@@ -217,10 +235,12 @@ class EyesSpec {
|
|
|
217
235
|
|
|
218
236
|
class EyeSdkService {
|
|
219
237
|
constructor() {
|
|
238
|
+
const sdkVersion = packageJson ? packageJson.dependencies['@applitools/eyes-sdk-core'] : 'N/A';
|
|
239
|
+
|
|
220
240
|
/** @type {Core} */
|
|
221
241
|
this.sdk = makeSDK({
|
|
222
242
|
name: 'Testim.io',
|
|
223
|
-
version:
|
|
243
|
+
version: `4.0.0/eyes-sdk-core/${sdkVersion}`,
|
|
224
244
|
spec: new EyesSpec(),
|
|
225
245
|
VisualGridClient: require('@applitools/visual-grid-client'),
|
|
226
246
|
});
|