@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testim/testim-cli",
3
- "version": "3.226.0",
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": "8.1.0",
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.4",
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.4",
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.5.5"
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.2"
47
+ "multer": "1.4.4"
48
48
  },
49
49
  "dependencies": {
50
- "@applitools/eyes-sdk-core": "13.0.0",
51
- "@applitools/visual-grid-client": "15.8.62",
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.1.1",
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.0",
63
- "chrome-launcher": "0.13.4",
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.0.0",
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.1",
71
+ "express": "4.17.3",
72
72
  "find-root": "1.1.0",
73
- "fkill": "7.0.1",
73
+ "fkill": "7.2.1",
74
74
  "form-data": "3.0.0",
75
- "fs-extra": "8.1.0",
76
- "glob": "7.1.6",
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": "16.7.0",
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": "2.0.3",
90
- "ora": "4.0.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.3.3",
107
- "winston-transport": "4.4.0",
108
- "ws": "8.2.3",
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
- return this.forceInputToBeVisible(target, options)
37
- .catch(err => {
38
- logger.error('failed to set input file in Safari recovery', { err });
39
- throw err;
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
- // // in safari we force the visibility ahead of time because making it visible the second time around doesn't work
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
- return preUploadStep.then(() => this.uploadFiles(gridLocalFiles, target))
50
- .catch(err => {
51
- const edgeErrorEditableMessage = 'The element is not editable';
52
- const edgeErrorFocusableMessage = 'The element is not focusable';
53
- const safariErrorVisibleMessege = 'An element command could not be completed because the element is not visible on the page.';
54
- const elementNotInteractable = 'element not interactable';
55
- const elementNotPointerOrKeyboardInteractable = 'element is not pointer- or keyboard interactable';
56
- const invalidStateMsg = 'invalid element state: Element is not currently interactable and may not be manipulated';
57
- const mustBeVisibleMsg = 'Element must not be hidden, disabled or read-only';
58
- const notReachableByKeyboard = 'is not reachable by keyboard';
59
- const errorMsg = err ? err.message : '';
60
- // Workaround move element if element is not visible or disabled
61
- if (_.isEqual(errorMsg, invalidStateMsg) ||
62
- _.startsWith(errorMsg, mustBeVisibleMsg) ||
63
- _.startsWith(errorMsg, edgeErrorEditableMessage) ||
64
- _.startsWith(errorMsg, edgeErrorFocusableMessage) ||
65
- _.startsWith(errorMsg, safariErrorVisibleMessege) ||
66
- _.includes(errorMsg, notReachableByKeyboard) ||
67
- _.includes(errorMsg, elementNotInteractable) ||
68
- _.includes(errorMsg, elementNotPointerOrKeyboardInteractable)
69
- ) {
70
- return this.forceInputToBeVisible(target).then(() => this.uploadFiles(gridLocalFiles, target));
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
- logger.error('failed to set input file', { err });
74
- return Promise.reject(err);
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
- //TODO remove if after release session player
88
- return (utils.addTokenToFileUrl ? utils.addTokenToFileUrl(
89
- this.context.project.id,
90
- this.step.fileUrls,
91
- this.stepActionUtils.testimServicesApi,
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
- [target.locatedElement, fileUrls])
102
- .then(() => Promise.resolve());
103
- }
98
+ return downloadAndUploadFile.apply(null, arguments);`, [target.locatedElement, fileUrls]);
99
+ return;
100
+ }
104
101
 
105
- return inputFileUtils.downloadFilesAndUploadToGrid(fileUrls, this.uploadFile.bind(this))
106
- .then(gridLocalFiles => this.uploadFilesAndForceVisibility(gridLocalFiles, target))
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
- const blob = await fetch(url).then(r => r.blob());
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
 
@@ -237,25 +237,7 @@ function getOptionGrid(options) {
237
237
 
238
238
  async function getTestPlanGridData(options, testPlanData) {
239
239
  const companyId = options.company.companyId;
240
- try {
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) {