@testim/testim-cli 3.253.0 → 3.255.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 (103) hide show
  1. package/OverrideTestDataBuilder.js +1 -1
  2. package/agent/routers/cliJsCode/index.js +4 -4
  3. package/agent/routers/cliJsCode/router.js +46 -42
  4. package/agent/routers/cliJsCode/service.js +18 -13
  5. package/agent/routers/codim/router.js +14 -17
  6. package/agent/routers/codim/router.test.js +19 -21
  7. package/agent/routers/codim/service.js +16 -16
  8. package/agent/routers/general/index.js +4 -8
  9. package/agent/routers/hybrid/registerRoutes.js +18 -18
  10. package/agent/routers/index.js +7 -7
  11. package/agent/routers/playground/router.js +11 -10
  12. package/agent/routers/playground/service.js +22 -23
  13. package/agent/routers/standalone-browser/registerRoutes.js +10 -10
  14. package/cdpTestRunner.js +4 -3
  15. package/chromiumInstaller.js +4 -5
  16. package/cli/onExit.js +2 -2
  17. package/cli.js +11 -10
  18. package/cliAgentMode.js +8 -8
  19. package/codim/codim-cli.js +20 -17
  20. package/codim/hybrid-utils.js +1 -1
  21. package/codim/measure-perf.js +9 -6
  22. package/codim/template.js/tests/examples/01-simple-text-validation.test.js +6 -6
  23. package/codim/template.js/tests/examples/02-using-locators.test.js +13 -15
  24. package/codim/template.js/tests/examples/03-using-hooks.test.js +17 -19
  25. package/codim/template.js/tests/examples/04-skip-and-only.test.js +16 -17
  26. package/codim/template.js/tests/examples/05-multiple-windows.test.js +16 -17
  27. package/codim/template.js/webpack.config.js +1 -1
  28. package/codim/template.ts/webpack.config.js +3 -3
  29. package/commons/AbortError.js +4 -4
  30. package/commons/detectDebugger.js +4 -2
  31. package/commons/featureFlags.js +8 -0
  32. package/commons/httpRequest.js +5 -1
  33. package/commons/httpRequestCounters.js +21 -10
  34. package/commons/lazyRequire.js +14 -12
  35. package/commons/logger.js +4 -4
  36. package/commons/performance-logger.js +14 -8
  37. package/commons/preloadTests.js +2 -2
  38. package/commons/prepareRunner.js +4 -2
  39. package/commons/prepareRunnerAndTestimStartUtils.js +40 -42
  40. package/commons/runnerFileCache.js +1 -1
  41. package/commons/socket/baseSocketServiceSocketIO.js +32 -34
  42. package/commons/socket/realDataService.js +6 -5
  43. package/commons/socket/realDataServiceSocketIO.js +4 -4
  44. package/commons/socket/remoteStepService.js +4 -3
  45. package/commons/socket/remoteStepServiceSocketIO.js +11 -12
  46. package/commons/socket/socketService.js +50 -52
  47. package/commons/socket/testResultServiceSocketIO.js +11 -11
  48. package/commons/testimDesiredCapabilitiesBuilder.js +3 -2
  49. package/commons/testimNgrok.js +2 -2
  50. package/commons/testimNgrok.test.js +1 -1
  51. package/commons/testimServicesApi.js +27 -20
  52. package/commons/testimTunnel.test.js +2 -1
  53. package/commons/xhr2.js +97 -100
  54. package/coverage/SummaryToObjectReport.js +0 -1
  55. package/coverage/jsCoverage.js +12 -10
  56. package/errors.js +5 -0
  57. package/fixLocalBuild.js +2 -0
  58. package/inputFileUtils.js +11 -9
  59. package/npm-shrinkwrap.json +2286 -1284
  60. package/package.json +9 -8
  61. package/player/appiumTestPlayer.js +1 -1
  62. package/player/chromeLauncherTestPlayer.js +0 -1
  63. package/player/services/tabService.js +15 -1
  64. package/player/services/tabServiceMock.js +166 -0
  65. package/player/stepActions/locateStepAction.js +2 -0
  66. package/player/stepActions/navigationStepAction.js +11 -10
  67. package/player/stepActions/sleepStepAction.js +4 -5
  68. package/player/stepActions/textStepAction.js +4 -11
  69. package/player/utils/imageCaptureUtils.js +81 -120
  70. package/player/utils/windowUtils.js +4 -3
  71. package/player/webdriver.js +26 -23
  72. package/processHandler.js +3 -3
  73. package/processHandler.test.js +1 -1
  74. package/reports/consoleReporter.js +3 -2
  75. package/reports/junitReporter.js +7 -9
  76. package/reports/reporter.js +34 -39
  77. package/runOptions.d.ts +260 -0
  78. package/runOptions.js +59 -44
  79. package/runner.js +14 -0
  80. package/runners/ParallelWorkerManager.js +9 -10
  81. package/runners/TestPlanRunner.js +142 -78
  82. package/runners/buildCodeTests.js +38 -37
  83. package/runners/runnerUtils.js +3 -3
  84. package/services/gridService.js +36 -40
  85. package/services/lambdatestService.js +3 -5
  86. package/stepPlayers/cliJsStepPlayback.js +22 -17
  87. package/testRunHandler.js +8 -0
  88. package/testRunStatus.js +9 -6
  89. package/utils/argsUtils.js +86 -0
  90. package/utils/argsUtils.test.js +32 -0
  91. package/utils/fsUtils.js +154 -0
  92. package/{utils.js → utils/index.js} +19 -262
  93. package/utils/promiseUtils.js +89 -0
  94. package/utils/stringUtils.js +98 -0
  95. package/utils/stringUtils.test.js +22 -0
  96. package/utils/timeUtils.js +25 -0
  97. package/utils/utils.test.js +27 -0
  98. package/workers/BaseWorker.js +16 -14
  99. package/workers/WorkerAppium.js +1 -1
  100. package/workers/WorkerExtension.js +6 -7
  101. package/workers/WorkerExtensionSingleBrowser.js +4 -4
  102. package/workers/WorkerSelenium.js +5 -2
  103. package/utils.test.js +0 -68
@@ -4,7 +4,7 @@ const _ = require('lodash');
4
4
  const Promise = require('bluebird');
5
5
 
6
6
  const { GridError, ArgError } = require('../errors');
7
- const { hasTestPlanFlag } = require('../utils');
7
+ const { hasTestPlanFlag, promiseMap } = require('../utils');
8
8
  const { gridMessages, gridTypes } = require('../commons/constants');
9
9
  const logger = require('../commons/logger').getLogger('grid-service');
10
10
  const servicesApi = require('../commons/testimServicesApi');
@@ -37,22 +37,22 @@ function extractHost(hostUrl) {
37
37
 
38
38
  function getSerializableObject(grid) {
39
39
  const host = grid && extractHost(grid.host);
40
- const port = grid && grid.port;
41
- const path = grid && grid.path;
40
+ const port = grid?.port;
41
+ const path = grid?.path;
42
42
  const protocol = grid && extractProtocol(grid);
43
- const accessToken = grid && grid.token;
44
- const slotId = grid && grid.slotId;
45
- const tunnel = grid && grid.hybrid && grid.hybrid.tunnel;
46
- const user = grid && grid.external && grid.external.user;
47
- const key = grid && grid.external && grid.external.key;
48
- const type = grid && grid.type;
43
+ const accessToken = grid?.token;
44
+ const slotId = grid?.slotId;
45
+ const tunnel = grid?.hybrid?.tunnel;
46
+ const user = grid?.external?.user;
47
+ const key = grid?.external?.key;
48
+ const type = grid?.type;
49
49
  const tunnelUser = type === gridTypes.HYBRID ?
50
50
  (tunnel && grid.hybrid.external && grid.hybrid.external[grid.hybrid.tunnel] && grid.hybrid.external[grid.hybrid.tunnel].user) : user;
51
51
  const tunnelKey = type === gridTypes.HYBRID ?
52
52
  (tunnel && grid.hybrid.external && grid.hybrid.external[grid.hybrid.tunnel] && grid.hybrid.external[grid.hybrid.tunnel].key) : key;
53
- const name = grid && grid.name;
53
+ const name = grid?.name;
54
54
  const gridId = grid && (grid._id || grid.gridId);
55
- const provider = grid && grid.provider;
55
+ const provider = grid?.provider;
56
56
 
57
57
  return {
58
58
  host, port, path, protocol, accessToken, slotId, gridId, tunnel, user, key, type, name, provider, tunnelUser, tunnelKey,
@@ -97,14 +97,16 @@ function addItemToGridCache(workerId, companyId, gridId, slotId, browser) {
97
97
  gridCache[workerId] = { gridId, companyId, slotId, browser };
98
98
  }
99
99
 
100
- function getHostAndPortById(workerId, companyId, projectId, gridId, browser, executionId, options) {
101
- return handleGetGridResponse(projectId, companyId, workerId, browser, () => servicesApi.getGridById(companyId, projectId, gridId, browser, executionId));
100
+ function getHostAndPortById(workerId, companyId, projectId, gridId, browser, executionId) {
101
+ return handleGetGridResponse(projectId, companyId, workerId, browser, () =>
102
+ servicesApi.getGridById(companyId, projectId, gridId, browser, executionId),
103
+ );
102
104
  }
103
105
 
104
106
  function getHostAndPortByName(workerId, companyId, projectId, gridName, browser, executionId, options) {
105
107
  const get = () => {
106
- const grid = options.allGrids && options.allGrids.find(grid => (grid.name || '').toLowerCase() === gridName.toLowerCase());
107
- if (grid && grid._id) {
108
+ const grid = options.allGrids?.find(g => (g.name || '').toLowerCase() === gridName.toLowerCase());
109
+ if (grid?._id) {
108
110
  return servicesApi.getGridById(companyId, projectId, grid._id, browser, executionId);
109
111
  }
110
112
  return servicesApi.getGridByName(companyId, projectId, gridName, browser, executionId);
@@ -116,26 +118,22 @@ function getAllGrids(companyId) {
116
118
  return servicesApi.getAllGrids(companyId);
117
119
  }
118
120
 
119
- function getGridDataByGridId(companyId, gridId, allGrids) {
120
- return Promise.resolve(allGrids || getAllGrids(companyId))
121
- .then(grids => {
122
- const grid = grids.find(grid => grid._id === gridId);
123
- if (!grid) {
124
- throw new ArgError(`Failed to find grid id: ${gridId}`);
125
- }
126
- return getSerializableObject(grid);
127
- });
121
+ async function getGridDataByGridId(companyId, gridId, allGrids) {
122
+ const grids = await Promise.resolve(allGrids || getAllGrids(companyId));
123
+ const grid = grids.find(g => g._id === gridId);
124
+ if (!grid) {
125
+ throw new ArgError(`Failed to find grid id: ${gridId}`);
126
+ }
127
+ return getSerializableObject(grid);
128
128
  }
129
129
 
130
- function getGridDataByGridName(companyId, gridName, allGrids) {
131
- return Promise.resolve(allGrids || getAllGrids(companyId))
132
- .then(grids => {
133
- const grid = grids.find(grid => (grid.name || '').toLowerCase() === gridName.toLowerCase());
134
- if (!grid) {
135
- throw new ArgError(`Failed to find grid name: ${gridName}`);
136
- }
137
- return getSerializableObject(grid);
138
- });
130
+ async function getGridDataByGridName(companyId, gridName, allGrids) {
131
+ const grids = await Promise.resolve(allGrids || getAllGrids(companyId));
132
+ const grid = grids.find(g => (g.name || '').toLowerCase() === gridName.toLowerCase());
133
+ if (!grid) {
134
+ throw new ArgError(`Failed to find grid name: ${gridName}`);
135
+ }
136
+ return getSerializableObject(grid);
139
137
  }
140
138
 
141
139
  function releaseGridSlot(workerId, projectId) {
@@ -184,7 +182,7 @@ function releaseAllSlots(projectId) {
184
182
  }
185
183
 
186
184
  logger.warn('not all slots released before end runner flow', { projectId });
187
- return Promise.map(workerIds, workerId => releaseGridSlot(workerId, projectId))
185
+ return promiseMap(workerIds, workerId => releaseGridSlot(workerId, projectId))
188
186
  .catch(err => logger.error('failed to release all slots', { err, projectId }));
189
187
  }
190
188
 
@@ -266,20 +264,18 @@ async function getGridData(options) {
266
264
  throw new GridError('Missing host or grid configuration');
267
265
  }
268
266
 
269
- const getGridSlot = Promise.method(_getGridSlot);
270
-
271
- async function _getGridSlot(browser, executionId, testResultId, onGridSlot, options, workerId) {
272
- const getGridDataFromServer = () => {
267
+ async function getGridSlot(browser, executionId, testResultId, onGridSlot, options, workerId) {
268
+ const getGridDataFromServer = async () => {
273
269
  const { host, project, grid, gridId, useLocalChromeDriver, useChromeLauncher, company = {} } = options;
274
270
  const companyId = company.companyId;
275
271
  if (useLocalChromeDriver || useChromeLauncher) {
276
272
  return { mode: 'local' };
277
273
  }
278
274
  if (host) {
279
- return Promise.resolve(getOptionGrid(options));
275
+ return getOptionGrid(options);
280
276
  }
281
277
  if (gridId) {
282
- return getHostAndPortById(workerId, companyId, project, gridId, browser, executionId, options);
278
+ return getHostAndPortById(workerId, companyId, project, gridId, browser, executionId);
283
279
  }
284
280
  if (grid) {
285
281
  return getHostAndPortByName(workerId, companyId, project, grid, browser, executionId, options);
@@ -4,8 +4,6 @@ const pRetry = require('p-retry');
4
4
  const fse = require('fs-extra');
5
5
  const portfinder = require('portfinder');
6
6
  const ms = require('ms');
7
-
8
- const { guid, isURL } = require('../utils');
9
7
  const utils = require('../utils');
10
8
  const { gridTypes, CLI_MODE } = require('../commons/constants');
11
9
  const httpRequest = require('../commons/httpRequest');
@@ -98,7 +96,7 @@ class LambdatestService {
98
96
  const infoAPIPort = await portfinder.getPortPromise();
99
97
  const { gridData = {}, gridUsername, gridPassword } = runnerOptions;
100
98
  const proxyUri = global.proxyUri;
101
- LambdatestService.tunnelName = guid();
99
+ LambdatestService.tunnelName = utils.guid();
102
100
 
103
101
  let tunnelArgs = [
104
102
  '--tunnelName', LambdatestService.tunnelName,
@@ -198,11 +196,11 @@ class LambdatestService {
198
196
  if (!extensionPath && extUrls[browser]) {
199
197
  loadExtension = [...loadExtension, extUrls[browser]];
200
198
  }
201
- if (extensionPath && isURL(extensionPath)) {
199
+ if (extensionPath && utils.isURL(extensionPath)) {
202
200
  loadExtension = [...loadExtension, extensionPath];
203
201
  }
204
202
  }
205
- if (installCustomExtension && isURL(installCustomExtension)) {
203
+ if (installCustomExtension && utils.isURL(installCustomExtension)) {
206
204
  loadExtension = [...loadExtension, installCustomExtension];
207
205
  }
208
206
 
@@ -1,16 +1,15 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  const service = require('../agent/routers/cliJsCode/service');
4
- const Promise = require('bluebird');
4
+ const { TimeoutError } = require('bluebird');
5
5
  const featureFlags = require('../commons/featureFlags');
6
- const logger = require('../commons/logger').getLogger('cli-js-step-playback');
7
6
 
8
7
  function isExceedingMaxResultSize(data, project) {
9
8
  try {
10
9
  const shouldEnforceMaxSize = project.defaults.enforceMaximumJsResultSize;
11
10
  const maximumJsResultSize = featureFlags.flags.maximumJsResultSize.getValue();
12
11
  const dataSizeExceeded = JSON.stringify(data).length > maximumJsResultSize;
13
- if(!shouldEnforceMaxSize) {
12
+ if (!shouldEnforceMaxSize) {
14
13
  return false;
15
14
  }
16
15
  return dataSizeExceeded;
@@ -19,17 +18,23 @@ function isExceedingMaxResultSize(data, project) {
19
18
  }
20
19
  }
21
20
 
22
- module.exports.run = (browser, step, projectData) => {
23
- const {code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, runTimeout, fileDataUrl, s3filepath} = step.data;
24
- return service.runCodeWithPackages(code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, runTimeout, fileDataUrl, s3filepath)
25
- .then(data => {
26
- if (data && isExceedingMaxResultSize({result: data.result, tstConsoleLogs: data.tstConsoleLogs}, projectData)) {
27
- return {
28
- code: 'js-result-max-size-exceeded',
29
- success: false,
30
- };
31
- }
32
- return {data, success: true};
33
- })
34
- .catch(Promise.TimeoutError, () => Promise.reject(new Error("Timeout while running action")));
21
+ module.exports.run = async (browser, step, projectData) => {
22
+ const {
23
+ code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, runTimeout, fileDataUrl, s3filepath,
24
+ } = step.data;
25
+ try {
26
+ const data = await service.runCodeWithPackages(code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, runTimeout, fileDataUrl, s3filepath);
27
+ if (data && isExceedingMaxResultSize({ result: data.result, tstConsoleLogs: data.tstConsoleLogs }, projectData)) {
28
+ return {
29
+ code: 'js-result-max-size-exceeded',
30
+ success: false,
31
+ };
32
+ }
33
+ return { data, success: true };
34
+ } catch (err) {
35
+ if (err instanceof TimeoutError) {
36
+ throw new Error('Timeout while running action');
37
+ }
38
+ throw err;
39
+ }
35
40
  };
package/testRunHandler.js CHANGED
@@ -111,6 +111,10 @@ class TestRun {
111
111
  return this._branch;
112
112
  }
113
113
 
114
+ getSfdcCredential() {
115
+ return this._options.sfdcCredential;
116
+ }
117
+
114
118
  getRemoteRunId() {
115
119
  return this._remoteRunId;
116
120
  }
@@ -203,6 +207,10 @@ class TestRun {
203
207
  runRequestParams.localRCASaver = this._options.localRCASaver;
204
208
  }
205
209
 
210
+ if (this.getSfdcCredential()) {
211
+ runRequestParams.sfdcCredential = this.getSfdcCredential();
212
+ }
213
+
206
214
  return runRequestParams;
207
215
  }
208
216
 
package/testRunStatus.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const constants = require('./commons/constants');
4
4
  const { TESTIM_CONCURRENT_WORKER_COUNT } = require('./commons/config');
5
- const utils = require('./utils.js');
5
+ const utils = require('./utils');
6
6
  const reporter = require('./reports/reporter.js');
7
7
  const servicesApi = require('./commons/testimServicesApi.js');
8
8
  const gridService = require('./services/gridService');
@@ -17,6 +17,7 @@ const { calculateCoverage } = require('./coverage/jsCoverage');
17
17
  const featureAvailabilityService = require('./commons/featureAvailabilityService');
18
18
  const featureFlags = require('./commons/featureFlags');
19
19
  const { mapFilesToLocalDrive } = require('./services/localRCASaver');
20
+ const { promiseMap } = require('./utils');
20
21
 
21
22
  const gitBranch = utils.getEnvironmentGitBranch();
22
23
  const gitCommit = process.env.GIT_COMMIT || process.env.CIRCLE_SHA1 || process.env.TRAVIS_COMMIT;
@@ -400,7 +401,7 @@ class RunStatus {
400
401
 
401
402
  const reportExecutionStarted = () => {
402
403
  const testResults = _.cloneDeep(this.testRunStatus);
403
- return Promise.map(Object.keys(testResults), testResultId => {
404
+ return promiseMap(Object.keys(testResults), testResultId => {
404
405
  const test = testResults[testResultId];
405
406
  const testData = test.config?.testData;
406
407
  const testId = test.testId;
@@ -498,10 +499,10 @@ class RunStatus {
498
499
  });
499
500
  }
500
501
 
501
- markAllQueuedTests(executionId, status, failureReason, success) {
502
+ async markAllQueuedTests(executionId, status, failureReason, success) {
502
503
  const queuedResultIds = Object.keys(this.testRunStatus).filter(resultId => this.getTestResult(resultId).status === 'QUEUED');
503
504
 
504
- return servicesApi.updateExecutionTests(
505
+ await servicesApi.updateExecutionTests(
505
506
  executionId,
506
507
  ['QUEUED'],
507
508
  status,
@@ -510,12 +511,14 @@ class RunStatus {
510
511
  this.startTime,
511
512
  null,
512
513
  this.options.project
513
- ).then(() => Promise.each(queuedResultIds, resultId => {
514
+ );
515
+ for (const resultId of queuedResultIds) {
514
516
  const test = this.getTestResult(resultId);
515
517
  test.status = status;
516
518
  test.failureReason = failureReason;
517
519
  test.success = success;
518
- })).then(() => this.testRunStatus);
520
+ }
521
+ return this.testRunStatus;
519
522
  }
520
523
  }
521
524
 
@@ -0,0 +1,86 @@
1
+ // @ts-check
2
+
3
+ 'use strict';
4
+
5
+ const { sessionType, testStatus: testStatusConst } = require('../commons/constants');
6
+
7
+
8
+ /**
9
+ * @typedef {import('../runOptions').Options} Options
10
+ * @typedef {import('../runOptions').InitModeOptions} InitModeOptions
11
+ * @typedef {import('../runOptions').LoginModeOptions} LoginModeOptions
12
+ * @typedef {import('../runOptions').TunnelOptions} TunnelOptions
13
+ * @typedef {import('../runOptions').NgrokTunnelOptions} NgrokTunnelOptions
14
+ * @typedef {import('../runOptions').TunnelDaemonOptions} TunnelDaemonOptions
15
+ * @typedef {import('../runOptions').RunnerOptions} RunnerOptions
16
+ */
17
+
18
+ /** @param {RunnerOptions} options */
19
+ function getSessionType(options) {
20
+ return options.files.length > 0 ? sessionType.CODEFUL : sessionType.CODELESS;
21
+ }
22
+
23
+ /**
24
+ * @param {RunnerOptions} options
25
+ * @param {{ runConfig: { browserValue: string } }[]} testList
26
+ */
27
+ function getUniqBrowsers(options, testList) {
28
+ if ((options.testConfigNames?.length || options.testConfigIds?.length || options.testPlan.length || options.testPlanIds.length) && !options.browser) {
29
+ return [...new Set(testList.map(t => t.runConfig.browserValue))];
30
+ }
31
+ return [options.browser?.toLowerCase()];
32
+ }
33
+
34
+ /** @param {RunnerOptions} options */
35
+ const hasTestPlanFlag = (options) => Boolean(options.testPlan?.length || options.testPlanIds?.length);
36
+
37
+ /** @param {RunnerOptions} options */
38
+ const isRemoteRun = (options) => options.resultId && options.source === 'remote-run';
39
+
40
+ /**
41
+ * @param {{ testStatus?: string }} test
42
+ * @param {RunnerOptions} options
43
+ */
44
+ const isQuarantineAndNotRemoteRun = (test, options) => test.testStatus === testStatusConst.QUARANTINE && !isRemoteRun(options) && !options.runQuarantinedTests;
45
+
46
+ function getArgsOnRemoteRunFailure() {
47
+ const { argv: args } = process;
48
+ if (!args.includes('--remoteRunId')) {
49
+ return undefined;
50
+ }
51
+ return {
52
+ remoteRunId: args[args.indexOf('--remoteRunId') + 1],
53
+ projectId: args[args.indexOf('--project') + 1],
54
+ token: args[args.indexOf('--token') + 1],
55
+ };
56
+ }
57
+
58
+
59
+ /** @type {(options: Options) => options is InitModeOptions} options */
60
+ // @ts-ignore should be `as any` etc
61
+ const isInitCodimMode = (options) => Boolean(options.initCodimMode);
62
+
63
+ /** @type {(options: Options) => options is LoginModeOptions} options */
64
+ // @ts-ignore should be `as any` etc
65
+ const isLoginMode = (options) => Boolean(options.loginMode);
66
+
67
+ /** @type {(options: Options) => options is TunnelOptions} options */
68
+ // @ts-ignore should be `as any` etc
69
+ const isTunnelOnlyMode = (options) => Boolean(options.tunnelOnlyMode);
70
+
71
+ /** @type {(options: Options) => options is RunnerOptions & { createPrefechedData: true; }} options */
72
+ // @ts-ignore should be `as any` etc
73
+ const isCreatePrefetchedDataMode = (options) => Boolean(options.createPrefechedData);
74
+
75
+ module.exports = {
76
+ getSessionType,
77
+ getUniqBrowsers,
78
+ hasTestPlanFlag,
79
+ isRemoteRun,
80
+ isQuarantineAndNotRemoteRun,
81
+ getArgsOnRemoteRunFailure,
82
+ isInitCodimMode,
83
+ isLoginMode,
84
+ isTunnelOnlyMode,
85
+ isCreatePrefetchedDataMode,
86
+ };
@@ -0,0 +1,32 @@
1
+ const chai = require('chai'); // eslint-disable-line import/no-extraneous-dependencies
2
+ const argsUtils = require('./argsUtils');
3
+
4
+ const expect = chai.expect;
5
+
6
+ describe('argsUtils', () => {
7
+ describe('getArgsOnRemoteRunFailure', () => {
8
+ let originalArgv;
9
+
10
+ beforeEach(() => {
11
+ originalArgv = process.argv;
12
+ });
13
+
14
+ afterEach(() => {
15
+ process.argv = originalArgv;
16
+ });
17
+
18
+ it('should return undefined if no remote run is current', () => {
19
+ process.argv = ['node', 'file.js', '--token', 'token', '--project', 'project-id'];
20
+ expect(argsUtils.getArgsOnRemoteRunFailure()).to.be.undefined;
21
+ });
22
+
23
+ it('should return details if remote run is current', () => {
24
+ process.argv = ['node', 'file.js', '--token', 'token', '--project', 'project-id', '--remoteRunId', 'remote-run-id'];
25
+ expect(argsUtils.getArgsOnRemoteRunFailure()).to.eql({
26
+ remoteRunId: 'remote-run-id',
27
+ projectId: 'project-id',
28
+ token: 'token',
29
+ });
30
+ });
31
+ });
32
+ });
@@ -0,0 +1,154 @@
1
+ // @ts-check
2
+
3
+ 'use strict';
4
+
5
+ const path = require('path');
6
+ const pRetry = require('p-retry');
7
+ const decompress = require('decompress');
8
+ const stringUtils = require('./stringUtils');
9
+ const httpRequest = require('../commons/httpRequest');
10
+ const { promises: fsPromises, createReadStream, createWriteStream, statSync } = require('fs');
11
+
12
+ const DOWNLOAD_RETRY = 3;
13
+
14
+ function getCliLocation() {
15
+ let cliLocation;
16
+ if (!require.main) { // we're in a REPL
17
+ return process.cwd(); // fall back on the current working directory
18
+ }
19
+ if (require.main.filename.includes('/src') || require.main.filename.includes('\\src') || process.env.IS_UNIT_TEST) {
20
+ cliLocation = path.resolve(__dirname, '../../');
21
+ } else {
22
+ cliLocation = path.resolve(__dirname, '../');
23
+ }
24
+
25
+ return cliLocation;
26
+ }
27
+
28
+ /**
29
+ * @param {string} url
30
+ */
31
+ const download = async (url) => pRetry(() => httpRequest.download(url), { retries: DOWNLOAD_RETRY });
32
+
33
+ /**
34
+ * @param {string} url
35
+ * @param {import('fs').PathLike} saveToLocation
36
+ */
37
+ const downloadAndSave = async (url, saveToLocation) => {
38
+ const res = await download(url);
39
+ return fsPromises.writeFile(saveToLocation, res.body);
40
+ };
41
+
42
+ /**
43
+ * @param {import('fs').PathLike} readFile
44
+ * @param {import('fs').PathLike} destFile
45
+ * @return {Promise<void>}
46
+ */
47
+ const copy = async (readFile, destFile) => new Promise((resolve, reject) => {
48
+ try {
49
+ // TODO: can this use fsPromises.copyFile?
50
+ const file = createWriteStream(destFile);
51
+ createReadStream(readFile).pipe(file);
52
+ file.on('finish', () => {
53
+ file.close(() => resolve());
54
+ });
55
+ } catch (err) {
56
+ reject(err);
57
+ }
58
+ });
59
+
60
+ /**
61
+ * @param {string} location
62
+ * @param {string=} fileName
63
+ */
64
+ function getSourcePath(location, fileName) {
65
+ if (stringUtils.isURL(location)) {
66
+ return fileName || path.join(process.cwd(), location.replace(/^.*[\\\/]/, ''));
67
+ }
68
+
69
+ return fileName || path.basename(location);
70
+ }
71
+
72
+ /**
73
+ * @param {string} location
74
+ * @param {string} fileName
75
+ */
76
+ const getSource = async (location, fileName) => {
77
+ const destFile = getSourcePath(location, fileName);
78
+ if (stringUtils.isURL(location)) {
79
+ return downloadAndSave(location, destFile);
80
+ }
81
+
82
+ return copy(location, destFile);
83
+ };
84
+
85
+ /**
86
+ * @param {string} location
87
+ */
88
+ const getSourceAsBuffer = async (location) => {
89
+ if (stringUtils.isURL(location)) {
90
+ return download(location);
91
+ }
92
+ return fsPromises.readFile(location);
93
+ };
94
+
95
+ /**
96
+ * @param {string} srcZipFile
97
+ * @param {string} destZipPath
98
+ */
99
+ const unzipFile = async (srcZipFile, destZipPath) => await decompress(srcZipFile, destZipPath);
100
+
101
+ /**
102
+ * @param {import('fs').PathLike} fileLocation
103
+ */
104
+ const getLocalFileSizeInMB = (fileLocation) => {
105
+ const stats = statSync(fileLocation);
106
+ const fileSizeInBytes = stats.size;
107
+ return fileSizeInBytes / 1000000;
108
+ };
109
+
110
+
111
+ function getRunnerVersion() {
112
+ try {
113
+ /** @type {import('../../package.json')} */
114
+ const pack = require(`${__dirname}/../package.json`); // eslint-disable-line import/no-dynamic-require
115
+ return pack.version;
116
+ } catch (err) {
117
+ return '';
118
+ }
119
+ }
120
+
121
+ function getEnginesVersion() {
122
+ try {
123
+ /** @type {import('../../package.json')} */
124
+ const pack = require(`${__dirname}/../package.json`); // eslint-disable-line import/no-dynamic-require
125
+ return pack.engines.node;
126
+ } catch (err) {
127
+ return '';
128
+ }
129
+ }
130
+
131
+ async function getEnginesVersionAsync() {
132
+ try {
133
+ /** @type {import('../../package.json')} */
134
+ const pack = JSON.parse(await fsPromises.readFile(`${__dirname}/../package.json`, 'utf8'));
135
+ return pack.engines.node;
136
+ } catch (err) {
137
+ return '';
138
+ }
139
+ }
140
+
141
+ module.exports = {
142
+ getCliLocation,
143
+ download,
144
+ downloadAndSave,
145
+ copy,
146
+ getSourcePath,
147
+ getSource,
148
+ getSourceAsBuffer,
149
+ unzipFile,
150
+ getLocalFileSizeInMB,
151
+ getRunnerVersion,
152
+ getEnginesVersion,
153
+ getEnginesVersionAsync,
154
+ };