@testim/testim-cli 3.255.0 → 3.257.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/agent/routers/cliJsCode/service.js +11 -8
- package/cli.js +2 -2
- package/cliAgentMode.js +7 -7
- package/codim/codim-cli.js +4 -1
- package/commons/featureFlags.js +21 -7
- package/commons/httpRequest.js +1 -1
- package/commons/initializeUserWithAuth.js +7 -4
- package/commons/preloadTests.js +5 -2
- package/commons/prepareRunner.js +5 -5
- package/commons/prepareRunnerAndTestimStartUtils.js +11 -4
- package/commons/runnerFileCache.js +9 -1
- package/commons/testimServicesApi.js +36 -5
- package/npm-shrinkwrap.json +59 -60
- package/package.json +1 -1
- package/player/stepActions/apiStepAction.js +49 -43
- package/player/stepActions/baseCliJsStepAction.js +19 -14
- package/player/stepActions/baseJsStepAction.js +9 -8
- package/player/stepActions/dropFileStepAction.js +1 -3
- package/player/stepActions/inputFileStepAction.js +10 -8
- package/player/stepActions/mouseStepAction.js +21 -22
- package/player/stepActions/nodePackageStepAction.js +34 -35
- package/player/stepActions/stepAction.js +1 -0
- package/player/utils/imageCaptureUtils.js +63 -63
- package/player/utils/screenshotUtils.js +16 -13
- package/player/utils/windowUtils.js +20 -8
- package/processHandler.js +4 -0
- package/runOptions.d.ts +27 -1
- package/runOptions.js +7 -7
- package/runner.js +62 -23
- package/runners/ParallelWorkerManager.js +3 -2
- package/runners/TestPlanRunner.js +9 -6
- package/runners/buildCodeTests.js +1 -0
- package/runners/runnerUtils.js +11 -2
- package/services/branchService.js +11 -5
- package/services/localRCASaver.js +4 -0
|
@@ -40,10 +40,6 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
40
40
|
return all;
|
|
41
41
|
}, '');
|
|
42
42
|
|
|
43
|
-
if (fileDataUrl === 'data:') { // fix chrome/safari bug that creates malformed datauri for empty files
|
|
44
|
-
fileDataUrl = 'data:,';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
43
|
const fileDataUrlToFileBuffer = !fileDataUrl ? 'var fileBuffer = null;' :
|
|
48
44
|
`
|
|
49
45
|
${dataUriToBuffer.toString()}
|
|
@@ -297,10 +293,6 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
|
|
|
297
293
|
return all;
|
|
298
294
|
}, '');
|
|
299
295
|
|
|
300
|
-
if (fileDataUrl === 'data:') { // fix chrome/safari bug that creates malformed datauri for empty files
|
|
301
|
-
fileDataUrl = 'data:,';
|
|
302
|
-
}
|
|
303
|
-
|
|
304
296
|
const fileDataUrlToFileBuffer = !fileDataUrl ? 'var fileBuffer = null;' :
|
|
305
297
|
`
|
|
306
298
|
${dataUriToBuffer.toString()}
|
|
@@ -581,6 +573,17 @@ function runCodeWithPackages(code, stepId, incomingParams, context, testResultId
|
|
|
581
573
|
}
|
|
582
574
|
}
|
|
583
575
|
|
|
576
|
+
if (Buffer.isBuffer(fileDataUrl)) { // Fix, S3 is returning a buffer and not a string on empty files
|
|
577
|
+
logger.debug('runCodeWithPackages: converted a buffer to base 64 string data URI', { fileDataUrl });
|
|
578
|
+
fileDataUrl = fileDataUrl.toString();
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const emptyFileDataUrl = 'data:,';
|
|
582
|
+
if (fileDataUrl === 'data:') { // Fix chrome/safari bug that creates malformed data-uri for empty files
|
|
583
|
+
logger.debug('runCodeWithPackages, fileDataUrl was an empty string ', { fileDataUrl });
|
|
584
|
+
fileDataUrl = emptyFileDataUrl;
|
|
585
|
+
}
|
|
586
|
+
|
|
584
587
|
if (workerThreads && featureFlags.flags.enableWorkerThreadsCliCodeExecution.isEnabled()) {
|
|
585
588
|
return runCodeWithWorkerThread(transactionId, incomingParams, context, code, packageLocalLocations, timeout, fileDataUrl);
|
|
586
589
|
}
|
package/cli.js
CHANGED
|
@@ -85,9 +85,9 @@ async function main() {
|
|
|
85
85
|
}
|
|
86
86
|
const res = await runnerFileCache.waitForSave();
|
|
87
87
|
if (res.success) {
|
|
88
|
-
console.log(`created
|
|
88
|
+
console.log(`created prefetched data at ${runnerFileCache.getCacheFileLocation()}`);
|
|
89
89
|
} else {
|
|
90
|
-
console.error('failed to create
|
|
90
|
+
console.error('failed to create prefetch data', res.error);
|
|
91
91
|
}
|
|
92
92
|
return undefined;
|
|
93
93
|
}
|
package/cliAgentMode.js
CHANGED
|
@@ -39,10 +39,7 @@ function shouldStartAgentMode(options) {
|
|
|
39
39
|
return options.agentMode;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
* @param {*} options
|
|
45
|
-
*/
|
|
42
|
+
/** @param {import('./runOptions').AgentModeOptions} options */
|
|
46
43
|
async function runAgentMode(options) {
|
|
47
44
|
let testimStandaloneBrowser;
|
|
48
45
|
|
|
@@ -169,6 +166,7 @@ async function startFixedVersionChromium(options, extensionBase64, downloadedExt
|
|
|
169
166
|
};
|
|
170
167
|
}
|
|
171
168
|
|
|
169
|
+
/** @param {import('./runOptions').AgentModeOptions} options */
|
|
172
170
|
async function startTestimStandaloneBrowser(options) {
|
|
173
171
|
// After next clickim release we will have also testim-full.zip
|
|
174
172
|
// const fullExtensionUrl = "https://testimstatic.blob.core.windows.net/extension/testim-full-master.zip";
|
|
@@ -222,9 +220,11 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
222
220
|
}
|
|
223
221
|
await prepareUtils.prepareChromeDriver(
|
|
224
222
|
{ projectId: options.project },
|
|
223
|
+
// @ts-expect-error not clear where chromeBinaryLocations comes from
|
|
225
224
|
{ chromeBinaryLocation: options.chromeBinaryLocations },
|
|
226
225
|
);
|
|
227
226
|
|
|
227
|
+
// @ts-expect-error not clear where chromeBinaryLocations comes from
|
|
228
228
|
const seleniumOptions = buildSeleniumOptions(USER_DATA_DIR, extensionBase64, options.extensionPath, options.chromeBinaryLocations);
|
|
229
229
|
|
|
230
230
|
const WebDriver = require('./player/webdriver');
|
|
@@ -264,7 +264,7 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
266
|
* @param {string} userDataDir
|
|
267
|
-
* @param {string} fullExtensionPath
|
|
267
|
+
* @param {string | null} fullExtensionPath
|
|
268
268
|
*/
|
|
269
269
|
function buildSeleniumOptions(userDataDir, fullExtensionPath, unpackedExtensionPath, chromeBinaryPath) {
|
|
270
270
|
const extensions = fullExtensionPath ? [fullExtensionPath] : [];
|
|
@@ -356,7 +356,7 @@ async function readAndValidateChromedriverDevToolsActivePortFile() {
|
|
|
356
356
|
|
|
357
357
|
/**
|
|
358
358
|
* @param {string | import("url").URL} webSocketDebuggerUrl
|
|
359
|
-
* @param {number
|
|
359
|
+
* @param {number=} timeout
|
|
360
360
|
*/
|
|
361
361
|
async function tryToCloseBrowserWithCDPUrl(webSocketDebuggerUrl, timeout = 100) {
|
|
362
362
|
const websocketConnection = await wsConnectAndOpen(webSocketDebuggerUrl, timeout);
|
|
@@ -371,7 +371,7 @@ async function tryToCloseBrowserWithCDPUrl(webSocketDebuggerUrl, timeout = 100)
|
|
|
371
371
|
|
|
372
372
|
/**
|
|
373
373
|
* @param {string | import("url").URL} webSocketDebuggerUrl
|
|
374
|
-
* @param {number
|
|
374
|
+
* @param {number=} timeout
|
|
375
375
|
*/
|
|
376
376
|
async function wsConnectAndOpen(webSocketDebuggerUrl, timeout = 100) {
|
|
377
377
|
const websocket = new WebSocket(webSocketDebuggerUrl, { timeout });
|
package/codim/codim-cli.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/* eslint-disable no-console */
|
|
2
4
|
|
|
3
5
|
'use strict';
|
|
@@ -6,11 +8,12 @@ const fs = require('fs');
|
|
|
6
8
|
const childProcess = require('child_process');
|
|
7
9
|
const path = require('path');
|
|
8
10
|
const validateNpmPackageName = require('validate-npm-package-name');
|
|
9
|
-
const ArgError = require('../errors.js').ArgError;
|
|
10
11
|
const { promisify } = require('util');
|
|
12
|
+
const { ArgError } = require('../errors.js');
|
|
11
13
|
|
|
12
14
|
const exec = promisify(childProcess.exec);
|
|
13
15
|
|
|
16
|
+
/** @param {string} name */
|
|
14
17
|
module.exports.init = async function init(name) {
|
|
15
18
|
const ora = require('ora');
|
|
16
19
|
const prompts = require('prompts');
|
package/commons/featureFlags.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { ROLLOUT_KEY, IS_ON_PREM, GATEWAY_URL } = require('./config');
|
|
4
|
-
const logger = require('./logger').getLogger('FeatureFlagsService');
|
|
5
|
-
const Promise = require('bluebird');
|
|
6
3
|
const Rox = require('rox-node');
|
|
4
|
+
const { getLogger } = require('./logger');
|
|
5
|
+
const { promiseTimeout } = require('../utils');
|
|
6
|
+
const { ROLLOUT_KEY, IS_ON_PREM, GATEWAY_URL } = require('./config');
|
|
7
|
+
|
|
8
|
+
const logger = getLogger('FeatureFlagsService');
|
|
7
9
|
|
|
8
10
|
// IS_UNIT_TEST = disable rollout if code run in unit test mode to ignore mocha process stuck on running
|
|
9
11
|
const USE_FEATURE_FLAGS = !IS_ON_PREM && !process.env.IS_UNIT_TEST && !GATEWAY_URL;
|
|
@@ -11,6 +13,7 @@ const USE_FEATURE_FLAGS = !IS_ON_PREM && !process.env.IS_UNIT_TEST && !GATEWAY_U
|
|
|
11
13
|
const FORCE_FETCH_TIMEOUT_MS = 20000; // rollout sometimes takes up to 15 seconds to load
|
|
12
14
|
const SEC_IN_DAY = 60 * 60 * 24;
|
|
13
15
|
|
|
16
|
+
/** @type {['labs', 'disabled', 'enabled'] as const} */
|
|
14
17
|
const LAB_FEATURE_FLAG_VALUES = ['labs', 'disabled', 'enabled'];
|
|
15
18
|
|
|
16
19
|
class LabFeatureFlag extends Rox.Variant {
|
|
@@ -18,6 +21,7 @@ class LabFeatureFlag extends Rox.Variant {
|
|
|
18
21
|
super(initialValue, LAB_FEATURE_FLAG_VALUES);
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/** @returns {(typeof LAB_FEATURE_FLAG_VALUES)[number]} */
|
|
21
25
|
getValue() {
|
|
22
26
|
const value = super.getValue();
|
|
23
27
|
if (!LAB_FEATURE_FLAG_VALUES.includes(value)) {
|
|
@@ -63,41 +67,51 @@ class FeatureFlagsService {
|
|
|
63
67
|
Rox.register('default', this.flags);
|
|
64
68
|
}
|
|
65
69
|
|
|
70
|
+
/** @param {string} projectId */
|
|
66
71
|
setProjectId(projectId) {
|
|
67
72
|
Rox.setCustomStringProperty('projectId', projectId);
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
/** @param {string} projectType */
|
|
70
76
|
setProjectType(projectType) {
|
|
71
77
|
Rox.setCustomStringProperty('projectType', projectType);
|
|
72
78
|
}
|
|
73
79
|
|
|
80
|
+
/** @param {string} productType */
|
|
74
81
|
setCompanyProductType(productType) {
|
|
75
82
|
Rox.setCustomStringProperty('productType', productType);
|
|
76
83
|
}
|
|
77
84
|
|
|
85
|
+
/** @param {string} companyId */
|
|
78
86
|
setCompanyId(companyId) {
|
|
79
87
|
Rox.setCustomStringProperty('companyId', companyId);
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
/** @param {string} planType */
|
|
82
91
|
setPlanType(planType) {
|
|
83
92
|
Rox.setCustomStringProperty('planType', planType);
|
|
84
93
|
}
|
|
85
94
|
|
|
95
|
+
/** @param {boolean} isPOC */
|
|
86
96
|
setIsPOC(isPOC) {
|
|
87
97
|
Rox.setCustomBooleanProperty('isPOC', isPOC);
|
|
88
98
|
}
|
|
99
|
+
|
|
100
|
+
/** @param {boolean} isStartUp */
|
|
89
101
|
setIsStartUp(isStartUp) {
|
|
90
102
|
Rox.setCustomBooleanProperty('isStartUp', isStartUp);
|
|
91
103
|
}
|
|
92
104
|
|
|
105
|
+
/** @param {string} mode */
|
|
93
106
|
setRunnerMode(mode) {
|
|
94
107
|
Rox.setCustomStringProperty('runnerMode', mode);
|
|
95
108
|
}
|
|
96
109
|
|
|
97
|
-
fetch() {
|
|
110
|
+
async fetch() {
|
|
98
111
|
if (!USE_FEATURE_FLAGS) {
|
|
99
|
-
return
|
|
112
|
+
return undefined;
|
|
100
113
|
}
|
|
114
|
+
/** @type {Rox.RoxSetupOptions} */
|
|
101
115
|
const opts = {
|
|
102
116
|
fetchIntervalInSec: SEC_IN_DAY, // we don't actually want to refresh feature flags in the CLI,
|
|
103
117
|
disableNetworkFetch: false,
|
|
@@ -110,8 +124,8 @@ class FeatureFlagsService {
|
|
|
110
124
|
opts.httpAgent = agent;
|
|
111
125
|
}
|
|
112
126
|
|
|
113
|
-
return
|
|
114
|
-
.
|
|
127
|
+
return promiseTimeout(Rox.setup(ROLLOUT_KEY, opts), FORCE_FETCH_TIMEOUT_MS)
|
|
128
|
+
.catch(err => logger.error('failed to get feature flag status', err));
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
131
|
|
package/commons/httpRequest.js
CHANGED
|
@@ -217,7 +217,7 @@ function put(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
|
|
|
217
217
|
|
|
218
218
|
/**
|
|
219
219
|
* @param {string} url
|
|
220
|
-
* @returns {Promise<superagent.Response>}
|
|
220
|
+
* @returns {Promise<Omit<superagent.Response, 'body'> & { body: Buffer }>}
|
|
221
221
|
*/
|
|
222
222
|
function download(url) {
|
|
223
223
|
logger.info('start to download', { url });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
const perf = require('./performance-logger');
|
|
3
3
|
const localRunnerCache = require('./runnerFileCache');
|
|
4
|
-
const servicesApi = require('./testimServicesApi
|
|
4
|
+
const servicesApi = require('./testimServicesApi');
|
|
5
5
|
const testimCustomToken = require('./testimCustomToken');
|
|
6
6
|
const { CLI_MODE } = require('./constants');
|
|
7
7
|
|
|
@@ -24,12 +24,15 @@ function preloadSlowRequires(mode) {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('../runOptions').RunnerOptions} options
|
|
29
|
+
*/
|
|
27
30
|
async function initializeUserWithAuth(options) {
|
|
28
31
|
const { project, token, lightweightMode, useLocalChromeDriver, useChromeLauncher, mode } = options;
|
|
29
32
|
|
|
30
|
-
const
|
|
33
|
+
const lightweightModeGeneral = Boolean(lightweightMode?.general);
|
|
31
34
|
const localGrid = Boolean(useLocalChromeDriver || useChromeLauncher);
|
|
32
|
-
const memoizationTTL =
|
|
35
|
+
const memoizationTTL = lightweightModeGeneral ? TEN_HOURS_MS : FIVE_MINUTES_MS;
|
|
33
36
|
|
|
34
37
|
perf.log('before initializeUserWithAuth');
|
|
35
38
|
const result = await localRunnerCache.memoize(async () => {
|
|
@@ -41,7 +44,7 @@ async function initializeUserWithAuth(options) {
|
|
|
41
44
|
lightweightMode,
|
|
42
45
|
localGrid,
|
|
43
46
|
});
|
|
44
|
-
}, 'initializeUserWithAuth', memoizationTTL, { project, token, branchName: options.branch,
|
|
47
|
+
}, 'initializeUserWithAuth', memoizationTTL, { project, token, branchName: options.branch, lightweightModeGeneral, localGrid })();
|
|
45
48
|
perf.log('after initializeUserWithAuth');
|
|
46
49
|
|
|
47
50
|
testimCustomToken.initFromData(result.authData, options.project, options.token);
|
package/commons/preloadTests.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const { promiseMap } = require('../utils');
|
|
3
2
|
const localRunnerCache = require('./runnerFileCache');
|
|
4
|
-
const servicesApi = require('./testimServicesApi
|
|
3
|
+
const servicesApi = require('./testimServicesApi');
|
|
4
|
+
const { promiseMap } = require('../utils');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
const TEN_HOURS = 1000 * 60 * 60 * 10;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('../runOptions').RunnerOptions} options
|
|
11
|
+
*/
|
|
9
12
|
async function preloadTests(options) {
|
|
10
13
|
if (!Array.isArray(options.testId) || !options.testId.length) {
|
|
11
14
|
return {};
|
package/commons/prepareRunner.js
CHANGED
|
@@ -22,6 +22,7 @@ Promise.resolve().then(() => {
|
|
|
22
22
|
global.xhr2 = require('./xhr2'); // this is inside a `then` to not block and let network requests start
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
/** @param {import('../runOptions').RunnerOptions} options */
|
|
25
26
|
async function prepare(options) {
|
|
26
27
|
/**
|
|
27
28
|
* @type {globalThis.Promise<void>}
|
|
@@ -61,16 +62,15 @@ async function prepare(options) {
|
|
|
61
62
|
|
|
62
63
|
async function prepareMockNetwork(location) {
|
|
63
64
|
logger.info('prepare MockNetwork', { location });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const rulesJsonBuf = await utils.getSourceAsBuffer(location);
|
|
65
|
+
const _rulesJson = await utils.getSourceAsBuffer(location);
|
|
66
|
+
const rulesJsonBuf = Buffer.isBuffer(_rulesJson) ? _rulesJson : _rulesJson.body;
|
|
67
67
|
if (rulesJsonBuf.byteLength > MAX_RULE_FILE_SIZE_IN_MB * 1000000) {
|
|
68
68
|
throw new Error(`${PREPARE_MOCK_NETWORK_ERROR_PREFIX} exceeded ${MAX_RULE_FILE_SIZE_IN_MB}MB`);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
let rulesJson;
|
|
72
72
|
try {
|
|
73
|
-
rulesJson = JSON.parse(rulesJsonBuf);
|
|
73
|
+
rulesJson = JSON.parse(rulesJsonBuf.toString('utf-8'));
|
|
74
74
|
} catch (error) {
|
|
75
75
|
throw new Error(`${PREPARE_MOCK_NETWORK_ERROR_PREFIX} cannot be parsed.${os.EOL}${error}`);
|
|
76
76
|
}
|
|
@@ -78,7 +78,7 @@ async function prepareMockNetwork(location) {
|
|
|
78
78
|
const ajv = new Ajv();
|
|
79
79
|
const valid = ajv.validate(mockNetworkRuleFileSchema, rulesJson);
|
|
80
80
|
if (!valid) {
|
|
81
|
-
const errors = ajv.errors
|
|
81
|
+
const errors = ajv.errors?.map((e, i) => `${++i}) ${e.dataPath} ${e.message}`).join(os.EOL);
|
|
82
82
|
throw new Error(`${PREPARE_MOCK_NETWORK_ERROR_PREFIX} is malformed.${os.EOL}${errors}`);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -140,7 +140,7 @@ async function getPlayerVersion() {
|
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* @param {string} location
|
|
143
|
-
* @param {
|
|
143
|
+
* @param {boolean=} canary
|
|
144
144
|
*/
|
|
145
145
|
async function getPlayerLocation(location, canary) {
|
|
146
146
|
if (!isURL(location) || (isURL(location) && canary) || config.IS_ON_PREM) {
|
|
@@ -177,13 +177,20 @@ async function downloadAndUnzip(loc, playerFileName, isRetry = false) {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* @param {string} location
|
|
182
|
+
* @param {boolean=} canary
|
|
183
|
+
*/
|
|
180
184
|
async function preparePlayer(location, canary) {
|
|
181
185
|
logger.info('prepare player', { location, canary });
|
|
182
186
|
const playerFileName = getPlayerDestination();
|
|
183
187
|
return localRunnerCache.memoize(
|
|
184
|
-
() =>
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
async () => {
|
|
189
|
+
const loc = await getPlayerLocation(location, canary);
|
|
190
|
+
await downloadAndUnzip(loc, playerFileName);
|
|
191
|
+
// return a truthy value, so the caching has a value, and doesn't ignore
|
|
192
|
+
return {};
|
|
193
|
+
},
|
|
187
194
|
'preparePlayer',
|
|
188
195
|
MSEC_IN_HALF_DAY,
|
|
189
196
|
[location, canary, playerFileName]
|
|
@@ -79,7 +79,15 @@ function decrypt(key, buffer) {
|
|
|
79
79
|
const decrypted = decipher.update(encryptedText);
|
|
80
80
|
return JSON.parse(Buffer.concat([decrypted, decipher.final()]));
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
/**
|
|
83
|
+
* argument-less memoize for functions with a global cache name
|
|
84
|
+
* @template T
|
|
85
|
+
* @param {() => PromiseLike<T>} fn
|
|
86
|
+
* @param {string} fnName
|
|
87
|
+
* @param {number=} duration
|
|
88
|
+
* @param {*} parameters
|
|
89
|
+
* @returns {() => Promise<Awaited<T>>}
|
|
90
|
+
*/
|
|
83
91
|
function memoize(fn, fnName, duration = THREE_HOURS, parameters = undefined) {
|
|
84
92
|
return Promise.method(async () => {
|
|
85
93
|
if (!cacheEnabled) {
|
|
@@ -192,6 +192,27 @@ async function getTestPlanTestList(projectId, names, planIds, branch, intersecti
|
|
|
192
192
|
}), { retries: DEFAULT_REQUEST_RETRY });
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* @param {{
|
|
197
|
+
* projectId: string;
|
|
198
|
+
* labels: string[];
|
|
199
|
+
* testIds: string[];
|
|
200
|
+
* testNames: string[];
|
|
201
|
+
* testConfigNames?: string[];
|
|
202
|
+
* suiteNames: string[];
|
|
203
|
+
* suiteIds: string[];
|
|
204
|
+
* branch: string;
|
|
205
|
+
* rerunFailedByRunId?: string;
|
|
206
|
+
* testConfigIds?: string[];
|
|
207
|
+
* intersections: import('../runOptions').RunnerOptions['intersections'];
|
|
208
|
+
* }} param0
|
|
209
|
+
* @returns {globalThis.Promise<{
|
|
210
|
+
* tests: any[][];
|
|
211
|
+
* branch?: string;
|
|
212
|
+
* runName?: string;
|
|
213
|
+
* runExists?: boolean;
|
|
214
|
+
* }>}
|
|
215
|
+
*/
|
|
195
216
|
function getSuiteTestList({
|
|
196
217
|
projectId, labels, testIds, testNames, testConfigNames, suiteNames, suiteIds, branch, rerunFailedByRunId, testConfigIds, intersections,
|
|
197
218
|
}) {
|
|
@@ -263,7 +284,17 @@ function getGridById(companyId, projectId, gridId, browser, executionId) {
|
|
|
263
284
|
return pRetry(() => getWithAuth(`/grid/${gridId}`, { companyId, projectId, browser, executionId, reqId: utils.guid() }), { retries: DEFAULT_REQUEST_RETRY });
|
|
264
285
|
}
|
|
265
286
|
|
|
266
|
-
|
|
287
|
+
/**
|
|
288
|
+
* @param {{ projectId: string; token: string; branchName: string; lightweightMode?: import('../runOptions').LightweightSettings; localGrid: boolean; }} param0
|
|
289
|
+
* @returns {globalThis.Promise<{
|
|
290
|
+
* authData: { token: string; refreshToken: string; uid: string; ngrokToken?: string; isNgrokWhitelisted?: boolean; };
|
|
291
|
+
* editorConfig: { editorUrl: string };
|
|
292
|
+
* companyByProjectId: Awaited<ReturnType<import('services/src/company/companyService')['getCompanyByProjectIdUsingCache']>>;
|
|
293
|
+
* projectById: NonNullable<Awaited<ReturnType<import('services/src/commons/testimCache')['project']['getById']>>>;
|
|
294
|
+
* allGrids: import('services/src/commons/mongo/models/grid').RawGrid[];
|
|
295
|
+
* branchName: string | import('services/src/commons/mongo/models/branchesData').RawBranchesData | null;
|
|
296
|
+
* }>}
|
|
297
|
+
*/
|
|
267
298
|
async function initializeUserWithAuth({ projectId, token, branchName, lightweightMode, localGrid }) {
|
|
268
299
|
try {
|
|
269
300
|
return await pRetry(() => httpRequest.post({
|
|
@@ -278,14 +309,14 @@ async function initializeUserWithAuth({ projectId, token, branchName, lightweigh
|
|
|
278
309
|
}), { retries: DEFAULT_REQUEST_RETRY });
|
|
279
310
|
} catch (e) {
|
|
280
311
|
logger.error('error initializing info from server', e);
|
|
281
|
-
if (e
|
|
312
|
+
if (e?.message?.includes('Bad Request')) {
|
|
282
313
|
throw new ArgError(
|
|
283
314
|
'Error trying to retrieve CLI token. ' +
|
|
284
315
|
'Your CLI token and project might not match. ' +
|
|
285
316
|
'Please make sure to pass `--project` and `--token` that' +
|
|
286
317
|
' match to each other or make sure they match in your ~/.testim file.');
|
|
287
318
|
}
|
|
288
|
-
if (e
|
|
319
|
+
if (e?.code?.includes('ENOTFOUND')) {
|
|
289
320
|
throw new ArgError('Due to network connectivity issues, Testim CLI has been unable to connect to the Testim backend.');
|
|
290
321
|
}
|
|
291
322
|
throw e;
|
|
@@ -415,7 +446,7 @@ const updateTestDataArtifact = _.memoize(async (projectId, testId, testResultId,
|
|
|
415
446
|
}
|
|
416
447
|
const removeHiddenParamsInTestData = () => {
|
|
417
448
|
const testDataValueClone = _.clone(testData);
|
|
418
|
-
if (projectDefaults
|
|
449
|
+
if (projectDefaults?.hiddenParams) {
|
|
419
450
|
const { hiddenParams } = projectDefaults;
|
|
420
451
|
(hiddenParams || []).forEach((param) => {
|
|
421
452
|
if (testDataValueClone[param]) {
|
|
@@ -521,7 +552,7 @@ module.exports = {
|
|
|
521
552
|
getLabFeaturesByProjectId,
|
|
522
553
|
uploadRunDataArtifact: Promise.method(uploadRunDataArtifact),
|
|
523
554
|
updateTestDataArtifact: Promise.method(updateTestDataArtifact),
|
|
524
|
-
initializeUserWithAuth
|
|
555
|
+
initializeUserWithAuth,
|
|
525
556
|
addTestRetry,
|
|
526
557
|
getHybridGridProvider,
|
|
527
558
|
loadSfdcCredential,
|