@testim/testim-cli 3.289.0 → 3.290.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 (217) hide show
  1. package/cli.js +22390 -122
  2. package/cli.js.map +1 -0
  3. package/npm-shrinkwrap.json +1951 -203
  4. package/package.json +9 -5
  5. package/OverrideTestDataBuilder.js +0 -117
  6. package/agent/routers/cliJsCode/index.js +0 -13
  7. package/agent/routers/cliJsCode/router.js +0 -63
  8. package/agent/routers/cliJsCode/service.js +0 -705
  9. package/agent/routers/codim/router.js +0 -69
  10. package/agent/routers/codim/router.test.js +0 -60
  11. package/agent/routers/codim/service.js +0 -193
  12. package/agent/routers/general/index.js +0 -36
  13. package/agent/routers/hybrid/registerRoutes.js +0 -81
  14. package/agent/routers/index.js +0 -56
  15. package/agent/routers/playground/router.js +0 -77
  16. package/agent/routers/playground/service.js +0 -96
  17. package/agent/routers/standalone-browser/registerRoutes.js +0 -47
  18. package/agent/server.js +0 -150
  19. package/cdpTestRunner.js +0 -86
  20. package/chromiumInstaller.js +0 -91
  21. package/cli/isCiRun.js +0 -10
  22. package/cli/onExit.js +0 -65
  23. package/cli/writeStackTrace.js +0 -27
  24. package/cliAgentMode.js +0 -384
  25. package/codim/codim-cli.js +0 -91
  26. package/codim/codim-npm-package/index.ts +0 -427
  27. package/codim/codim-npm-package/package-lock.json +0 -14
  28. package/codim/codim-npm-package/package.json +0 -14
  29. package/codim/hybrid-utils.js +0 -28
  30. package/codim/measure-perf.js +0 -41
  31. package/codim/template.js/.idea/workspace.xml +0 -57
  32. package/codim/template.js/.vscode/launch.json +0 -53
  33. package/codim/template.ts/.idea/workspace.xml +0 -57
  34. package/codim/template.ts/.vscode/launch.json +0 -55
  35. package/commons/AbortError.js +0 -12
  36. package/commons/SeleniumPerfStats.js +0 -58
  37. package/commons/chrome-launcher.js +0 -15
  38. package/commons/chromedriverWrapper.js +0 -70
  39. package/commons/config.js +0 -39
  40. package/commons/constants.js +0 -67
  41. package/commons/detectDebugger.js +0 -19
  42. package/commons/featureAvailabilityService.js +0 -26
  43. package/commons/featureFlags.js +0 -132
  44. package/commons/getSessionPlayerRequire.js +0 -28
  45. package/commons/httpRequest.js +0 -261
  46. package/commons/httpRequestCounters.js +0 -98
  47. package/commons/httpRequestCounters.test.js +0 -38
  48. package/commons/initializeUserWithAuth.js +0 -55
  49. package/commons/lazyRequire.js +0 -105
  50. package/commons/logUtils.js +0 -15
  51. package/commons/logUtils.test.js +0 -21
  52. package/commons/logger.js +0 -178
  53. package/commons/mockNetworkRuleFileSchema.json +0 -140
  54. package/commons/npmWrapper.js +0 -174
  55. package/commons/npmWrapper.test.js +0 -374
  56. package/commons/performance-logger.js +0 -71
  57. package/commons/preloadTests.js +0 -29
  58. package/commons/prepareRunner.js +0 -85
  59. package/commons/prepareRunner.test.js +0 -144
  60. package/commons/prepareRunnerAndTestimStartUtils.js +0 -198
  61. package/commons/prepareRunnerAndTestimStartUtils.test.js +0 -73
  62. package/commons/requireWithFallback.js +0 -25
  63. package/commons/runnerFileCache.js +0 -204
  64. package/commons/socket/baseSocketServiceSocketIO.js +0 -197
  65. package/commons/socket/realDataService.js +0 -59
  66. package/commons/socket/realDataServiceSocketIO.js +0 -33
  67. package/commons/socket/remoteStepService.js +0 -55
  68. package/commons/socket/remoteStepServiceSocketIO.js +0 -61
  69. package/commons/socket/socketService.js +0 -175
  70. package/commons/socket/testResultService.js +0 -62
  71. package/commons/socket/testResultServiceSocketIO.js +0 -64
  72. package/commons/testimAnalytics.js +0 -40
  73. package/commons/testimCloudflare.js +0 -83
  74. package/commons/testimCloudflare.test.js +0 -185
  75. package/commons/testimCustomToken.js +0 -124
  76. package/commons/testimDesiredCapabilitiesBuilder.js +0 -647
  77. package/commons/testimNgrok.js +0 -90
  78. package/commons/testimNgrok.test.js +0 -140
  79. package/commons/testimServicesApi.js +0 -631
  80. package/commons/testimTunnel.js +0 -73
  81. package/commons/testimTunnel.test.js +0 -172
  82. package/commons/xhr2.js +0 -897
  83. package/coverage/SummaryToObjectReport.js +0 -19
  84. package/coverage/jsCoverage.js +0 -252
  85. package/credentialsManager.js +0 -142
  86. package/errors.js +0 -161
  87. package/executionQueue.js +0 -37
  88. package/fixLocalBuild.js +0 -24
  89. package/inputFileUtils.js +0 -103
  90. package/lib/coralogix-winston.transport.js +0 -99
  91. package/player/SeleniumProtocolError.js +0 -100
  92. package/player/WebDriverHttpRequest.js +0 -177
  93. package/player/WebdriverioWebDriverApi.js +0 -671
  94. package/player/appiumTestPlayer.js +0 -90
  95. package/player/chromeLauncherTestPlayer.js +0 -67
  96. package/player/constants.js +0 -332
  97. package/player/extensionTestPlayer.js +0 -32
  98. package/player/findElementStrategy.js +0 -154
  99. package/player/scripts/isElementDisplayed.js +0 -252
  100. package/player/seleniumTestPlayer.js +0 -140
  101. package/player/services/frameLocator.js +0 -170
  102. package/player/services/mobileFrameLocatorMock.js +0 -32
  103. package/player/services/playbackTimeoutCalculator.js +0 -175
  104. package/player/services/portSelector.js +0 -19
  105. package/player/services/tabService.js +0 -551
  106. package/player/services/tabServiceMock.js +0 -167
  107. package/player/services/windowCreationListener.js +0 -8
  108. package/player/stepActions/RefreshStepAction.js +0 -16
  109. package/player/stepActions/apiStepAction.js +0 -89
  110. package/player/stepActions/baseCliJsStepAction.js +0 -51
  111. package/player/stepActions/baseJsStepAction.js +0 -277
  112. package/player/stepActions/cliConditionStepAction.js +0 -11
  113. package/player/stepActions/cliJsStepAction.js +0 -11
  114. package/player/stepActions/dropFileStepAction.js +0 -34
  115. package/player/stepActions/evaluateExpressionStepAction.js +0 -52
  116. package/player/stepActions/extensionOnlyStepAction.js +0 -12
  117. package/player/stepActions/extractTextStepAction.js +0 -19
  118. package/player/stepActions/hoverStepAction.js +0 -55
  119. package/player/stepActions/inputFileStepAction.js +0 -199
  120. package/player/stepActions/jsCodeStepAction.js +0 -11
  121. package/player/stepActions/jsConditionStepAction.js +0 -11
  122. package/player/stepActions/locateStepAction.js +0 -159
  123. package/player/stepActions/mouseStepAction.js +0 -370
  124. package/player/stepActions/navigationStepAction.js +0 -29
  125. package/player/stepActions/nodePackageStepAction.js +0 -47
  126. package/player/stepActions/pixelValidationStepAction.js +0 -39
  127. package/player/stepActions/scripts/dispatchEvents.js +0 -282
  128. package/player/stepActions/scripts/doClick.js +0 -221
  129. package/player/stepActions/scripts/doDragPath.js +0 -225
  130. package/player/stepActions/scripts/doubleClick.js +0 -119
  131. package/player/stepActions/scripts/dropEvent.js +0 -63
  132. package/player/stepActions/scripts/focusElement.js +0 -46
  133. package/player/stepActions/scripts/html5dragAction.js +0 -56
  134. package/player/stepActions/scripts/html5dragActionV2.js +0 -312
  135. package/player/stepActions/scripts/runCode.js +0 -147
  136. package/player/stepActions/scripts/scroll.js +0 -90
  137. package/player/stepActions/scripts/selectOption.js +0 -51
  138. package/player/stepActions/scripts/setText.js +0 -415
  139. package/player/stepActions/scripts/wheel.js +0 -61
  140. package/player/stepActions/scrollStepAction.js +0 -96
  141. package/player/stepActions/selectOptionStepAction.js +0 -49
  142. package/player/stepActions/sfdcRecordedStepAction.js +0 -24
  143. package/player/stepActions/sfdcStepAction.js +0 -28
  144. package/player/stepActions/sleepStepAction.js +0 -12
  145. package/player/stepActions/specialKeyStepAction.js +0 -52
  146. package/player/stepActions/stepAction.js +0 -73
  147. package/player/stepActions/stepActionRegistrar.js +0 -111
  148. package/player/stepActions/submitStepAction.js +0 -12
  149. package/player/stepActions/tdkHybridStepAction.js +0 -18
  150. package/player/stepActions/textStepAction.js +0 -110
  151. package/player/stepActions/textValidationStepAction.js +0 -64
  152. package/player/stepActions/wheelStepAction.js +0 -41
  153. package/player/utils/cookieUtils.js +0 -39
  154. package/player/utils/eyeSdkService.js +0 -250
  155. package/player/utils/imageCaptureUtils.js +0 -267
  156. package/player/utils/screenshotUtils.js +0 -68
  157. package/player/utils/stepActionUtils.js +0 -90
  158. package/player/utils/windowUtils.js +0 -195
  159. package/player/webDriverUtils.js +0 -40
  160. package/player/webDriverUtils.test.js +0 -116
  161. package/player/webdriver.js +0 -976
  162. package/polyfills/Array.prototype.at.js +0 -13
  163. package/polyfills/index.js +0 -13
  164. package/processHandler.js +0 -79
  165. package/processHandler.test.js +0 -55
  166. package/reports/chromeReporter.js +0 -17
  167. package/reports/consoleReporter.js +0 -190
  168. package/reports/debugReporter.js +0 -82
  169. package/reports/jsonReporter.js +0 -55
  170. package/reports/junitReporter.js +0 -183
  171. package/reports/reporter.js +0 -166
  172. package/reports/reporterUtils.js +0 -54
  173. package/reports/teamCityReporter.js +0 -73
  174. package/runOptions.d.ts +0 -305
  175. package/runOptions.js +0 -1288
  176. package/runOptionsAgentFlow.js +0 -87
  177. package/runOptionsUtils.js +0 -60
  178. package/runner.js +0 -355
  179. package/runners/ParallelWorkerManager.js +0 -284
  180. package/runners/TestPlanRunner.js +0 -419
  181. package/runners/buildCodeTests.js +0 -159
  182. package/runners/runnerUtils.js +0 -81
  183. package/services/analyticsService.js +0 -96
  184. package/services/branchService.js +0 -29
  185. package/services/gridService.js +0 -357
  186. package/services/gridService.test.js +0 -357
  187. package/services/labFeaturesService.js +0 -64
  188. package/services/lambdatestService.js +0 -227
  189. package/services/lambdatestService.test.js +0 -353
  190. package/services/localRCASaver.js +0 -124
  191. package/stepPlayers/cliJsStepPlayback.js +0 -40
  192. package/stepPlayers/hybridStepPlayback.js +0 -140
  193. package/stepPlayers/nodePackageStepPlayback.js +0 -28
  194. package/stepPlayers/playwrightHybridStepPlayback.js +0 -61
  195. package/stepPlayers/puppeteerHybridStepPlayback.js +0 -76
  196. package/stepPlayers/remoteStepPlayback.js +0 -80
  197. package/stepPlayers/seleniumHybridStepPlayback.js +0 -84
  198. package/stepPlayers/tdkHybridStepPlayback.js +0 -112
  199. package/testRunHandler.js +0 -603
  200. package/testRunStatus.js +0 -567
  201. package/testimNpmDriver.js +0 -52
  202. package/utils/argsUtils.js +0 -91
  203. package/utils/argsUtils.test.js +0 -32
  204. package/utils/fsUtils.js +0 -174
  205. package/utils/index.js +0 -197
  206. package/utils/promiseUtils.js +0 -85
  207. package/utils/stringUtils.js +0 -98
  208. package/utils/stringUtils.test.js +0 -22
  209. package/utils/timeUtils.js +0 -25
  210. package/utils/utils.test.js +0 -27
  211. package/workers/BaseWorker.js +0 -498
  212. package/workers/BaseWorker.test.js +0 -186
  213. package/workers/WorkerAppium.js +0 -180
  214. package/workers/WorkerExtension.js +0 -192
  215. package/workers/WorkerExtensionSingleBrowser.js +0 -77
  216. package/workers/WorkerSelenium.js +0 -253
  217. package/workers/workerUtils.js +0 -20
@@ -1,419 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash');
4
- const utils = require('../utils');
5
- const Logger = require('../commons/logger');
6
- const config = require('../commons/config');
7
- const reporter = require('../reports/reporter');
8
- const constants = require('../commons/constants');
9
- const TestRunStatus = require('../testRunStatus');
10
- const perf = require('../commons/performance-logger');
11
- const gridService = require('../services/gridService');
12
- const branchService = require('../services/branchService');
13
- const ParallelWorkerManager = require('./ParallelWorkerManager');
14
- const analyticsService = require('../services/analyticsService');
15
- const testimServicesApi = require('../commons/testimServicesApi');
16
- const testimCustomToken = require('../commons/testimCustomToken');
17
- const RealDataService = require('../commons/socket/realDataService');
18
- const { StopRunOnError, ArgError } = require('../errors');
19
- const { getSuite, calcTestResultStatus, validateConfig } = require('./runnerUtils');
20
-
21
- const guid = utils.guid;
22
- const TESTIM_RUN_STATUS = constants.testRunStatus;
23
- const logger = Logger.getLogger('test-plan-runner');
24
- const TDK_CHILD_RESULTS_TIMEOUT = 1000 * 60 * 5;
25
-
26
- /** @typedef {Awaited<ReturnType<typeof getSuite>>['tests'][number]} ExecutionList */
27
-
28
- class TestPlanRunner {
29
- /** @param {string=} customExtensionLocalLocation */
30
- constructor(customExtensionLocalLocation) {
31
- this.workerManager = new ParallelWorkerManager(customExtensionLocalLocation);
32
- this.startTime = Date.now();
33
- }
34
-
35
- /**
36
- * @private
37
- * @param {ExecutionList} beforeTests
38
- * @param {ExecutionList} tests
39
- * @param {ExecutionList} afterTests
40
- * @param {string} branchToUse
41
- * @param {import('../runOptions').RunnerOptions} tpOptions
42
- * @param {string} executionId
43
- * @param {string} executionName
44
- * @param {TestRunStatus} testStatus
45
- */
46
- async runTestAllPhases(beforeTests, tests, afterTests, branchToUse, tpOptions, executionId, executionName, testStatus) {
47
- /** @type {{ [testResultId: string]: any; }} */
48
- const executionResults = {};
49
- const authData = testimCustomToken.getTokenV3UserData();
50
-
51
- const runBeforeTests = async () => {
52
- const workerCount = tpOptions.beforeParallel || 1;
53
- const stopOnError = true;
54
- const beforeTestsResults = await this.workerManager.runTests(beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError);
55
- Object.assign(executionResults, beforeTestsResults);
56
- };
57
-
58
- const runTestPlanTests = async () => {
59
- const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
60
- const stopOnError = false;
61
- perf.log('right before this.workerManager.runTests');
62
- const testsResults = await this.workerManager.runTests(tests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError);
63
- perf.log('right after this.workerManager.runTests');
64
- Object.assign(executionResults, testsResults);
65
- };
66
-
67
- const runAfterTests = async () => {
68
- const workerCount = tpOptions.afterParallel || 1;
69
- const stopOnError = false;
70
- const afterTestsResults = await this.workerManager.runTests(afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError);
71
- Object.assign(executionResults, afterTestsResults);
72
- };
73
-
74
- const sessionType = utils.getSessionType(tpOptions);
75
- analyticsService.analyticsExecsStart({ authData, executionId, projectId: tpOptions.project, sessionType });
76
- perf.log('right before runBeforeTests');
77
- try {
78
- await runBeforeTests();
79
- perf.log('right before runTestPlanTests');
80
- await runTestPlanTests();
81
- perf.log('right after runTestPlanTests');
82
- await runAfterTests();
83
- return executionResults;
84
- } catch (err) {
85
- logger.error('error running test plan', { err });
86
- if (err instanceof StopRunOnError) {
87
- return testStatus.markAllQueuedTests(executionId, constants.runnerTestStatus.ABORTED, 'aborted', false);
88
- }
89
- throw err;
90
- } finally {
91
- await handlePixelValidationBatches();
92
- }
93
-
94
- async function handlePixelValidationBatches() {
95
- if (tpOptions.lightweightMode?.disablePixelValidation) {
96
- return;
97
- }
98
- // When sessionPlayer is available, use it - as it only attempts to close batches that exist.
99
- if (tpOptions.mode === constants.CLI_MODE.SELENIUM) {
100
- const { EyeSdkBuilder } = require('../commons/getSessionPlayerRequire').getSessionPlayer();
101
- await EyeSdkBuilder.closeBatch(executionId);
102
- return;
103
- }
104
- /** @type {Awaited<ReturnType<typeof testimServicesApi['getApplitoolsIntegrationData']>>} */
105
- let applitoolsIntegrationData;
106
- try {
107
- if (!tpOptions.company?.activePlan?.premiumFeatures?.applitools) {
108
- return;
109
- }
110
- applitoolsIntegrationData = await testimServicesApi.getApplitoolsIntegrationData(tpOptions.project);
111
- if (_.isEmpty(applitoolsIntegrationData) || !executionId) {
112
- return;
113
- }
114
- const { runKey: apiKey, url: serverUrl } = applitoolsIntegrationData;
115
- const tmpSDK = require('@applitools/eyes-sdk-core').makeSDK({ name: 'Testim.io', version: '4.0.0', spec: {} });
116
- await tmpSDK.closeBatches({ settings: { batchIds: [executionId], serverUrl, apiKey } });
117
- } catch (err) {
118
- // If a batch with this name did not exist, do not log an error.
119
- if (err.message && (err.message.startsWith('Request failed with status code 404') || err.message.startsWith('no batchIds were set'))) {
120
- return;
121
- }
122
- logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project, applitoolsIntegrationData, batchIds: [executionId] });
123
- }
124
- }
125
- }
126
-
127
- /**
128
- * @private
129
- * @param {string} projectId
130
- */
131
- async initRealDataService(projectId) {
132
- const realDataService = new RealDataService();
133
- await realDataService.init(projectId);
134
- return realDataService;
135
- }
136
-
137
- /**
138
- * @private
139
- * @param {RealDataService} realDataService
140
- * @param {string} projectId
141
- * @param {string} runId
142
- * @param {TestRunStatus} testStatus
143
- */
144
- async listenToTestCreatedInFile(realDataService, projectId, runId, testStatus) {
145
- const childTestResults = {};
146
- realDataService.joinToTestResultsByRunId(runId, projectId);
147
- let isPromisePending = true;
148
- /** @type {Promise<any[]>} */
149
- const promise = new Promise(_resolve => {
150
- const resolve = (val) => {
151
- isPromisePending = false;
152
- _resolve(val);
153
- };
154
- realDataService.listenToTestResultsByRunId(runId, testResult => {
155
- const resultId = testResult.id;
156
- if (!testStatus.getTestResult(resultId)) {
157
- const prevTestResult = childTestResults[resultId];
158
- const mergedTestResult = _.merge({}, prevTestResult, testResult, { resultId });
159
- childTestResults[resultId] = mergedTestResult;
160
- if (!prevTestResult || prevTestResult.status !== testResult.status) {
161
- const parentTestResult = testStatus.getTestResult(mergedTestResult.parentResultId) || { workerId: 1 };
162
- const workerId = parentTestResult.workerId;
163
- if ([TESTIM_RUN_STATUS.RUNNING].includes(testResult.status)) {
164
- reporter.onTestStarted(mergedTestResult, workerId);
165
- }
166
- if ([TESTIM_RUN_STATUS.COMPLETED].includes(testResult.status)) {
167
- mergedTestResult.duration = (mergedTestResult.endTime - mergedTestResult.startTime) || 0;
168
- reporter.onTestFinished(mergedTestResult, workerId);
169
- }
170
- }
171
- }
172
-
173
- const allChildTestResultCompleted = !(Object.values(childTestResults)
174
- .some(result => ['QUEUED', 'RUNNING'].includes(result.runnerStatus)));
175
-
176
- const allParentTestResultCompleted = !(Object.values(testStatus.getAllTestResults())
177
- .some(result => ['QUEUED', 'RUNNING'].includes(result.status)));
178
-
179
- if (allChildTestResultCompleted && allParentTestResultCompleted) {
180
- return resolve(Object.values(childTestResults));
181
- }
182
-
183
- if (allParentTestResultCompleted && !allChildTestResultCompleted) {
184
- // wait 10 sec to handle race condition when parent test result (file) finished before child test result
185
- return utils.delay(10000)
186
- .then(() => {
187
- if (isPromisePending) {
188
- // TODO(Benji) we are missing the child test results here.
189
- // we are resolving here with partial data - we should consider fetching it
190
- // from the server
191
- resolve(childTestResults);
192
- }
193
- });
194
- }
195
- return undefined;
196
- });
197
- });
198
-
199
- return await promise;
200
- }
201
-
202
- /**
203
- * @private
204
- * @param {string} projectId
205
- * @param {string} executionId
206
- * @param {TestRunStatus} testStatus
207
- */
208
- async initRealDataServiceAndListenToTestsCreatedInFile(projectId, executionId, testStatus) {
209
- const realDataService = await this.initRealDataService(projectId);
210
- return this.listenToTestCreatedInFile(realDataService, projectId, executionId, testStatus);
211
- }
212
-
213
- /**
214
- * @private
215
- * @param {ExecutionList} beforeTests
216
- * @param {ExecutionList} tests
217
- * @param {ExecutionList} afterTests
218
- * @param {import('../runOptions').RunnerOptions} tpOptions
219
- * @param {string} testPlanName
220
- * @param {string | null} testPlanId
221
- * @param {string} branch
222
- * @param {boolean=} isAnonymous
223
- */
224
- async runTestPlan(beforeTests, tests, afterTests, tpOptions, testPlanName, testPlanId, branch, isAnonymous) {
225
- const executionId = guid();
226
- const projectId = tpOptions.project;
227
- Logger.setExecutionId(executionId);
228
- beforeTests.forEach(test => { test.isBeforeTestPlan = true; });
229
- afterTests.forEach(test => { test.isAfterTestPlan = true; });
230
- const testStatus = new TestRunStatus([].concat(beforeTests, tests, afterTests), tpOptions, testPlanId, branch);
231
-
232
- const configs = _.chain([].concat(beforeTests, tests, afterTests))
233
- .map(test => test.overrideTestConfig?.name || '')
234
- .uniq()
235
- .compact()
236
- .value();
237
- /** @type {string | null} */
238
- const configName = configs?.length === 1 ? configs[0] : null;
239
-
240
- const isCodeMode = tpOptions.files.length > 0;
241
- const testNames = tpOptions.lightweightMode?.onlyTestIdsNoSuite ? [] : [].concat(beforeTests, tests, afterTests).map(test => test.name);
242
-
243
- const testListInfoPromise = tpOptions.lightweightMode?.onlyTestIdsNoSuite ?
244
- { beforeTests, tests, afterTests } :
245
- testStatus.executionStart(executionId, projectId, this.startTime, testPlanName, testNames);
246
- let childTestResults;
247
- if (isCodeMode) {
248
- childTestResults = this.initRealDataServiceAndListenToTestsCreatedInFile(projectId, executionId, testStatus);
249
- }
250
- perf.log('before testListInfoPromise');
251
- const testListInfo = await testListInfoPromise;
252
- if (!tpOptions.lightweightMode?.onlyTestIdsNoSuite) {
253
- reporter.onTestPlanStarted(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, testPlanName, executionId, isAnonymous, configName, isCodeMode);
254
- }
255
-
256
- perf.log('before runTestAllPhases');
257
- const results = await this.runTestAllPhases(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, branch, tpOptions, executionId, testPlanName || 'All Tests', testStatus);
258
- const childResults = await utils.promiseTimeout(childTestResults, TDK_CHILD_RESULTS_TIMEOUT)
259
- .catch(async () => {
260
- logger.warn('timed out waiting for child results on websocket. using REST fallback', { projectId, executionId });
261
- const testResults = await testimServicesApi.getRealData(projectId, 'testResult', `runId=${executionId}&sort=runOrder`);
262
- return _.chain((testResults?.data?.docs) || [])
263
- .groupBy('parentResultId')
264
- .omit('undefined')
265
- .values()
266
- .flatten()
267
- .value();
268
- });
269
- perf.log('before executionEnd');
270
- await testStatus.executionEnd(executionId);
271
- perf.log('after executionEnd');
272
- return { results, executionId, testPlanName, configName, childTestResults: childResults };
273
- }
274
-
275
- /**
276
- * @private
277
- * @param {import('../runOptions').RunnerOptions} options
278
- * @param {string} branchToUse
279
- */
280
- async runTestPlans(options, branchToUse) {
281
- logger.info('start to run test plan', {
282
- options: Object.assign({}, options, { token: undefined, userParamsData: undefined }),
283
- branchToUse,
284
- });
285
-
286
- function flattenTestListData(testPlansData) {
287
- return _.flattenDeep(Object.values(testPlansData)).reduce((all, testRun) => all.concat(testRun.beforeTests, testRun.tests, testRun.afterTests), []);
288
- }
289
-
290
- const testPlansResults = {};
291
- const testPlansTests = {};
292
- const projectId = options.project;
293
-
294
- const data = await testimServicesApi.getTestPlanTestList(projectId, options.testPlan, options.testPlanIds, branchToUse, options.intersections);
295
- const testPlans = data.testPlans;
296
- const testPlansData = data.testPlansData;
297
- if (!testPlans || testPlans.length === 0) {
298
- throw new ArgError(`no test plan to run ${options.testPlan}`);
299
- }
300
- if (!testPlansData || Object.keys(testPlansData).length === 0) {
301
- if (options.passZeroTests) {
302
- return [];
303
- }
304
- throw new ArgError(`no test to run in test plan ${options.testPlan}`);
305
- }
306
- await validateConfig(options, flattenTestListData(testPlansData));
307
- return await utils.promiseMap(testPlans, async testPlan => {
308
- const id = testPlan.testPlanId;
309
- testPlansResults[id] = {};
310
-
311
- const tpOptions = Object.assign({}, options);
312
- tpOptions.baseUrl = options.baseUrl || testPlan.startUrl;
313
- tpOptions.host = options.host;
314
- tpOptions.port = options.port;
315
- tpOptions.gridId = options.gridId || testPlan.gridId;
316
-
317
- //if user pass --grid with test plan we want to use grid option instead of host and port
318
- if (options.grid) {
319
- delete tpOptions.gridId;
320
- }
321
-
322
-
323
- tpOptions.gridData = await gridService.getTestPlanGridData(options, testPlan);
324
-
325
- const testPlanName = tpOptions.overrideExecutionName || testPlan.name;
326
- return await utils.promiseMap(testPlansData[id], async testPlanTests => {
327
- const res = await this.runTestPlan(testPlanTests.beforeTests, testPlanTests.tests, testPlanTests.afterTests, tpOptions, testPlanName, id, branchToUse);
328
- const isCodeMode = options.files.length > 0;
329
- reporter.onTestPlanFinished(res.results, testPlan.name, this.startTime, res.executionId, false, isCodeMode, res.childTestResults);
330
- testPlansResults[id][res.executionId] = res.results;
331
-
332
- const executions = Object.keys(testPlansResults[id]).map(exeId => ({
333
- executionId: exeId,
334
- status: calcTestResultStatus(testPlansResults[id][exeId]),
335
- }));
336
- const tests = Object.keys(testPlansResults[id]).map(exeId => testPlansResults[id][exeId]).reduce((testResult, test) => Object.assign(testResult, test), {});
337
- const success = calcTestResultStatus(tests);
338
- Object.assign(testPlansTests, tests);
339
- const executionId = success ? executions[0].executionId : executions.find(exec => !exec.success).executionId;
340
- await testimServicesApi.saveTestPlanResult(projectId, id, { success, executions, executionId });
341
- return res;
342
- });
343
- });
344
- }
345
-
346
- /**
347
- * @private
348
- * @param {import('../runOptions').RunnerOptions} options
349
- * @param {string} branchToUse
350
- */
351
- async runAnonymousTestPlan(options, branchToUse) {
352
- logger.info('start to run anonymous', {
353
- options: Object.assign({}, options, { token: undefined }),
354
- branchToUse,
355
- });
356
-
357
- perf.log('before getSuite');
358
- const suiteResult = await getSuite(options, branchToUse);
359
- perf.log('after getSuite');
360
-
361
- if (!suiteResult?.tests[0]?.length) {
362
- if (options.rerunFailedByRunId) {
363
- throw new ArgError('No failed tests found in the provided run');
364
- }
365
- if (options.passZeroTests) {
366
- return [];
367
- }
368
- throw new ArgError('No tests to run');
369
- }
370
- branchToUse = suiteResult.branch || branchToUse;
371
- if (options.rerunFailedByRunId && !suiteResult.runName) {
372
- if (!suiteResult.runExists) {
373
- throw new ArgError('Invalid run ID - no such run.');
374
- }
375
- const isAnonymouslyNamedRun = suiteResult.runName === '';
376
- if (isAnonymouslyNamedRun) {
377
- suiteResult.runName = `rerun-${options.rerunFailedByRunId}`;
378
- }
379
- }
380
- const testPlanName = options.overrideExecutionName || suiteResult.runName || [].concat(options.label, options.name, options.suites).join(' ');
381
- const isAnonymous = true;
382
- perf.log('Right before validateConfig + runAnonymousTestPlan tests map');
383
- return await utils.promiseMap(suiteResult.tests, async suiteTests => { // array of results per execution
384
- //override result id for remote run mode and run only the first test data
385
- if (options.resultId) {
386
- const firstTest = suiteTests[0];
387
- firstTest.resultId = options.resultId;
388
- suiteTests = [firstTest];
389
- }
390
- await validateConfig(options, suiteTests);
391
- perf.log('right before runTestPlan');
392
- const res = await this.runTestPlan([], suiteTests, [], options, testPlanName, null, branchToUse, isAnonymous);
393
- perf.log('right after runTestPlan');
394
- const isCodeMode = options.files.length > 0;
395
- await reporter.onTestPlanFinished(res.results, testPlanName, this.startTime, res.executionId, isAnonymous, isCodeMode, res.childTestResults);
396
- return res;
397
- });
398
- }
399
-
400
- /**
401
- * @param {import('../runOptions').RunnerOptions} options
402
- */
403
- async run(options) {
404
- const branchToUse = branchService.getCurrentBranch();
405
- let results = [];
406
- if (utils.hasTestPlanFlag(options)) {
407
- results = await this.runTestPlans(options, branchToUse);
408
- } else {
409
- results = await this.runAnonymousTestPlan(options, branchToUse);
410
- }
411
- const flattenResults = _.flattenDeep(results);
412
- perf.log('right before onAllTestPlansFinished');
413
- await reporter.onAllTestPlansFinished(flattenResults);
414
- perf.log('right after onAllTestPlansFinished');
415
- return flattenResults.map(res => res.results).reduce((total, cur) => Object.assign(total, cur), {});
416
- }
417
- }
418
-
419
- module.exports = TestPlanRunner;
@@ -1,159 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash');
4
- const path = require('path');
5
- const MemoryFS = require('memory-fs');
6
- const utils = require('../utils');
7
- const lazyRequire = require('../commons/lazyRequire');
8
- const { AbortError } = require('../commons/AbortError');
9
-
10
- // compiler instance we can reuse between calls
11
- const state = {
12
- compiler: null,
13
- webpackConfig: null,
14
- };
15
-
16
- exports.buildCodeTests = async function buildCodeTestsGuarded(
17
- files,
18
- webpackConfig,
19
- runnerOptionsToMaybeCopyToTestEnvironment,
20
- fileSystem,
21
- optionalAbortSignal
22
- ) {
23
- try {
24
- return await buildCodeTests(files, webpackConfig, runnerOptionsToMaybeCopyToTestEnvironment, fileSystem, optionalAbortSignal);
25
- } catch (e) {
26
- if (e && e.code === 'ENOENT') {
27
- // this is a webpack config error - it means webpack didn't pick up on a file change and didn't generate the correct bundle
28
- // according to the guid hash
29
- state.compiler = null;
30
- state.webpackConfig = null;
31
- fileSystem.data = {}; // reset the memory filesystem in case we left a mess there in the previous invocation
32
- return await buildCodeTests(files, webpackConfig, runnerOptionsToMaybeCopyToTestEnvironment, fileSystem, optionalAbortSignal);
33
- }
34
- throw e;
35
- }
36
- };
37
-
38
- async function buildCodeTests(files, webpackConfig = { mode: 'development' }, runnerOptionsToMaybeCopyToTestEnvironment = undefined, fileSystem = undefined, optionalAbortSignal = undefined) {
39
- const webpack = await lazyRequire('webpack');
40
-
41
- const suite = {};
42
- const webpackConfigBeforeOurChanges = _.cloneDeep(webpackConfig);
43
-
44
- webpackConfig.externals = { // define testim as an external
45
- testim: '__testim',
46
- // 'chai': '__chai'
47
- };
48
- webpackConfig.devtool = webpackConfig.devtool || 'inline-source-map';
49
-
50
- webpackConfig.plugins = webpackConfig.plugins || [];
51
-
52
- webpackConfig.plugins.push(new webpack.DefinePlugin(getEnvironmentVariables(runnerOptionsToMaybeCopyToTestEnvironment)), new webpack.DefinePlugin({
53
- 'process.argv': JSON.stringify(process.argv),
54
- }));
55
- files = files.map(f => path.resolve(f));
56
-
57
- const fileHashes = files.map(() => utils.guid(30));
58
-
59
- webpackConfig.optimization = { minimize: false };
60
-
61
- const majorNodeVersion = Number(process.versions.node.split('.')[0]);
62
- if (majorNodeVersion >= 17) {
63
- // TODO ugly hack to be removed once using Webpack 5 - https://stackoverflow.com/a/73465262 + https://github.com/webpack/webpack/issues/14532
64
- const crypto = require('crypto');
65
- const originalCryptoCreateHash = crypto.createHash;
66
- crypto.createHash = (algorithm, options) => originalCryptoCreateHash(algorithm === 'md4' ? 'sha256' : algorithm, options);
67
- }
68
-
69
- webpackConfig.entry = Object.fromEntries(_.zip(files, fileHashes).map(([filename, hash]) => [hash, filename]));
70
- webpackConfig.output = Object.assign({
71
- devtoolModuleFilenameTemplate: (info) => `file:///${info.absoluteResourcePath}`,
72
- filename: '[name].bundle.js',
73
- }, webpackConfig.output);
74
-
75
-
76
- let compiler;
77
- // if we are passed a filesystem, assume reuse between calls and turn on watch mode
78
- if (fileSystem) {
79
- // were we passed a filesystem before to compile the same thing?
80
- if (_.isEqual(state.webpackConfig, webpackConfigBeforeOurChanges) && state.compiler) {
81
- // we already have a compiler up and running
82
- compiler = state.compiler;
83
- } else {
84
- state.webpackConfig = webpackConfigBeforeOurChanges;
85
- state.compiler = webpack(webpackConfig);
86
- compiler = state.compiler;
87
- }
88
- } else {
89
- compiler = webpack(webpackConfig); // no caching
90
- }
91
-
92
- const mfs = fileSystem || new MemoryFS();
93
- compiler.outputFileSystem = mfs; // no need to write compiled tests to disk
94
-
95
- // This can only reject
96
- const abortSignalPromise = utils.promiseFromCallback(cb => {
97
- if (optionalAbortSignal) {
98
- optionalAbortSignal.addEventListener('abort', () => {
99
- cb(new AbortError());
100
- });
101
- }
102
- });
103
-
104
- // run compiler:
105
- try {
106
- const stats = await Promise.race([utils.promiseFromCallback(cb => compiler.run(cb)), abortSignalPromise]);
107
- if (stats.hasErrors()) {
108
- throw new Error(stats.toJson().errors);
109
- }
110
- } catch (e) {
111
- const { ArgError } = require('../errors');
112
-
113
- const cantFindFile = e.message.match(/Entry module not found: Error: Can't resolve '(.*)'/);
114
- if (cantFindFile && cantFindFile.length === 2) {
115
- if (webpackConfig.output && webpackConfig.output.library === 'tdk') {
116
- throw new ArgError(`Could not open dev-kit functions file in ${cantFindFile[1]}`);
117
- }
118
- throw new ArgError(`Can't find test files in: '${cantFindFile[1]}'`);
119
- }
120
-
121
- throw new ArgError(`Compilation Webpack Error in tests: ${e.message}`);
122
- }
123
-
124
- /** @type {{ code: string; name: string; }[]} */
125
- const fileResults = files.map((file, i) => ({ code: mfs.readFileSync(path.resolve('./dist', `${fileHashes[i]}.bundle.js`)), name: file })); // read all files
126
-
127
- suite.tests = [fileResults.map(({ code, name }) => ({
128
- code: code.toString(),
129
- baseUrl: '', // not supported at the moment
130
- name: path.resolve(name),
131
- testConfig: {},
132
- testConfigId: null,
133
- testId: utils.guid(),
134
- resultId: utils.guid(),
135
- isTestsContainer: true,
136
- }))];
137
- suite.runName = `Testim Dev Kit Run ${new Date().toLocaleString()}`;
138
- return suite;
139
- }
140
-
141
- // copied mostly from facebook/create-react-app/blob/8b7b819b4b9e6ba457e011e92e33266690e26957/packages/react-scripts/config/env.js
142
- function getEnvironmentVariables(runnerOptionsToMaybeCopyToTestEnvironment) {
143
- const fromEnvironment = _.fromPairs(
144
- Object.keys(process.env)
145
- .filter(key => /^TDK_/i.test(key) || key === 'BASE_URL')
146
- .map(key => [key, process.env[key]])
147
- );
148
-
149
- const fromConfig = {
150
- BASE_URL: runnerOptionsToMaybeCopyToTestEnvironment.baseUrl,
151
- };
152
-
153
- return {
154
- 'process.env': stringifyValues({ ...fromConfig, ...fromEnvironment }),
155
- };
156
- }
157
- function stringifyValues(object) {
158
- return _.fromPairs(Object.entries(object).map(([key, value]) => [key, JSON.stringify(value)]));
159
- }
@@ -1,81 +0,0 @@
1
- 'use strict';
2
-
3
- const _ = require('lodash');
4
- const path = require('path');
5
- const utils = require('../utils');
6
- const analytics = require('../commons/testimAnalytics');
7
- const { ArgError } = require('../errors');
8
-
9
-
10
- /**
11
- * @param {import('../runOptions').RunnerOptions} options
12
- * @param {string} branchToUse
13
- */
14
- async function getSuite(options, branchToUse) {
15
- if (options.lightweightMode?.onlyTestIdsNoSuite && options.testId) {
16
- return { tests: [options.testId.map(testId => ({ testId, testConfig: {}, resultId: utils.guid() }))] };
17
- }
18
- // local code test
19
- if (options.files.length > 0) {
20
- const { buildCodeTests } = require('./buildCodeTests');
21
- let webpackConfig = {};
22
- if (options.webpackConfig) {
23
- const webpackConfigPath = path.join(process.cwd(), options.webpackConfig);
24
- webpackConfig = require(webpackConfigPath); // eslint-disable-line import/no-dynamic-require
25
- }
26
-
27
- return buildCodeTests(options.files, webpackConfig, { baseUrl: options.baseUrl });
28
- }
29
- // regular test
30
- const servicesApi = require('../commons/testimServicesApi');
31
- return await servicesApi.getSuiteTestList({
32
- projectId: options.project,
33
- labels: options.label,
34
- testIds: options.testId,
35
- testNames: options.name,
36
- testConfigNames: options.testConfigNames,
37
- suiteNames: options.suites,
38
- suiteIds: options.suiteIds,
39
- branch: branchToUse,
40
- rerunFailedByRunId: options.rerunFailedByRunId,
41
- testConfigIds: options.testConfigIds,
42
- intersections: options.intersections,
43
- });
44
- }
45
-
46
-
47
- function calcTestResultStatus(tests) {
48
- const total = Object.keys(tests).length;
49
- const passed = Object.keys(tests).reduce((count, resultId) => count + (tests[resultId].success === true ? 1 : 0), 0);
50
- return total === passed;
51
- }
52
-
53
-
54
- /**
55
- * @param {import('../runOptions').RunnerOptions} options
56
- * @param {import('./TestPlanRunner').ExecutionList} testList
57
- */
58
- async function validateConfig(options, testList) {
59
- const supportedBrowsers = options.mode === 'extension' ? [
60
- 'edge-chromium', 'chrome',
61
- ] : [
62
- 'firefox', 'chrome', 'edge-chromium', 'safari', 'safari technology preview', 'browser', 'android', 'ios', 'iphone', 'ipad',
63
- ];
64
- const diff = _.difference(utils.getUniqBrowsers(options, testList), supportedBrowsers);
65
-
66
- if (diff.length > 0) {
67
- analytics.trackWithCIUser('invalid-config-run', {
68
- browser: diff.join(', '),
69
- mode: 'runner',
70
- });
71
- throw new ArgError(`browser type <${diff}> is not supported in ${options.mode} mode.`);
72
- }
73
-
74
- return testList;
75
- }
76
-
77
- module.exports = {
78
- getSuite,
79
- calcTestResultStatus,
80
- validateConfig,
81
- };