@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.
- package/OverrideTestDataBuilder.js +1 -1
- package/agent/routers/cliJsCode/index.js +4 -4
- package/agent/routers/cliJsCode/router.js +46 -42
- package/agent/routers/cliJsCode/service.js +18 -13
- package/agent/routers/codim/router.js +14 -17
- package/agent/routers/codim/router.test.js +19 -21
- package/agent/routers/codim/service.js +16 -16
- package/agent/routers/general/index.js +4 -8
- package/agent/routers/hybrid/registerRoutes.js +18 -18
- package/agent/routers/index.js +7 -7
- package/agent/routers/playground/router.js +11 -10
- package/agent/routers/playground/service.js +22 -23
- package/agent/routers/standalone-browser/registerRoutes.js +10 -10
- package/cdpTestRunner.js +4 -3
- package/chromiumInstaller.js +4 -5
- package/cli/onExit.js +2 -2
- package/cli.js +11 -10
- package/cliAgentMode.js +8 -8
- package/codim/codim-cli.js +20 -17
- package/codim/hybrid-utils.js +1 -1
- package/codim/measure-perf.js +9 -6
- package/codim/template.js/tests/examples/01-simple-text-validation.test.js +6 -6
- package/codim/template.js/tests/examples/02-using-locators.test.js +13 -15
- package/codim/template.js/tests/examples/03-using-hooks.test.js +17 -19
- package/codim/template.js/tests/examples/04-skip-and-only.test.js +16 -17
- package/codim/template.js/tests/examples/05-multiple-windows.test.js +16 -17
- package/codim/template.js/webpack.config.js +1 -1
- package/codim/template.ts/webpack.config.js +3 -3
- package/commons/AbortError.js +4 -4
- package/commons/detectDebugger.js +4 -2
- package/commons/featureFlags.js +8 -0
- package/commons/httpRequest.js +5 -1
- package/commons/httpRequestCounters.js +21 -10
- package/commons/lazyRequire.js +14 -12
- package/commons/logger.js +4 -4
- package/commons/performance-logger.js +14 -8
- package/commons/preloadTests.js +2 -2
- package/commons/prepareRunner.js +4 -2
- package/commons/prepareRunnerAndTestimStartUtils.js +40 -42
- package/commons/runnerFileCache.js +1 -1
- package/commons/socket/baseSocketServiceSocketIO.js +32 -34
- package/commons/socket/realDataService.js +6 -5
- package/commons/socket/realDataServiceSocketIO.js +4 -4
- package/commons/socket/remoteStepService.js +4 -3
- package/commons/socket/remoteStepServiceSocketIO.js +11 -12
- package/commons/socket/socketService.js +50 -52
- package/commons/socket/testResultServiceSocketIO.js +11 -11
- package/commons/testimDesiredCapabilitiesBuilder.js +3 -2
- package/commons/testimNgrok.js +2 -2
- package/commons/testimNgrok.test.js +1 -1
- package/commons/testimServicesApi.js +27 -20
- package/commons/testimTunnel.test.js +2 -1
- package/commons/xhr2.js +97 -100
- package/coverage/SummaryToObjectReport.js +0 -1
- package/coverage/jsCoverage.js +12 -10
- package/errors.js +5 -0
- package/fixLocalBuild.js +2 -0
- package/inputFileUtils.js +11 -9
- package/npm-shrinkwrap.json +2286 -1284
- package/package.json +9 -8
- package/player/appiumTestPlayer.js +1 -1
- package/player/chromeLauncherTestPlayer.js +0 -1
- package/player/services/tabService.js +15 -1
- package/player/services/tabServiceMock.js +166 -0
- package/player/stepActions/locateStepAction.js +2 -0
- package/player/stepActions/navigationStepAction.js +11 -10
- package/player/stepActions/sleepStepAction.js +4 -5
- package/player/stepActions/textStepAction.js +4 -11
- package/player/utils/imageCaptureUtils.js +81 -120
- package/player/utils/windowUtils.js +4 -3
- package/player/webdriver.js +26 -23
- package/processHandler.js +3 -3
- package/processHandler.test.js +1 -1
- package/reports/consoleReporter.js +3 -2
- package/reports/junitReporter.js +7 -9
- package/reports/reporter.js +34 -39
- package/runOptions.d.ts +260 -0
- package/runOptions.js +59 -44
- package/runner.js +14 -0
- package/runners/ParallelWorkerManager.js +9 -10
- package/runners/TestPlanRunner.js +142 -78
- package/runners/buildCodeTests.js +38 -37
- package/runners/runnerUtils.js +3 -3
- package/services/gridService.js +36 -40
- package/services/lambdatestService.js +3 -5
- package/stepPlayers/cliJsStepPlayback.js +22 -17
- package/testRunHandler.js +8 -0
- package/testRunStatus.js +9 -6
- package/utils/argsUtils.js +86 -0
- package/utils/argsUtils.test.js +32 -0
- package/utils/fsUtils.js +154 -0
- package/{utils.js → utils/index.js} +19 -262
- package/utils/promiseUtils.js +89 -0
- package/utils/stringUtils.js +98 -0
- package/utils/stringUtils.test.js +22 -0
- package/utils/timeUtils.js +25 -0
- package/utils/utils.test.js +27 -0
- package/workers/BaseWorker.js +16 -14
- package/workers/WorkerAppium.js +1 -1
- package/workers/WorkerExtension.js +6 -7
- package/workers/WorkerExtensionSingleBrowser.js +4 -4
- package/workers/WorkerSelenium.js +5 -2
- package/utils.test.js +0 -68
package/services/gridService.js
CHANGED
|
@@ -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
|
|
41
|
-
const path = grid
|
|
40
|
+
const port = grid?.port;
|
|
41
|
+
const path = grid?.path;
|
|
42
42
|
const protocol = grid && extractProtocol(grid);
|
|
43
|
-
const accessToken = grid
|
|
44
|
-
const slotId = grid
|
|
45
|
-
const tunnel = grid
|
|
46
|
-
const user = grid
|
|
47
|
-
const key = grid
|
|
48
|
-
const type = grid
|
|
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
|
|
53
|
+
const name = grid?.name;
|
|
54
54
|
const gridId = grid && (grid._id || grid.gridId);
|
|
55
|
-
const provider = grid
|
|
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
|
|
101
|
-
return handleGetGridResponse(projectId, companyId, workerId, browser, () =>
|
|
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
|
|
107
|
-
if (grid
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
275
|
+
return getOptionGrid(options);
|
|
280
276
|
}
|
|
281
277
|
if (gridId) {
|
|
282
|
-
return getHostAndPortById(workerId, companyId, project, gridId, browser, executionId
|
|
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
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const service = require('../agent/routers/cliJsCode/service');
|
|
4
|
-
const
|
|
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 {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
)
|
|
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
|
-
}
|
|
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
|
+
});
|
package/utils/fsUtils.js
ADDED
|
@@ -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
|
+
};
|