@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.
Files changed (70) hide show
  1. package/README.md +1 -1
  2. package/cli/onExit.js +12 -1
  3. package/cli.js +5 -1
  4. package/codim/codim-npm-package/index.ts +1 -0
  5. package/commons/constants.js +0 -25
  6. package/commons/featureFlags.js +2 -0
  7. package/commons/socket/testResultService.js +4 -14
  8. package/commons/testimAnalytics.js +0 -1
  9. package/commons/testimDesiredCapabilitiesBuilder.js +0 -95
  10. package/commons/testimServicesApi.js +10 -80
  11. package/executionQueue.js +7 -4
  12. package/npm-shrinkwrap.json +956 -520
  13. package/package.json +3 -1
  14. package/player/chromeLauncherTestPlayer.js +5 -2
  15. package/player/stepActions/apiStepAction.js +1 -0
  16. package/player/stepActions/baseJsStepAction.js +5 -1
  17. package/player/stepActions/pixelValidationStepAction.js +28 -0
  18. package/player/stepActions/salesforceAutoLoginStepAction.js +39 -0
  19. package/player/stepActions/scripts/focusElement.js +5 -3
  20. package/player/stepActions/stepActionRegistrar.js +5 -47
  21. package/player/utils/eyeSdkService.js +230 -0
  22. package/reports/consoleReporter.js +0 -20
  23. package/reports/reporter.js +0 -21
  24. package/runOptions.js +13 -89
  25. package/runner.js +9 -46
  26. package/runners/{strategies/LocalStrategy.js → ParallelWorkerManager.js} +60 -66
  27. package/runners/TestPlanRunner.js +286 -67
  28. package/runners/runnerUtils.js +73 -0
  29. package/{runners/strategies/BaseStrategy.js → services/analyticsService.js} +41 -28
  30. package/services/gridService.js +24 -16
  31. package/services/gridService.test.js +21 -21
  32. package/services/lambdatestService.js +1 -1
  33. package/testRunHandler.js +1 -1
  34. package/testRunStatus.js +30 -20
  35. package/utils.js +5 -5
  36. package/workers/BaseWorker.js +38 -39
  37. package/workers/BaseWorker.test.js +1 -1
  38. package/workers/WorkerExtensionSingleBrowser.js +6 -3
  39. package/commons/apkUploader/apkUploader.js +0 -46
  40. package/commons/apkUploader/apkUploaderFactory.js +0 -68
  41. package/commons/apkUploader/deviceFarmApkUploader.js +0 -41
  42. package/commons/apkUploader/saucelabsApkUploader.js +0 -36
  43. package/commons/apkUploader/testObjectApkUploader.js +0 -34
  44. package/player/mobile/mobileTestPlayer.js +0 -80
  45. package/player/mobile/mobileWebDriver.js +0 -155
  46. package/player/mobile/services/frameLocatorMock.js +0 -18
  47. package/player/mobile/services/mobilePortSelector.js +0 -22
  48. package/player/mobile/services/mobileTabService.js +0 -241
  49. package/player/mobile/utils/mobileScreenshotUtils.js +0 -46
  50. package/player/mobile/utils/mobileWindowUtils.js +0 -84
  51. package/player/stepActions/mobile/android/androidLocateStepAction.js +0 -122
  52. package/player/stepActions/mobile/android/androidLongClickStepAction.js +0 -12
  53. package/player/stepActions/mobile/android/androidScrollStepAction.js +0 -134
  54. package/player/stepActions/mobile/android/androidSpecialKeyStepAction.js +0 -22
  55. package/player/stepActions/mobile/android/androidSwipeStepAction.js +0 -32
  56. package/player/stepActions/mobile/androidGlobalActionStepAction.js +0 -12
  57. package/player/stepActions/mobile/androidTapStepAction.js +0 -19
  58. package/player/stepActions/mobile/androidTextChangeStepAction.js +0 -23
  59. package/player/stepActions/mobile/ios/iosLocateStepAction.js +0 -124
  60. package/player/stepActions/mobile/ios/iosScrollStepAction.js +0 -76
  61. package/runners/AnonymousTestPlanRunner.js +0 -106
  62. package/runners/BaseRunner.js +0 -42
  63. package/runners/BaseTestPlanRunner.js +0 -194
  64. package/runners/DeviceFarmRemoteRunner.js +0 -50
  65. package/runners/SchedulerRemoteRunner.js +0 -47
  66. package/runners/strategies/DeviceFarmStrategy.js +0 -195
  67. package/runners/strategies/LocalDeviceFarmStrategy.js +0 -12
  68. package/runners/strategies/LocalTestStrategy.js +0 -14
  69. package/runners/strategies/Strategy.js +0 -17
  70. package/workers/WorkerAppium.js +0 -70
@@ -1,106 +0,0 @@
1
- 'use strict';
2
-
3
- const path = require('path');
4
- const Promise = require('bluebird');
5
-
6
- const _ = require('lodash');
7
-
8
- const reporter = require('../reports/reporter');
9
- const logger = require('../commons/logger').getLogger('suite-runner');
10
- const utils = require('../utils.js');
11
- const { ArgError } = require('../errors');
12
- const perf = require('../commons/performance-logger');
13
-
14
- const BaseTestPlanRunner = require('./BaseTestPlanRunner');
15
-
16
- class AnonymousTestPlanRunner extends BaseTestPlanRunner {
17
- runAnonymousTestPlan(options, branchToUse) {
18
- logger.info('start to run anonymous', {
19
- options: Object.assign({}, options, { token: undefined }),
20
- branchToUse,
21
- });
22
-
23
- return this.prepareForTestResources(options)
24
- .log('after prepareForTestResoutces')
25
- .then(() => getSuite(options, branchToUse))
26
- .log('after getSuite')
27
- .then((suiteResult) => {
28
- if (!suiteResult.tests[0] || suiteResult.tests[0].length === 0) {
29
- if (options.rerunFailedByRunId) {
30
- throw new ArgError('No failed tests found in the provided run');
31
- }
32
- if (options.passZeroTests) {
33
- return [];
34
- }
35
- throw new ArgError('No tests to run');
36
- }
37
- branchToUse = suiteResult.branch || branchToUse;
38
- if (options.rerunFailedByRunId && !suiteResult.runName) {
39
- if (!suiteResult.runExists) {
40
- throw new ArgError('Invalid run ID - no such run.');
41
- }
42
- const isAnonymouslyNamedRun = suiteResult.runName === '';
43
- if (isAnonymouslyNamedRun) {
44
- suiteResult.runName = `rerun-${options.rerunFailedByRunId}`;
45
- }
46
- }
47
- const testPlanName = options.overrideExecutionName || suiteResult.runName || _.concat(options.label, options.name, options.suites).join(' ');
48
- const isAnonymous = true;
49
- perf.log('Right before validateConfig + runTestPlan Promise.map');
50
- return Promise.map(suiteResult.tests, suiteTests => {
51
- //override result id for remote run mode and run only the first test data
52
- if (options.resultId) {
53
- const firstTest = _.first(suiteTests);
54
- firstTest.resultId = options.resultId;
55
- suiteTests = [firstTest];
56
- }
57
- return this.validateConfig(options, suiteTests)
58
- .log('right before runTestPlan')
59
- .then(() => this.runTestPlan([], suiteTests, [], options, testPlanName, null, branchToUse, isAnonymous))
60
- .log('right after runTestPlan')
61
- .tap(async res => {
62
- const isCodeMode = options.files.length > 0;
63
- await reporter.onTestPlanFinished(res.results, testPlanName, this.startTime, res.executionId, isAnonymous, isCodeMode, res.childTestResults);
64
- });
65
- }).then(async results => { // array of results per execution
66
- const flattenResults = _(results).flattenDeep().value();
67
- perf.log('right before onAllTestPlansFinished');
68
- await reporter.onAllTestPlansFinished(flattenResults);
69
- perf.log('right after onAllTestPlansFinished');
70
- return flattenResults.map(res => res.results).reduce((total, cur) => Object.assign(total, cur), {});
71
- });
72
- });
73
- }
74
- }
75
-
76
- async function getSuite(options, branchToUse) {
77
- if (options.lightweightMode && options.lightweightMode.onlyTestIdsNoSuite && options.testId) {
78
- return { tests: [options.testId.map(testId => ({ testId, testConfig: { }, resultId: utils.guid() }))] };
79
- }
80
- // local code test
81
- if (options.files.length > 0) {
82
- const { buildCodeTests } = require('./buildCodeTests');
83
- let webpackConfig = {};
84
- if (options.webpackConfig) {
85
- const webpackConfigPath = path.join(process.cwd(), options.webpackConfig);
86
- webpackConfig = require(webpackConfigPath);
87
- }
88
-
89
- return buildCodeTests(options.files, webpackConfig, { baseUrl: options.baseUrl });
90
- }
91
- // regular test
92
- const servicesApi = require('../commons/testimServicesApi');
93
- return await servicesApi.getSuiteTestList({
94
- projectId: options.project,
95
- labels: options.label,
96
- testIds: options.testId,
97
- testNames: options.name,
98
- testConfigNames: options.testConfigNames,
99
- suiteNames: options.suites,
100
- suiteIds: options.suiteIds,
101
- branch: branchToUse,
102
- rerunFailedByRunId: options.rerunFailedByRunId,
103
- testConfigIds: options.testConfigIds,
104
- });
105
- }
106
- module.exports = AnonymousTestPlanRunner;
@@ -1,42 +0,0 @@
1
- const Promise = require('bluebird');
2
- const _ = require('lodash');
3
- const utils = require('../utils');
4
- const testimCustomToken = require('../commons/testimCustomToken');
5
- const analytics = require('../commons/testimAnalytics');
6
- const {ArgError} = require('../errors');
7
-
8
- class BaseRunner {
9
- constructor(strategy) {
10
- this.strategy = strategy;
11
- this.startTime = Date.now();
12
- }
13
-
14
- analyticsExecsStart({ executionId, projectId, sessionType }) {
15
- analytics.trackWithCIUser('batch-run-ci', {
16
- executionId,
17
- projectId,
18
- sessionType,
19
- });
20
- }
21
-
22
- validateConfig(options, testList) {
23
- let supportedBrowsers = options.mode === 'extension' ? [
24
- 'edge-chromium', 'chrome',
25
- ] : [
26
- 'ie11', 'firefox', 'chrome', 'edge', 'edge-chromium', 'safari', 'safari technology preview', 'browser', 'android', 'ios', 'iphone', 'ipad',
27
- ];
28
- let diff = _.difference(utils.getUniqBrowsers(options, testList), supportedBrowsers);
29
-
30
- if (diff.length > 0) {
31
- analytics.trackWithCIUser('invalid-config-run', {
32
- browser: diff.join(", "),
33
- mode: 'runner'
34
- });
35
- return Promise.reject(new ArgError(`browser type <${diff}> is not supported in ${options.mode} mode.`));
36
- }
37
-
38
- return Promise.resolve(testList);
39
- }
40
- }
41
-
42
- module.exports = BaseRunner;
@@ -1,194 +0,0 @@
1
- 'use strict';
2
-
3
- const Promise = require('bluebird');
4
- const _ = require('lodash');
5
- const constants = require('../commons/constants');
6
-
7
- const TESTIM_RUN_STATUS = constants.testRunStatus;
8
- const { CLI_MODE } = constants;
9
- const reporter = require('../reports/reporter');
10
- const RealDataService = require('../commons/socket/realDataService');
11
- const testimServicesApi = require('../commons/testimServicesApi');
12
- const testimCustomToken = require('../commons/testimCustomToken');
13
- const BaseRunner = require('./BaseRunner');
14
- const TestRunStatus = require('../testRunStatus');
15
- const config = require('../commons/config');
16
- const utils = require('../utils');
17
- const { StopRunOnError } = require('../errors');
18
- const Logger = require('../commons/logger');
19
- const perf = require('../commons/performance-logger');
20
-
21
- const guid = utils.guid;
22
- const _logger = Logger.getLogger('base-test-plan-runner');
23
- const TDK_CHILD_RESULTS_TIMEOUT = 1000 * 60 * 5;
24
-
25
- class BaseTestPlanRunner extends BaseRunner {
26
- constructor(strategy) {
27
- super(strategy);
28
- this.runTestPlan = Promise.method(this.runTestPlan);
29
- }
30
- runTestAllPhases(beforeTests, tests, afterTests, branchToUse, tpOptions, executionId, testStatus) {
31
- const executionResults = {};
32
- const authData = testimCustomToken.getTokenV3UserData();
33
-
34
- const runBeforeTests = (beforeTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
35
- const workerCount = 1;
36
- const stopOnError = true;
37
- return this.strategy.runTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
38
- .then(beforeTestsResults => Object.assign(executionResults, beforeTestsResults));
39
- };
40
-
41
- const runTestPlanTests = (tests, testStatus, executionId, tpOptions, branchToUse, authData) => {
42
- const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
43
- const stopOnError = false;
44
- perf.log('right before this.strategy.runTests');
45
- return this.strategy.runTests(tests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
46
- .log('right after this.strategy.runTests')
47
- .then(testsResults => Object.assign(executionResults, testsResults));
48
- };
49
-
50
- const runAfterTests = (afterTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
51
- const workerCount = 1;
52
- const stopOnError = false;
53
- return this.strategy.runTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
54
- .then(afterTestsResults => Object.assign(executionResults, afterTestsResults));
55
- };
56
-
57
- function catchBeforeTestsFailed(executionId) {
58
- return testStatus.markAllQueuedTests(executionId, constants.runnerTestStatus.ABORTED, 'aborted', false);
59
- }
60
-
61
- const sessionType = utils.getSessionType(tpOptions);
62
- this.analyticsExecsStart({ authData, executionId, projectId: tpOptions.project, sessionType });
63
- perf.log('right before runBeforeTests');
64
- return runBeforeTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData)
65
- .log('right before runTestPlanTests')
66
- .then(() => runTestPlanTests(tests, testStatus, executionId, tpOptions, branchToUse, authData))
67
- .log('right after runTestPlanTests')
68
- .then(() => runAfterTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData))
69
- .then(() => executionResults)
70
- .catch(StopRunOnError, () => catchBeforeTestsFailed(executionId));
71
- }
72
-
73
- prepareForTestResources(tpOptions) {
74
- if (tpOptions.mode !== CLI_MODE.APPIUM && !(this.strategy.constructor.name === 'DeviceFarmStrategy')) {
75
- return Promise.resolve();
76
- }
77
- const apkUploaderFactory = require('../commons/apkUploader/apkUploaderFactory');
78
- return apkUploaderFactory.uploadApk(tpOptions);
79
- }
80
-
81
- async initRealDataService(projectId) {
82
- const realDataService = new RealDataService();
83
- await realDataService.init(projectId);
84
- return realDataService;
85
- }
86
-
87
- async listenToTestCreatedInFile(realDataService, projectId, runId, testStatus) {
88
- const childTestResults = {};
89
- realDataService.joinToTestResultsByRunId(runId, projectId);
90
- const promise = new Promise(resolve => {
91
- realDataService.listenToTestResultsByRunId(runId, testResult => {
92
- const resultId = testResult.id;
93
- if (!testStatus.getTestResult(resultId)) {
94
- const prevTestResult = childTestResults[resultId];
95
- const mergedTestResult = _.merge({}, prevTestResult, testResult, { resultId });
96
- childTestResults[resultId] = mergedTestResult;
97
- if (!prevTestResult || prevTestResult.status !== testResult.status) {
98
- const parentTestResult = testStatus.getTestResult(mergedTestResult.parentResultId) || { workerId: 1 };
99
- const workerId = parentTestResult.workerId;
100
- if ([TESTIM_RUN_STATUS.RUNNING].includes(testResult.status)) {
101
- reporter.onTestStarted(mergedTestResult, workerId);
102
- }
103
- if ([TESTIM_RUN_STATUS.COMPLETED].includes(testResult.status)) {
104
- mergedTestResult.duration = (mergedTestResult.endTime - mergedTestResult.startTime) || 0;
105
- reporter.onTestFinished(mergedTestResult, workerId);
106
- }
107
- }
108
- }
109
-
110
- const allChildTestResultCompleted = !(Object.values(childTestResults)
111
- .some(result => ['QUEUED', 'RUNNING'].includes(result.runnerStatus)));
112
-
113
- const allParentTestResultCompleted = !(Object.values(testStatus.getAllTestResults())
114
- .some(result => ['QUEUED', 'RUNNING'].includes(result.status)));
115
-
116
- if (allChildTestResultCompleted && allParentTestResultCompleted) {
117
- return resolve(Object.values(childTestResults));
118
- }
119
-
120
- if (allParentTestResultCompleted && !allChildTestResultCompleted) {
121
- // wait 10 sec to handle race condition when parent test result (file) finished before child test result
122
- return Promise.delay(10000)
123
- .then(() => {
124
- if (promise.isPending()) {
125
- // TODO(Benji) we are missing the child test results here.
126
- // we are resolving here with partial data - we should consider fetching it
127
- // from the server
128
- resolve(childTestResults);
129
- }
130
- });
131
- }
132
- return undefined;
133
- });
134
- });
135
-
136
- return await promise;
137
- }
138
-
139
- async runTestPlan(beforeTests, tests, afterTests, tpOptions, testPlanName, testPlanId, branch, isAnonymous) {
140
- const executionId = guid();
141
- const projectId = tpOptions.project;
142
- Logger.setExecutionId(executionId);
143
- beforeTests.forEach(test => { test.isBeforeTestPlan = true; });
144
- afterTests.forEach(test => { test.isAfterTestPlan = true; });
145
- const testStatus = new TestRunStatus(_.concat(beforeTests, tests, afterTests), tpOptions, testPlanId, branch);
146
-
147
- const configs = _(_.concat(beforeTests, tests, afterTests)).map(test => (test.overrideTestConfig && test.overrideTestConfig.name) || '').uniq().filter(Boolean)
148
- .value();
149
- const configName = configs && configs.length === 1 ? configs[0] : null;
150
-
151
- const isCodeMode = tpOptions.files.length > 0;
152
-
153
- if (isCodeMode && tpOptions.mode === constants.CLI_MODE.SELENIUM) {
154
- // in selenium mode we don't need to wait for the runner and clickim to sync, so we don't need to wait for reports.
155
- testStatus.setAsyncReporting(true);
156
- }
157
- const testListInfoPromise = tpOptions.lightweightMode && tpOptions.lightweightMode.onlyTestIdsNoSuite ?
158
- { beforeTests, tests, afterTests } :
159
- testStatus.executionStart(executionId, projectId, this.startTime, testPlanName);
160
- let childTestResults;
161
- if (isCodeMode) {
162
- childTestResults = Promise.try(async () => {
163
- const realDataService = await this.initRealDataService(projectId);
164
- return this.listenToTestCreatedInFile(realDataService, projectId, executionId, testStatus);
165
- });
166
- }
167
- perf.log('before testListInfoPromise');
168
- const testListInfo = await testListInfoPromise;
169
- if (!(tpOptions.lightweightMode && tpOptions.lightweightMode.onlyTestIdsNoSuite)) {
170
- reporter.onTestPlanStarted(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, testPlanName, executionId, isAnonymous, configName, isCodeMode);
171
- }
172
-
173
- perf.log('before runTestAllPhases');
174
- const results = await this.runTestAllPhases(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, branch, tpOptions, executionId, testStatus);
175
- const childResults = await Promise.resolve(childTestResults)
176
- .timeout(TDK_CHILD_RESULTS_TIMEOUT)
177
- .catch(async () => {
178
- _logger.warn('timed out waiting for child resutls on websocket. using REST fallback', { projectId, executionId });
179
- const testResults = await testimServicesApi.getRealData(projectId, 'testResult', `runId=${executionId}&sort=runOrder`);
180
- return _.chain((testResults && testResults.data && testResults.data.docs) || [])
181
- .groupBy('parentResultId')
182
- .omit('undefined')
183
- .values()
184
- .flatten()
185
- .value();
186
- });
187
- perf.log('before executionEnd');
188
- await testStatus.executionEnd(executionId);
189
- perf.log('after executionEnd');
190
- return { results, executionId, testPlanName, configName, childTestResults: childResults };
191
- }
192
- }
193
-
194
- module.exports = BaseTestPlanRunner;
@@ -1,50 +0,0 @@
1
- "use strict";
2
-
3
- const utils = require('../utils');
4
- const config = require('../commons/config');
5
- const testimCustomToken = require('../commons/testimCustomToken');
6
- const BaseRunner = require('./BaseRunner');
7
- const TestRunStatus = require('../testRunStatus');
8
- const reporter = require("../reports/reporter");
9
- const Logger = require('../commons/logger');
10
- const gridService = require('../services/gridService');
11
- const logger = Logger.getLogger('remote-test-runner');
12
-
13
- class DeviceFarmRemoteRunner extends BaseRunner {
14
- runExecution(testList, testStatus, executionId, options, branchToUse) {
15
- const projectId = options.project;
16
- const sessionType = utils.getSessionType(options);
17
- // report exec start analytics
18
- const authData = testimCustomToken.getTokenV3UserData();
19
- this.analyticsExecsStart({authData, executionId, projectId, sessionType});
20
- const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || options.parallel;
21
-
22
- return this.strategy.runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount);
23
- }
24
-
25
- runTest(executionId, testList, gridInfo, branchToUse, options) {
26
- Logger.setExecutionId(executionId);
27
-
28
- logger.info("start to remote runner", {
29
- executionId: executionId,
30
- options: Object.assign({}, options, {token: undefined}),
31
- branchToUse: branchToUse,
32
- });
33
-
34
- const testPlanName = "remote run";
35
- const testStatus = new TestRunStatus(testList, options, null, branchToUse);
36
- reporter.onTestPlanStarted([], testList, [], testPlanName, executionId);
37
-
38
- const workerId = 1;
39
- const browserType = options.projectData.type; //android or ios
40
- const {gridId, slotId} = gridInfo;
41
- gridService.addItemToGridCache(workerId, gridId, slotId, browserType);
42
- options.disableWindowAnimation = options.remoteRunObject.echoedOptions.disableWindowAnimation
43
- options.baseUrl = options.remoteRunObject.echoedOptions.baseUrl
44
- return this.runExecution(testList, testStatus, executionId, options, branchToUse)
45
- .tap(results => reporter.onTestPlanFinished(results, testPlanName, this.startTime, executionId))
46
- .then(combinedTestResults => combinedTestResults);
47
- }
48
- }
49
-
50
- module.exports = DeviceFarmRemoteRunner;
@@ -1,47 +0,0 @@
1
- "use strict";
2
-
3
- const utils = require('../utils');
4
- const config = require('../commons/config');
5
- const testimCustomToken = require('../commons/testimCustomToken');
6
- const BaseRunner = require('./BaseRunner');
7
- const TestRunStatus = require('../testRunStatus');
8
- const reporter = require("../reports/reporter");
9
- const guid = require('../utils').guid;
10
- const Logger = require('../commons/logger');
11
- const logger = Logger.getLogger('remote-test-runner');
12
-
13
- class SchedulerRemoteRunner extends BaseRunner {
14
- runExecution(testList, testStatus, executionId, options, branchToUse) {
15
- const sessionType = utils.getSessionType(options);
16
- const projectId = options.project;
17
- // report exec start analytics
18
- const authData = testimCustomToken.getTokenV3UserData();
19
- this.analyticsExecsStart({authData, executionId, projectId, sessionType});
20
- const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || options.parallel;
21
-
22
- return this.strategy.runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount);
23
- }
24
-
25
- runTest(options, branchToUse) {
26
- const executionId = options.executionId || guid();
27
- const test = options.testObject;
28
- Logger.setExecutionId(executionId);
29
-
30
- logger.info("start to run test", {
31
- executionId: executionId,
32
- options: Object.assign({}, options, {token: undefined}),
33
- branchToUse: branchToUse,
34
- test: test
35
- });
36
-
37
- const testArray = [test];
38
- const testPlanName = options.overrideExecutionName || "remote run";
39
- const testStatus = new TestRunStatus(testArray, options, null, branchToUse);
40
- reporter.onTestPlanStarted([], testArray, [], testPlanName, executionId);
41
- return this.runExecution(testArray, testStatus, executionId, options, branchToUse)
42
- .tap(results => reporter.onTestPlanFinished(results, testPlanName, this.startTime, executionId))
43
- .then(combinedTestResults => combinedTestResults);
44
- }
45
- }
46
-
47
- module.exports = SchedulerRemoteRunner;
@@ -1,195 +0,0 @@
1
- 'use strict';
2
-
3
- const Promise = require('bluebird');
4
- const _ = require('lodash');
5
- const { CLI_MODE, runnerTestStatus } = require('../../commons/constants');
6
- const BaseStrategy = require('./BaseStrategy');
7
- const config = require('../../commons/config');
8
- const { deviceFarm, testRunStatus } = require('../../commons/constants');
9
- const logger = require('../../commons/logger').getLogger('deviceFarm-strategy');
10
- const utils = require('../../utils');
11
- const RealDataService = require('../../commons/socket/realDataService');
12
- const { getBrowserWithRetries: getDeviceWithRetries } = require('../../workers/workerUtils');
13
- const { GetBrowserError, ArgError } = require('../../errors');
14
- const { getAppCaps } = require('../../commons/apkUploader/apkUploaderFactory');
15
- const reporter = require('../../reports/reporter');
16
- const BaseWorker = require('../../workers/BaseWorker');
17
-
18
- const testimServicesApi = require('../../commons/testimServicesApi');
19
- const gridService = require('../../services/gridService');
20
-
21
- const MAX_EXECUTION_TIMEOUT = 150 * 60 * 1000; //150 min is the maximum allowed by device farm
22
- const STATUS_CHECK_INTERVAL = 20000;
23
-
24
- const DF_RUN_STATUS = deviceFarm.status;
25
- const DF_RUN_RESULT = deviceFarm.result;
26
- const TESTIM_RUN_STATUS = testRunStatus;
27
-
28
- class DeviceFarmStrategy extends BaseStrategy {
29
- constructor() {
30
- super();
31
- this.lastDeviceFarmStatus = DF_RUN_STATUS.INITIALIZING;
32
- }
33
-
34
- getDeviceFarmRunStatus(projectId, runArn) {
35
- return testimServicesApi.getDeviceFarmRun(projectId, runArn)
36
- .then(runInfo => {
37
- if (this.lastDeviceFarmStatus !== runInfo.status) {
38
- logger.info(`DeviceFarm run status changed from: ${this.lastDeviceFarmStatus} to ${runInfo.status}`);
39
- this.lastDeviceFarmStatus = runInfo.status;
40
- }
41
- if ([DF_RUN_STATUS.COMPLETED, DF_RUN_STATUS.STOPPING].includes(runInfo.status)) {
42
- return runInfo;
43
- }
44
- throw new Error('still running');
45
- });
46
- }
47
-
48
- convertTestResultObjectStatusToReportFormat(executionResults) {
49
- Object.keys(executionResults).forEach(resultId => {
50
- executionResults[resultId].status = executionResults[resultId].success ? runnerTestStatus.PASSED : runnerTestStatus.FAILED;
51
- });
52
- return executionResults;
53
- }
54
-
55
- convertTestResultArrayStatusToReportFormat(executionResults) {
56
- executionResults.forEach(result => {
57
- result.status = result.success ? runnerTestStatus.PASSED : runnerTestStatus.FAILED;
58
- });
59
- return executionResults;
60
- }
61
-
62
- buildConfiguration(testList) {
63
- const { overrideTestConfig } = _.uniqBy(testList, 'overrideTestConfig.name')[0];
64
- if (_.isEmpty(overrideTestConfig)) {
65
- return {};
66
- }
67
- const configuration = Object.assign({}, overrideTestConfig);
68
- const [platformName, platformVersion] = configuration.os.split(' ');
69
-
70
- return {
71
- platformName,
72
- deviceName: configuration.browser,
73
- platformVersion,
74
- };
75
- }
76
-
77
- buildDeviceFarmConfiguration(options) {
78
- const validateOptionKeys = (option) => {
79
- const { deviceName, platformVersion /*platformName, appiumVersion,*/ } = option;
80
- return deviceName && platformVersion;
81
- };
82
- const mapOptionToConfig = (option) => ({
83
- deviceName: option.deviceName,
84
- platformVersion: option.platformVersion,
85
- });
86
-
87
- if (_.isArray(options)) {
88
- return options.filter(validateOptionKeys).map(mapOptionToConfig);
89
- }
90
- return validateOptionKeys(options) ? mapOptionToConfig(options) : {};
91
- }
92
-
93
- runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount, stopOnError) {
94
- if (testList && testList.length === 0) {
95
- return Promise.resolve();
96
- }
97
- const executionResults = {};
98
- const projectId = options.project;
99
- const companyId = options.company.companyId;
100
- const workerId = BaseWorker.getWorkerId();
101
- const testResultId = '';
102
-
103
- const getBrowserTimeout = options.browserTimeout;
104
- const newBrowserWaitTimeout = options.newBrowserWaitTimeout;
105
-
106
- const configuration = this.buildConfiguration(testList);
107
- if (_.isEmpty(configuration)) {
108
- return Promise.reject(new ArgError('--test-config is missing or not properly used'));
109
- }
110
-
111
- const realDataService = new RealDataService();
112
- const releaseSlotOnTestFinished = true;
113
- const callbacksForGetDeviceRetryLogic = {
114
- getBrowserOnce() {
115
- reporter.onGetSession(workerId, `for execution ${executionId}`, CLI_MODE.APPIUM);
116
- return gridService.getGridSlot(configuration.platformName, executionId, testResultId, () => {}, options, workerId);
117
- },
118
- testPlayerFactory: () => {}, // no factory since this is a remote run
119
- releaseSlotOnTestFinished,
120
- };
121
- const deviceFetchConfig = {
122
- totalTimeoutDuration: newBrowserWaitTimeout,
123
- singleGetBrowserDuration: getBrowserTimeout,
124
- projectId,
125
- workerId,
126
- reporter,
127
- };
128
- return realDataService.init(projectId)
129
- .then(() => getDeviceWithRetries(callbacksForGetDeviceRetryLogic, deviceFetchConfig)).then(gridInfo => {
130
- const allowedRemoteRunEnv = Object.keys(config);
131
- const env = _.reduce(process.env, (envObj, value, key) => {
132
- if (allowedRemoteRunEnv.includes(key)) {
133
- envObj[key] = value;
134
- }
135
- return envObj;
136
- }, {});
137
-
138
- const remoteRunObject = {
139
- gridInfo,
140
- testList,
141
- echoedOptions: {
142
- disableWindowAnimation: options.disableWindowAnimation,
143
- baseUrl: options.baseUrl,
144
- },
145
- };
146
- const projectArn = gridInfo.arn;
147
- const { appArn } = getAppCaps(gridInfo);
148
- reporter.onWaitForDevice(workerId, executionId);
149
- realDataService.joinToTestResultsByRunId(executionId, projectId);
150
- return testimServicesApi.createDeviceFarmRun(companyId, projectId, projectArn, appArn, configuration, branchToUse, executionId, env, remoteRunObject);
151
- }).then(run => {
152
- realDataService.listenToTestResultsByRunId(executionId, testResult => {
153
- const prevTestResult = executionResults[testResult.id];
154
- const mergedTestResult = _.merge({}, prevTestResult, testResult, { resultId: testResult.id });
155
- if (!prevTestResult || prevTestResult.status !== testResult.status) {
156
- if ([TESTIM_RUN_STATUS.RUNNING].includes(testResult.status)) {
157
- testStatus.testStart(workerId, executionId, mergedTestResult.id);
158
- }
159
- if ([TESTIM_RUN_STATUS.COMPLETED].includes(testResult.status)) {
160
- testStatus.testEnd(workerId, Object.assign({}, mergedTestResult), executionId);
161
- }
162
- }
163
- executionResults[testResult.id] = mergedTestResult;
164
- });
165
- return utils.runWithRetries(
166
- () => this.getDeviceFarmRunStatus(projectId, run.arn), MAX_EXECUTION_TIMEOUT, STATUS_CHECK_INTERVAL);
167
- })
168
- .then(runInfo => {
169
- if ([DF_RUN_RESULT.SKIPPED].includes(runInfo.result) &&
170
- runInfo.deviceSelectionResult &&
171
- runInfo.deviceSelectionResult.matchedDevicesCount === 0) {
172
- console.log('Device Farm Error: The device in your configuration is not supported');
173
- }
174
- if ([DF_RUN_RESULT.STOPPED].includes(runInfo.result)) {
175
- console.log('Device Farm Error: The test has been stopped. Please try running it again in a few minutes');
176
- }
177
- if ([DF_RUN_RESULT.ERRORED].includes(runInfo.result)) {
178
- console.log(`Device Farm Error: ${runInfo.message}`);
179
- return testStatus.markAllQueuedTests(executionId, runnerTestStatus.ABORTED, 'aborted', false);
180
- }
181
- // Results from socket (currently unused).
182
- this.convertTestResultObjectStatusToReportFormat(executionResults);
183
- // Results from server.
184
- return testimServicesApi.getRealData(projectId, 'testResult', `runId=${executionId}&sort=runOrder`)
185
- .then(res => this.convertTestResultArrayStatusToReportFormat(res.data.docs));
186
- })
187
- .catch(GetBrowserError, err => testStatus.markAllQueuedTests(executionId, runnerTestStatus.FAILED, err.message, false))
188
- .finally(() => {
189
- realDataService.stopListenToTestResultsByRunId();
190
- return gridService.releaseGridSlot(workerId, projectId);
191
- });
192
- }
193
- }
194
-
195
- module.exports = DeviceFarmStrategy;
@@ -1,12 +0,0 @@
1
- 'use strict';
2
-
3
- const LocalStrategy = require('./LocalStrategy');
4
-
5
- class LocalDeviceFarmStrategy extends LocalStrategy {
6
- startWorker(worker, options, onTestStarted, onTestCompleted, executionId, onGridSlot, onTestIgnored) {
7
- const releaseSlotOnTestFinished = false;
8
- worker.start(options, onTestStarted, onTestCompleted, executionId, onGridSlot, onTestIgnored, releaseSlotOnTestFinished);
9
- }
10
- }
11
-
12
- module.exports = LocalDeviceFarmStrategy;
@@ -1,14 +0,0 @@
1
- 'use strict';
2
-
3
- const LocalStrategy = require('./LocalStrategy');
4
- const perf = require('../../commons/performance-logger');
5
-
6
- class LocalTestStrategy extends LocalStrategy {
7
- startWorker(worker, options, onTestStarted, onTestCompleted, executionId, onGridSlot, onTestIgnored) {
8
- const releaseSlotOnTestFinished = true;
9
- perf.log('right before worker.start in startWorker');
10
- worker.start(options, onTestStarted, onTestCompleted, executionId, onGridSlot, onTestIgnored, releaseSlotOnTestFinished);
11
- }
12
- }
13
-
14
- module.exports = LocalTestStrategy;