@testim/testim-cli 3.193.0 → 3.197.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/README.md +1 -1
- package/cli/onExit.js +12 -1
- package/cli.js +5 -1
- package/codim/codim-npm-package/index.ts +1 -0
- package/commons/constants.js +0 -25
- package/commons/featureFlags.js +2 -0
- package/commons/socket/testResultService.js +4 -14
- package/commons/testimAnalytics.js +0 -1
- package/commons/testimDesiredCapabilitiesBuilder.js +0 -95
- package/commons/testimServicesApi.js +10 -80
- package/executionQueue.js +7 -4
- package/npm-shrinkwrap.json +956 -520
- package/package.json +3 -1
- package/player/chromeLauncherTestPlayer.js +5 -2
- package/player/stepActions/apiStepAction.js +1 -0
- package/player/stepActions/baseJsStepAction.js +5 -1
- package/player/stepActions/pixelValidationStepAction.js +28 -0
- package/player/stepActions/salesforceAutoLoginStepAction.js +39 -0
- package/player/stepActions/scripts/focusElement.js +5 -3
- package/player/stepActions/stepActionRegistrar.js +5 -47
- package/player/utils/eyeSdkService.js +230 -0
- package/reports/consoleReporter.js +0 -20
- package/reports/reporter.js +0 -21
- package/runOptions.js +13 -89
- package/runner.js +9 -46
- package/runners/{strategies/LocalStrategy.js → ParallelWorkerManager.js} +60 -66
- package/runners/TestPlanRunner.js +286 -67
- package/runners/runnerUtils.js +73 -0
- package/{runners/strategies/BaseStrategy.js → services/analyticsService.js} +41 -28
- package/services/gridService.js +24 -16
- package/services/gridService.test.js +21 -21
- package/services/lambdatestService.js +1 -1
- package/testRunHandler.js +1 -1
- package/testRunStatus.js +30 -20
- package/utils.js +5 -5
- package/workers/BaseWorker.js +38 -39
- package/workers/BaseWorker.test.js +1 -1
- package/workers/WorkerExtensionSingleBrowser.js +6 -3
- package/commons/apkUploader/apkUploader.js +0 -46
- package/commons/apkUploader/apkUploaderFactory.js +0 -68
- package/commons/apkUploader/deviceFarmApkUploader.js +0 -41
- package/commons/apkUploader/saucelabsApkUploader.js +0 -36
- package/commons/apkUploader/testObjectApkUploader.js +0 -34
- package/player/mobile/mobileTestPlayer.js +0 -80
- package/player/mobile/mobileWebDriver.js +0 -155
- package/player/mobile/services/frameLocatorMock.js +0 -18
- package/player/mobile/services/mobilePortSelector.js +0 -22
- package/player/mobile/services/mobileTabService.js +0 -241
- package/player/mobile/utils/mobileScreenshotUtils.js +0 -46
- package/player/mobile/utils/mobileWindowUtils.js +0 -84
- package/player/stepActions/mobile/android/androidLocateStepAction.js +0 -122
- package/player/stepActions/mobile/android/androidLongClickStepAction.js +0 -12
- package/player/stepActions/mobile/android/androidScrollStepAction.js +0 -134
- package/player/stepActions/mobile/android/androidSpecialKeyStepAction.js +0 -22
- package/player/stepActions/mobile/android/androidSwipeStepAction.js +0 -32
- package/player/stepActions/mobile/androidGlobalActionStepAction.js +0 -12
- package/player/stepActions/mobile/androidTapStepAction.js +0 -19
- package/player/stepActions/mobile/androidTextChangeStepAction.js +0 -23
- package/player/stepActions/mobile/ios/iosLocateStepAction.js +0 -124
- package/player/stepActions/mobile/ios/iosScrollStepAction.js +0 -76
- package/runners/AnonymousTestPlanRunner.js +0 -106
- package/runners/BaseRunner.js +0 -42
- package/runners/BaseTestPlanRunner.js +0 -194
- package/runners/DeviceFarmRemoteRunner.js +0 -50
- package/runners/SchedulerRemoteRunner.js +0 -47
- package/runners/strategies/DeviceFarmStrategy.js +0 -195
- package/runners/strategies/LocalDeviceFarmStrategy.js +0 -12
- package/runners/strategies/LocalTestStrategy.js +0 -14
- package/runners/strategies/Strategy.js +0 -17
- package/workers/WorkerAppium.js +0 -70
package/runOptions.js
CHANGED
|
@@ -72,11 +72,9 @@ const printUsage = () => {
|
|
|
72
72
|
return line.includes('--player-path') || line.includes('--player-require-path');
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function
|
|
75
|
+
function isScheduler(line) {
|
|
76
76
|
return (
|
|
77
|
-
line.includes('--testObject') ||
|
|
78
77
|
line.includes('--executionId') ||
|
|
79
|
-
line.includes('--testObject2') ||
|
|
80
78
|
line.includes('--source') ||
|
|
81
79
|
line.includes('--resultId') ||
|
|
82
80
|
line.includes('--remoteRunId') ||
|
|
@@ -84,15 +82,6 @@ const printUsage = () => {
|
|
|
84
82
|
);
|
|
85
83
|
}
|
|
86
84
|
|
|
87
|
-
function isAwsDF(line) {
|
|
88
|
-
return (
|
|
89
|
-
line.includes('--aws-project-arn') ||
|
|
90
|
-
line.includes('--aws-region') ||
|
|
91
|
-
line.includes('--aws-access-key-id') ||
|
|
92
|
-
line.includes('--aws-secret-access-key')
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
85
|
function isWebdriverTimeout(line) {
|
|
97
86
|
return (
|
|
98
87
|
line.includes('--get-browser-timeout') ||
|
|
@@ -116,6 +105,10 @@ const printUsage = () => {
|
|
|
116
105
|
return line.includes('--save-rca-locally');
|
|
117
106
|
}
|
|
118
107
|
|
|
108
|
+
function isExitCodeIgnoreFailingTests(line) {
|
|
109
|
+
return line.includes('--exit-code-ignore-failing-tests');
|
|
110
|
+
}
|
|
111
|
+
|
|
119
112
|
program.help((txt) => {
|
|
120
113
|
const lines = txt.split('\n');
|
|
121
114
|
return lines
|
|
@@ -125,12 +118,12 @@ const printUsage = () => {
|
|
|
125
118
|
!isParamsJsonOption(ln) &&
|
|
126
119
|
!isDefaultHelpLine(ln) &&
|
|
127
120
|
!isPlayerOption(ln) &&
|
|
128
|
-
!
|
|
121
|
+
!isScheduler(ln) &&
|
|
129
122
|
!isMonitorPerformance(ln) &&
|
|
130
123
|
!isUserId(ln) &&
|
|
131
|
-
!isAwsDF(ln) &&
|
|
132
124
|
!isWebdriverTimeout(ln) &&
|
|
133
|
-
!isSaveRCALocally(ln)
|
|
125
|
+
!isSaveRCALocally(ln) &&
|
|
126
|
+
!isExitCodeIgnoreFailingTests(ln)
|
|
134
127
|
)
|
|
135
128
|
.join('\n');
|
|
136
129
|
});
|
|
@@ -304,9 +297,6 @@ program
|
|
|
304
297
|
.option('--disable-sockets', 'Disable CLI sockets', false)
|
|
305
298
|
|
|
306
299
|
// Remote run options
|
|
307
|
-
.option('--testObject [test-object]', '', '')
|
|
308
|
-
.option('--remoteRunObject [remote-run-object]', '', '')
|
|
309
|
-
.option('--testObject2 [test-object]', '', '')
|
|
310
300
|
.option('--executionId [execution-id]', '', '')
|
|
311
301
|
.option('--remoteRunId [remote-run-id]', '', '')
|
|
312
302
|
.option('--schedulerId [scheduler-id]', '', '')
|
|
@@ -319,17 +309,6 @@ program
|
|
|
319
309
|
.option('--agent-port [agent-port]', 'set agent port', Number, 42543)
|
|
320
310
|
.option('--agent-bind [agent-host-bind]', 'set agent host bind', '127.0.0.1')
|
|
321
311
|
|
|
322
|
-
// Mobile options
|
|
323
|
-
.option('--apk-location [apk-local-location]', 'application apk location')
|
|
324
|
-
.option('--ipa-location [ipa-local-location]', 'application ipa location')
|
|
325
|
-
.option('--apk-timeout [apk-upload-timeout]', 'upload apk timeout in milliseconds', 15 * 60 * 1000)
|
|
326
|
-
.option('--ipa-timeout [ipa-upload-timeout]', 'upload ipa timeout in milliseconds', 15 * 60 * 1000)
|
|
327
|
-
.option('--disable-window-animation [disable-window-animation]', 'disable window animation by setting Appium capability', false)
|
|
328
|
-
|
|
329
|
-
.option('--device-udid [device-udid]', 'device udid')
|
|
330
|
-
.option('--device-name [device-name]', 'device name', 'mobile')
|
|
331
|
-
.option('--vendor-app-id [vendor-app-id]', 'use existing application id instead of upload new app')
|
|
332
|
-
|
|
333
312
|
.option('--chrome-extra-prefs [chrome-extra-prefs]', 'add extra chrome preferences', '')
|
|
334
313
|
.option('--chrome-extra-args [chrome-extra-args]', 'add extra chrome arguments separated by \',\'', '')
|
|
335
314
|
.option('--chrome-block-location [chrome-block-location]', 'block chrome geolocation', false)
|
|
@@ -342,17 +321,13 @@ program
|
|
|
342
321
|
.option('--version [version]', 'print the current version of the Testim CLI and exit', false)
|
|
343
322
|
.option('--monitor-performance', 'collect test playback performance data')
|
|
344
323
|
|
|
345
|
-
// AWS DF
|
|
346
|
-
.option('--aws-project-arn [projectArn]', 'projectArn', '')
|
|
347
|
-
.option('--aws-region [region]', 'region', 'us-west-2')
|
|
348
|
-
.option('--aws-access-key-id [accessKeyId]', 'accessKeyId', '')
|
|
349
|
-
.option('--aws-secret-access-key [secretAccessKey]', 'secretAccessKey', '')
|
|
350
|
-
|
|
351
324
|
.option('--high-speed', 'run in high speed mode')
|
|
352
325
|
.option('--lightweight-mode [settings]', 'run lightweight mode')
|
|
353
326
|
.option('--create-prefeched-data [location]', 'prefech data into local cache file')
|
|
354
327
|
.option('--use-prefeched-data [location]', 'use prefeched data from local cache file, and force using only cached data')
|
|
355
328
|
.option('--save-rca-locally [path]', 'save root cause analysis assets locally')
|
|
329
|
+
|
|
330
|
+
.option('--exit-code-ignore-failing-tests', 'dont return non zero exit code when tests fail. non zero exit code will mean a real error occurred')
|
|
356
331
|
.parse(process.argv);
|
|
357
332
|
|
|
358
333
|
module.exports = {
|
|
@@ -814,7 +789,7 @@ module.exports = {
|
|
|
814
789
|
return Promise.reject(new ArgError('parallel could not be a negative number or not number, --parallel <number-of-tests>'));
|
|
815
790
|
}
|
|
816
791
|
|
|
817
|
-
if ([CLI_MODE.EXTENSION, CLI_MODE.SELENIUM
|
|
792
|
+
if ([CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].indexOf(program.mode) === -1) {
|
|
818
793
|
return Promise.reject(new ArgError(`runner mode <${program.mode}> is not supported`));
|
|
819
794
|
}
|
|
820
795
|
|
|
@@ -825,38 +800,11 @@ module.exports = {
|
|
|
825
800
|
if (
|
|
826
801
|
!program.browser &&
|
|
827
802
|
!isTestConfigSpecified &&
|
|
828
|
-
!isTestPlanSpecified
|
|
829
|
-
!program.testObject2
|
|
803
|
+
!isTestPlanSpecified
|
|
830
804
|
) {
|
|
831
805
|
program.browser = 'chrome';
|
|
832
806
|
}
|
|
833
807
|
|
|
834
|
-
if (program.testObject) {
|
|
835
|
-
try {
|
|
836
|
-
program.testObject = JSON.parse(program.testObject);
|
|
837
|
-
} catch (err) {
|
|
838
|
-
return Promise.reject(new ArgError(`failed to parse testObject string error: ${err.message}`));
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
if (program.testObject2) {
|
|
843
|
-
try {
|
|
844
|
-
const obj = decodeURIComponent(program.testObject2);
|
|
845
|
-
program.testObject = JSON.parse(obj);
|
|
846
|
-
} catch (err) {
|
|
847
|
-
return Promise.reject(new ArgError(`failed to parse testObject string error: ${err.message}`));
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
if (program.remoteRunObject) {
|
|
852
|
-
try {
|
|
853
|
-
const obj = decodeURIComponent(program.remoteRunObject);
|
|
854
|
-
program.remoteRunObject = JSON.parse(obj);
|
|
855
|
-
} catch (err) {
|
|
856
|
-
return Promise.reject(new ArgError(`failed to parse remoteRunObject string error: ${err.message}`));
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
|
|
860
808
|
if (program.testPlan && program.testPlan.length === 0 && program.testPlanId && program.testPlanId.length === 0) {
|
|
861
809
|
if (
|
|
862
810
|
typeof program.host !== 'string' &&
|
|
@@ -950,9 +898,6 @@ module.exports = {
|
|
|
950
898
|
} else {
|
|
951
899
|
program.files = [];
|
|
952
900
|
}
|
|
953
|
-
if (program.apkLocation && program.ipaLocation) {
|
|
954
|
-
return Promise.reject(new ArgError('cannot set --apk-location and --ipa-location. please choose the one compatible with your project type'));
|
|
955
|
-
}
|
|
956
901
|
|
|
957
902
|
if (program.setRetention && !_.inRange(_.parseInt(program.setRetention), 1, 11)) {
|
|
958
903
|
return Promise.reject(new ArgError('Please provide the number of days that the test results will be retained for (--set-retention must be a whole number between 1 to 10)'));
|
|
@@ -1119,7 +1064,6 @@ module.exports = {
|
|
|
1119
1064
|
testobjectSauce: program.testobjectSauce,
|
|
1120
1065
|
gridUsername: program.gridUsername,
|
|
1121
1066
|
gridPassword: program.gridPassword,
|
|
1122
|
-
vendorAppId: program.vendorAppId,
|
|
1123
1067
|
overrideExecutionName: program.overrideExecutionName,
|
|
1124
1068
|
|
|
1125
1069
|
tmsSuppressReporting: Boolean(program.suppressTmsReporting) || Boolean(program.tmsSuppressReporting),
|
|
@@ -1186,9 +1130,7 @@ module.exports = {
|
|
|
1186
1130
|
codeCoverageInclude: program.codeCoverageInclude,
|
|
1187
1131
|
|
|
1188
1132
|
// Remote run options
|
|
1189
|
-
testObject: program.testObject,
|
|
1190
1133
|
executionId: program.executionId,
|
|
1191
|
-
remoteRunObject: program.remoteRunObject,
|
|
1192
1134
|
remoteRunId: program.remoteRunId,
|
|
1193
1135
|
schedulerId: program.schedulerId,
|
|
1194
1136
|
source: program.source,
|
|
@@ -1200,19 +1142,6 @@ module.exports = {
|
|
|
1200
1142
|
w3cCapabilities: program.w3cCapabilities,
|
|
1201
1143
|
oldCapabilities: program.oldCapabilities,
|
|
1202
1144
|
|
|
1203
|
-
//APK options
|
|
1204
|
-
apkLocation: program.apkLocation,
|
|
1205
|
-
apkTimeout: program.apkTimeout,
|
|
1206
|
-
|
|
1207
|
-
// IPA options
|
|
1208
|
-
ipaLocation: program.ipaLocation,
|
|
1209
|
-
ipaTimeout: program.ipaTimeout,
|
|
1210
|
-
|
|
1211
|
-
disableWindowAnimation: program.disableWindowAnimation,
|
|
1212
|
-
|
|
1213
|
-
deviceUdid: program.deviceUdid,
|
|
1214
|
-
deviceName: program.deviceName,
|
|
1215
|
-
|
|
1216
1145
|
chromeBlockLocation: program.chromeBlockLocation,
|
|
1217
1146
|
chromeUserDataDir: program.chromeUserDataDir,
|
|
1218
1147
|
retries: program.retries,
|
|
@@ -1226,16 +1155,11 @@ module.exports = {
|
|
|
1226
1155
|
|
|
1227
1156
|
user: program.user,
|
|
1228
1157
|
|
|
1229
|
-
awsProjectArn: program.awsProjectArn,
|
|
1230
|
-
awsRegion: program.awsRegion,
|
|
1231
|
-
|
|
1232
|
-
awsAccessKeyId: program.awsAccessKeyId,
|
|
1233
|
-
awsSecretAccessKey: program.awsSecretAccessKey,
|
|
1234
|
-
|
|
1235
1158
|
lightweightMode: program.lightweightMode,
|
|
1236
1159
|
createPrefechedData: program.createPrefechedData,
|
|
1237
1160
|
|
|
1238
1161
|
saveRCALocally: program.saveRcaLocally,
|
|
1162
|
+
exitCodeIgnoreFailingTests: program.exitCodeIgnoreFailingTests,
|
|
1239
1163
|
|
|
1240
1164
|
disableSockets: program.disableSockets,
|
|
1241
1165
|
});
|
package/runner.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/* eslint-disable no-console */
|
|
4
|
-
const { CLI_MODE
|
|
4
|
+
const { CLI_MODE } = require('./commons/constants');
|
|
5
5
|
const Promise = require('bluebird');
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
const { EDITOR_URL } = require('./commons/config');
|
|
@@ -15,16 +15,13 @@ const npmDriver = require('./testimNpmDriver.js');
|
|
|
15
15
|
const analytics = require('./commons/testimAnalytics');
|
|
16
16
|
const branchService = require('./services/branchService');
|
|
17
17
|
const gridService = require('./services/gridService');
|
|
18
|
-
const strategySelector = require('./runners/strategies/Strategy');
|
|
19
18
|
const { ArgError, QuotaDepletedError } = require('./errors');
|
|
20
19
|
const featureFlags = require('./commons/featureFlags');
|
|
21
20
|
const perf = require('./commons/performance-logger');
|
|
22
21
|
const { prepareMockNetwork, initializeUserWithAuth } = require('./commons/prepareRunner');
|
|
23
|
-
const { hasTestPlanFlag } = require('./utils');
|
|
24
22
|
|
|
25
23
|
const FREE_PLAN_MINIMUM_BROWSER_TIMEOUT = 30 * 60 * 1000;
|
|
26
24
|
|
|
27
|
-
const AnonymousTestPlanRunner = require('./runners/AnonymousTestPlanRunner');
|
|
28
25
|
const TestPlanRunner = require('./runners/TestPlanRunner');
|
|
29
26
|
const labFeaturesService = require('./services/labFeaturesService');
|
|
30
27
|
const featureAvailabilityService = require('./commons/featureAvailabilityService');
|
|
@@ -85,17 +82,6 @@ function validateCliAccount(options) {
|
|
|
85
82
|
});
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
function validateRemoteRunAccount(options) {
|
|
89
|
-
return validateProjectQuotaNotDepleted(options)
|
|
90
|
-
.catch(err => {
|
|
91
|
-
if (err instanceof QuotaDepletedError) {
|
|
92
|
-
return Promise.reject(err);
|
|
93
|
-
}
|
|
94
|
-
logger.error('could not validate remote run account', { err });
|
|
95
|
-
return undefined;
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
85
|
function analyticsIdentify(projectId) {
|
|
100
86
|
const authData = testimCustomToken.getTokenV3UserData();
|
|
101
87
|
return analytics.identify({
|
|
@@ -138,7 +124,7 @@ function setCompany(options, company) {
|
|
|
138
124
|
const { onprem, id, storageBaseUrl, storageType, name, activePlan = {} } = company;
|
|
139
125
|
if (onprem) {
|
|
140
126
|
const { mode, extensionPath, ext, playerPath } = options;
|
|
141
|
-
if ([CLI_MODE.SELENIUM
|
|
127
|
+
if ([CLI_MODE.SELENIUM].includes(mode) && !playerPath) {
|
|
142
128
|
return Promise.reject(new ArgError('in selenium on prem mode --player-path must be provided'));
|
|
143
129
|
}
|
|
144
130
|
if (mode === 'extension' && !extensionPath && !ext) {
|
|
@@ -214,32 +200,13 @@ async function setMockNetworkRules(options) {
|
|
|
214
200
|
|
|
215
201
|
function runRunner(options, customExtensionLocalLocation) {
|
|
216
202
|
perf.log('in runner.js runRunner');
|
|
217
|
-
const branchToUse = branchService.getCurrentBranch();
|
|
218
|
-
|
|
219
|
-
const selectedStrategy = strategySelector(options, customExtensionLocalLocation);
|
|
220
|
-
const {
|
|
221
|
-
remoteRunObject, testObject, executionId, project, remoteRunId, useLocalChromeDriver, useChromeLauncher,
|
|
222
|
-
} = options;
|
|
223
203
|
|
|
224
|
-
|
|
225
|
-
const SchedulerRemoteRunner = require('./runners/SchedulerRemoteRunner');
|
|
226
|
-
const schedulerRemoteRunner = new SchedulerRemoteRunner(selectedStrategy);
|
|
227
|
-
return validateRemoteRunAccount(options)
|
|
228
|
-
.then(() => schedulerRemoteRunner.runTest(options, branchToUse));
|
|
229
|
-
}
|
|
204
|
+
const { project, remoteRunId, useLocalChromeDriver, useChromeLauncher } = options;
|
|
230
205
|
|
|
231
206
|
if (!remoteRunId) {
|
|
232
207
|
options.source = (useLocalChromeDriver || useChromeLauncher) ? 'cli-local' : 'cli';
|
|
233
208
|
}
|
|
234
209
|
|
|
235
|
-
if (remoteRunObject && executionId) {
|
|
236
|
-
const { testList, gridInfo } = remoteRunObject;
|
|
237
|
-
const DeviceFarmRemoteRunner = require('./runners/DeviceFarmRemoteRunner');
|
|
238
|
-
const deviceFarmRemoteRunner = new DeviceFarmRemoteRunner(selectedStrategy);
|
|
239
|
-
return validateRemoteRunAccount(options)
|
|
240
|
-
.then(() => deviceFarmRemoteRunner.runTest(executionId, testList, gridInfo, branchToUse, options));
|
|
241
|
-
}
|
|
242
|
-
|
|
243
210
|
npmDriver.checkNpmVersion();
|
|
244
211
|
perf.log('in runner.js after checkNpmVersion');
|
|
245
212
|
|
|
@@ -247,15 +214,7 @@ function runRunner(options, customExtensionLocalLocation) {
|
|
|
247
214
|
.log('in runRunner before tunnel.connect')
|
|
248
215
|
.then(() => tunnel.connect(options, testimCustomToken.getTokenV3UserData()))
|
|
249
216
|
.log('in runRunner after tunnel.connect')
|
|
250
|
-
.then(() =>
|
|
251
|
-
if (hasTestPlanFlag(options)) {
|
|
252
|
-
const testPlanRunner = new TestPlanRunner(selectedStrategy);
|
|
253
|
-
return testPlanRunner.runTestPlans(options, branchToUse);
|
|
254
|
-
}
|
|
255
|
-
const anonymousTestPlanRunner = new AnonymousTestPlanRunner(selectedStrategy);
|
|
256
|
-
perf.log('right before runAnonymousTestPlan');
|
|
257
|
-
return anonymousTestPlanRunner.runAnonymousTestPlan(options, branchToUse);
|
|
258
|
-
})
|
|
217
|
+
.then(() => new TestPlanRunner(customExtensionLocalLocation).run(options))
|
|
259
218
|
.log('before tunnel.disconnect')
|
|
260
219
|
.tap(() => tunnel.disconnect(options))
|
|
261
220
|
.tap(() => gridService.keepAlive.end(project))
|
|
@@ -309,10 +268,14 @@ async function init(options) {
|
|
|
309
268
|
await labFeaturesService.loadLabFeatures(projectById.id, companyByProjectId.activePlan);
|
|
310
269
|
}
|
|
311
270
|
|
|
312
|
-
if (options.lightweightMode && options.lightweightMode.type === 'highSpeed' && !labFeaturesService.isFeatureAvailableForProject('highSpeedMode')) {
|
|
271
|
+
if (options.lightweightMode && options.lightweightMode.type === 'highSpeed' && (!labFeaturesService.isFeatureAvailableForProject('highSpeedMode') || options.company.planType === 'free')) {
|
|
313
272
|
delete options.lightweightMode;
|
|
314
273
|
}
|
|
315
274
|
|
|
275
|
+
if (options.lightweightMode && options.lightweightMode.type === 'highSpeed') {
|
|
276
|
+
console.log('High-speed mode will ignore step delays. Test artifacts like screenshots and logs will only be saved for failed runs. For more information see our docs: https://help.testim.io/docs/high-speed-mode');
|
|
277
|
+
}
|
|
278
|
+
|
|
316
279
|
gridService.keepAlive.start(project);
|
|
317
280
|
analyticsIdentify(project);
|
|
318
281
|
await setMockNetworkRules(options);
|
|
@@ -1,53 +1,43 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class LocalStrategy extends BaseStrategy {
|
|
3
|
+
const utils = require('../utils');
|
|
4
|
+
const logger = require('../commons/logger').getLogger('parallel-worker-manager');
|
|
5
|
+
const { CLI_MODE } = require('../commons/constants');
|
|
6
|
+
const analyticsService = require('../services/analyticsService');
|
|
7
|
+
const config = require('../commons/config');
|
|
8
|
+
const ExecutionQueue = require('../executionQueue');
|
|
9
|
+
|
|
10
|
+
const testimCustomToken = require('../commons/testimCustomToken');
|
|
11
|
+
const testimServicesApi = require('../commons/testimServicesApi');
|
|
12
|
+
const labFeaturesService = require('../services/labFeaturesService');
|
|
13
|
+
const perf = require('../commons/performance-logger');
|
|
14
|
+
const { StopRunOnError } = require('../errors');
|
|
15
|
+
|
|
16
|
+
require('../player/webdriver'); // preload
|
|
17
|
+
|
|
18
|
+
class ParallelWorkerManager {
|
|
21
19
|
constructor(customExtensionLocalLocation) {
|
|
22
|
-
super();
|
|
23
20
|
this.customExtensionLocalLocation = customExtensionLocalLocation;
|
|
24
21
|
}
|
|
25
22
|
|
|
26
|
-
startWorker(worker, options, onTestStarted, onTestCompleted, executionId, onGridSlot, onTestIgnored) {
|
|
27
|
-
throw new Error('need to implement');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
23
|
getWorkerType(mode) {
|
|
31
24
|
switch (mode) {
|
|
32
25
|
case CLI_MODE.SELENIUM:
|
|
33
|
-
return require('
|
|
34
|
-
case CLI_MODE.APPIUM:
|
|
35
|
-
case CLI_MODE.DEVICE_FARM_APPIUM:
|
|
36
|
-
return require('../../workers/WorkerAppium');
|
|
26
|
+
return require('../workers/WorkerSelenium');
|
|
37
27
|
default:
|
|
38
28
|
if (labFeaturesService.isFeatureAvailableForProject('useSameBrowserForMultiTests')) {
|
|
39
|
-
return require('
|
|
29
|
+
return require('../workers/WorkerExtensionSingleBrowser');
|
|
40
30
|
}
|
|
41
|
-
return require('
|
|
31
|
+
return require('../workers/WorkerExtension');
|
|
42
32
|
}
|
|
43
33
|
}
|
|
44
34
|
|
|
45
|
-
createWorkers(count, queue, mode) {
|
|
35
|
+
createWorkers(count, queue, mode, ...args) {
|
|
46
36
|
const Worker = this.getWorkerType(mode);
|
|
47
37
|
const createWorker = () => {
|
|
48
38
|
try {
|
|
49
39
|
perf.log('before new Worker', mode);
|
|
50
|
-
return new Worker(queue,
|
|
40
|
+
return new Worker(queue, ...args);
|
|
51
41
|
} finally {
|
|
52
42
|
perf.log('after new Worker', mode);
|
|
53
43
|
}
|
|
@@ -56,9 +46,9 @@ class LocalStrategy extends BaseStrategy {
|
|
|
56
46
|
return Array.from(new Array(count), createWorker);
|
|
57
47
|
}
|
|
58
48
|
|
|
59
|
-
runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount, stopOnError) {
|
|
49
|
+
async runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount, stopOnError) {
|
|
60
50
|
if (testList && testList.length === 0) {
|
|
61
|
-
return
|
|
51
|
+
return undefined;
|
|
62
52
|
}
|
|
63
53
|
|
|
64
54
|
const runAndWaitToComplete = token => new Promise((resolve, reject) => {
|
|
@@ -72,13 +62,13 @@ class LocalStrategy extends BaseStrategy {
|
|
|
72
62
|
const companyName = options.company && options.company.name;
|
|
73
63
|
const source = options.source || 'cli';
|
|
74
64
|
const user = options.user;
|
|
75
|
-
const
|
|
65
|
+
const companyPlan = options.company && options.company.planType;
|
|
76
66
|
const projectName = options.projectData && options.projectData.name;
|
|
77
67
|
const lightweightMode = options.lightweightMode;
|
|
78
68
|
const sessionType = utils.getSessionType(options);
|
|
79
69
|
|
|
80
70
|
const onTestStarted = (wid, testId, resultId, isRerun, testRetryKey) => {
|
|
81
|
-
|
|
71
|
+
analyticsService.analyticsTestStart({
|
|
82
72
|
authData,
|
|
83
73
|
executionId,
|
|
84
74
|
projectId,
|
|
@@ -87,7 +77,7 @@ class LocalStrategy extends BaseStrategy {
|
|
|
87
77
|
companyId,
|
|
88
78
|
companyName,
|
|
89
79
|
projectName,
|
|
90
|
-
|
|
80
|
+
companyPlan,
|
|
91
81
|
sessionType,
|
|
92
82
|
source,
|
|
93
83
|
user,
|
|
@@ -95,11 +85,8 @@ class LocalStrategy extends BaseStrategy {
|
|
|
95
85
|
});
|
|
96
86
|
return testStatus.testStartAndReport(wid, executionId, resultId, isRerun, testRetryKey);
|
|
97
87
|
};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (lightweightMode && lightweightMode.disableResults && isLocalRun) {
|
|
101
|
-
return undefined;
|
|
102
|
-
}
|
|
88
|
+
|
|
89
|
+
const onTestCompleted = async (wid, testId, testResult, sessionId, isRerun) => {
|
|
103
90
|
const update = {};
|
|
104
91
|
if (lightweightMode && lightweightMode.onlyTestIdsNoSuite) {
|
|
105
92
|
update.show = true;
|
|
@@ -135,18 +122,15 @@ class LocalStrategy extends BaseStrategy {
|
|
|
135
122
|
} else if (options.saucelabs) {
|
|
136
123
|
update.gridName = 'saucelabs-from-options';
|
|
137
124
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
return undefined;
|
|
144
|
-
}).then(() => {
|
|
125
|
+
|
|
126
|
+
await testStatus.testEndAndReport(wid, testResult, executionId, sessionId, isRerun, update)
|
|
127
|
+
.catch(err => logger.error('testEndAndReport threw an error', { err }));
|
|
128
|
+
|
|
145
129
|
if (isRerun) {
|
|
146
130
|
return undefined;
|
|
147
131
|
}
|
|
148
132
|
combinedTestResults[testResult.resultId] = testResult;
|
|
149
|
-
|
|
133
|
+
analyticsService.analyticsTestEnd({
|
|
150
134
|
authData,
|
|
151
135
|
executionId,
|
|
152
136
|
projectId,
|
|
@@ -156,23 +140,24 @@ class LocalStrategy extends BaseStrategy {
|
|
|
156
140
|
companyId,
|
|
157
141
|
companyName,
|
|
158
142
|
projectName,
|
|
159
|
-
|
|
143
|
+
companyPlan,
|
|
160
144
|
sessionType,
|
|
161
145
|
source,
|
|
162
146
|
user,
|
|
163
147
|
lightweightMode,
|
|
148
|
+
logger,
|
|
164
149
|
});
|
|
165
150
|
if (stopOnError && !testResult.success) {
|
|
166
151
|
reject(new StopRunOnError());
|
|
167
|
-
|
|
152
|
+
throw new StopRunOnError();
|
|
168
153
|
}
|
|
169
154
|
const completedTests = Object.keys(combinedTestResults).length;
|
|
170
155
|
if (completedTests === testCount) {
|
|
171
156
|
resolve(combinedTestResults);
|
|
172
157
|
return undefined;
|
|
173
158
|
}
|
|
174
|
-
return
|
|
175
|
-
}
|
|
159
|
+
return undefined;
|
|
160
|
+
};
|
|
176
161
|
|
|
177
162
|
const onTestIgnored = (wid, testResult) => {
|
|
178
163
|
combinedTestResults[testResult.resultId] = testResult;
|
|
@@ -182,6 +167,7 @@ class LocalStrategy extends BaseStrategy {
|
|
|
182
167
|
resolve(combinedTestResults);
|
|
183
168
|
}
|
|
184
169
|
};
|
|
170
|
+
|
|
185
171
|
const onGridSlot = (executionId, resultId, gridInfo) => testStatus.onGridSlot(executionId, resultId, gridInfo);
|
|
186
172
|
|
|
187
173
|
options.userData = {
|
|
@@ -195,25 +181,33 @@ class LocalStrategy extends BaseStrategy {
|
|
|
195
181
|
servicesUrl: config.SERVICES_HOST,
|
|
196
182
|
};
|
|
197
183
|
perf.log('in localStrategy before createWorker');
|
|
198
|
-
this.createWorkers(workerCount, executionQueue, options.mode)
|
|
184
|
+
this.createWorkers(workerCount, executionQueue, options.mode, options, this.customExtensionLocalLocation, executionId, onTestStarted, onTestCompleted, onGridSlot, onTestIgnored)
|
|
199
185
|
.forEach((worker, index) => {
|
|
200
|
-
perf.log('before schedule
|
|
186
|
+
perf.log('before schedule worker.run after createWorkers');
|
|
201
187
|
schedule(() => {
|
|
202
|
-
|
|
188
|
+
perf.log('right before worker.run');
|
|
189
|
+
worker.run();
|
|
203
190
|
}, index);
|
|
204
191
|
});
|
|
205
|
-
function schedule(fn, index) {
|
|
206
|
-
if (index === 0) {
|
|
207
|
-
fn();
|
|
208
|
-
} else {
|
|
209
|
-
setTimeout(fn, index * config.START_WORKER_DELAY_MS);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
192
|
});
|
|
213
193
|
|
|
214
|
-
|
|
215
|
-
|
|
194
|
+
try {
|
|
195
|
+
const token = await testimCustomToken.getCustomTokenV3();
|
|
196
|
+
return await runAndWaitToComplete(token);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
logger.error('failed running parallel workers', { executionId, err });
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
function schedule(fn, index) {
|
|
206
|
+
if (index === 0) {
|
|
207
|
+
fn();
|
|
208
|
+
} else {
|
|
209
|
+
setTimeout(fn, index * config.START_WORKER_DELAY_MS);
|
|
216
210
|
}
|
|
217
211
|
}
|
|
218
212
|
|
|
219
|
-
module.exports =
|
|
213
|
+
module.exports = ParallelWorkerManager;
|