@testim/testim-cli 3.235.0 → 3.238.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/server.js +2 -2
- package/cli.js +0 -2
- package/cliAgentMode.js +129 -15
- package/commons/chromedriverWrapper.js +1 -0
- package/commons/featureFlags.js +1 -0
- package/commons/prepareRunnerAndTestimStartUtils.js +7 -3
- package/commons/testimCloudflare.js +8 -8
- package/commons/testimCloudflare.test.js +162 -0
- package/commons/testimNgrok.js +6 -4
- package/commons/testimNgrok.test.js +140 -0
- package/commons/testimTunnel.js +5 -5
- package/commons/testimTunnel.test.js +69 -0
- package/executionQueue.js +4 -0
- package/npm-shrinkwrap.json +261 -234
- package/package.json +1 -1
- package/player/stepActions/inputFileStepAction.js +23 -14
- package/player/stepActions/textValidationStepAction.js +3 -0
- package/player/webdriver.js +13 -3
- package/runOptions.js +19 -0
- package/runOptionsAgentFlow.js +5 -0
- package/runner.js +1 -2
- package/runners/ParallelWorkerManager.js +14 -6
- package/runners/TestPlanRunner.js +10 -11
- package/services/lambdatestService.js +8 -9
- package/services/lambdatestService.test.js +259 -0
- package/testRunStatus.js +34 -5
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ const StepAction = require('./stepAction');
|
|
|
4
4
|
const _ = require('lodash');
|
|
5
5
|
const logger = require('../../commons/logger').getLogger('input-file-step-action');
|
|
6
6
|
const { codeSnippets, utils } = require('../../commons/getSessionPlayerRequire');
|
|
7
|
-
const { extractElementId } = require('../../utils');
|
|
7
|
+
const { extractElementId, download } = require('../../utils');
|
|
8
8
|
const inputFileUtils = require('../../inputFileUtils');
|
|
9
9
|
const featureFlagService = require('../../commons/featureFlags');
|
|
10
10
|
|
|
@@ -41,18 +41,15 @@ class InputFileStepAction extends StepAction {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async uploadFilesAndForceVisibility(gridLocalFiles, target) {
|
|
44
|
-
const preUploadStep = this.driver.isSafari() ?
|
|
45
|
-
// in safari we force the visibility ahead of time because making it visible the second time around doesn't work
|
|
46
|
-
this.safariPreUploadActions(target) :
|
|
47
|
-
Promise.resolve();
|
|
48
|
-
|
|
49
44
|
try {
|
|
50
|
-
|
|
45
|
+
if (this.driver.isSafari()) {
|
|
46
|
+
await this.safariPreUploadActions(target);
|
|
47
|
+
}
|
|
51
48
|
await this.uploadFiles(gridLocalFiles, target);
|
|
52
49
|
} catch (err) {
|
|
53
50
|
const edgeErrorEditableMessage = 'The element is not editable';
|
|
54
51
|
const edgeErrorFocusableMessage = 'The element is not focusable';
|
|
55
|
-
const
|
|
52
|
+
const safariErrorVisibleMessage = 'An element command could not be completed because the element is not visible on the page.';
|
|
56
53
|
const elementNotInteractable = 'element not interactable';
|
|
57
54
|
const elementNotPointerOrKeyboardInteractable = 'element is not pointer- or keyboard interactable';
|
|
58
55
|
const invalidStateMsg = 'invalid element state: Element is not currently interactable and may not be manipulated';
|
|
@@ -64,7 +61,7 @@ class InputFileStepAction extends StepAction {
|
|
|
64
61
|
_.startsWith(errorMsg, mustBeVisibleMsg) ||
|
|
65
62
|
_.startsWith(errorMsg, edgeErrorEditableMessage) ||
|
|
66
63
|
_.startsWith(errorMsg, edgeErrorFocusableMessage) ||
|
|
67
|
-
_.startsWith(errorMsg,
|
|
64
|
+
_.startsWith(errorMsg, safariErrorVisibleMessage) ||
|
|
68
65
|
_.includes(errorMsg, notReachableByKeyboard) ||
|
|
69
66
|
_.includes(errorMsg, elementNotInteractable) ||
|
|
70
67
|
_.includes(errorMsg, elementNotPointerOrKeyboardInteractable)
|
|
@@ -88,9 +85,18 @@ class InputFileStepAction extends StepAction {
|
|
|
88
85
|
async performAction() {
|
|
89
86
|
const target = this.context.data[this.step.targetId || 'targetId'];
|
|
90
87
|
const overrideAzureStorageUrl = featureFlagService.flags.overrideAzureStorageUrl.isEnabled();
|
|
91
|
-
|
|
92
|
-
const fileUrls = await utils.addTokenToFileUrl(this.context.project.id, this.step.fileUrls, this.stepActionUtils.testimServicesApi, overrideAzureStorageUrl, logger);
|
|
93
88
|
const useJsInputCodeInSafari = featureFlagService.flags.useJsInputCodeInSafari.isEnabled();
|
|
89
|
+
const downloadToBase64 = featureFlagService.flags.downloadToBase64.isEnabled();
|
|
90
|
+
|
|
91
|
+
let fileUrls = await utils.addTokenToFileUrl(this.context.project.id, this.step.fileUrls, this.stepActionUtils.testimServicesApi, overrideAzureStorageUrl, logger);
|
|
92
|
+
|
|
93
|
+
if (downloadToBase64) {
|
|
94
|
+
fileUrls = await Promise.all(fileUrls.map(async ({ name, url }) => {
|
|
95
|
+
const res = await download(url);
|
|
96
|
+
return { name, url: `data:${res.type};base64,${Buffer.from(res.body).toString('base64')}` };
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
if (this.driver.isSafari() && (useJsInputCodeInSafari || fileUrls.length > 1)) {
|
|
95
101
|
await this.driver.executeJSWithArray(`
|
|
96
102
|
const getLocatedElement = ${codeSnippets.getLocatedElementCode};
|
|
@@ -165,15 +171,18 @@ function downloadAndUpload() {
|
|
|
165
171
|
return new File([blob], name, { type: blob.type });
|
|
166
172
|
}));
|
|
167
173
|
|
|
168
|
-
|
|
174
|
+
const dt = new DataTransfer();
|
|
175
|
+
for (const file of fileList) {
|
|
176
|
+
dt.items.add(file);
|
|
177
|
+
}
|
|
178
|
+
element.files = dt.files;
|
|
179
|
+
|
|
169
180
|
let changeWasFired = false;
|
|
170
181
|
const changeFiredHandler = (e) => {
|
|
171
182
|
changeWasFired = true;
|
|
172
183
|
};
|
|
173
184
|
|
|
174
185
|
element.addEventListener("change", changeFiredHandler, true);
|
|
175
|
-
Reflect.deleteProperty(element, 'files');
|
|
176
|
-
Reflect.defineProperty(element, 'files', { get() { return fileList; }, configurable: true });
|
|
177
186
|
await Promise.resolve(); // wait microtick
|
|
178
187
|
element.dispatchEvent(new Event("input", { bubbles: true }));
|
|
179
188
|
if (!changeWasFired) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
const sessionPlayer = require('../../commons/getSessionPlayerRequire');
|
|
4
5
|
|
|
5
6
|
const StepAction = require('./stepAction');
|
|
@@ -7,6 +8,7 @@ const constants = sessionPlayer.commonConstants.stepResult;
|
|
|
7
8
|
const paramEvaluator = sessionPlayer.stepParamExpressionEvaluator;
|
|
8
9
|
const utils = sessionPlayer.utils;
|
|
9
10
|
|
|
11
|
+
|
|
10
12
|
const Promise = require('bluebird');
|
|
11
13
|
|
|
12
14
|
class TextValidationStepAction extends StepAction {
|
|
@@ -15,6 +17,7 @@ class TextValidationStepAction extends StepAction {
|
|
|
15
17
|
var context = this.context;
|
|
16
18
|
var target = this.getTarget();
|
|
17
19
|
var frameHandler = this.frameHandler;
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
return new Promise(resolve => {
|
|
20
23
|
var onFail = resultInfo => {
|
package/player/webdriver.js
CHANGED
|
@@ -59,6 +59,7 @@ class WebDriver extends WebDriverApi {
|
|
|
59
59
|
this.cdpUrl = undefined;
|
|
60
60
|
this.browserClosedCallbacks = [];
|
|
61
61
|
this.browserClosedFailedKeepAlives = 0;
|
|
62
|
+
this.ignoreHiddenTagsText = false;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
registerToClosedBrowser(callback) {
|
|
@@ -71,6 +72,7 @@ class WebDriver extends WebDriverApi {
|
|
|
71
72
|
|
|
72
73
|
async init(browserOptions, testName, testRunConfig, gridInfo, customExtensionLocalLocation, executionId, testResultId, seleniumPerfStats = new SeleniumPerfStats(), fastInit = false, lambdatestService) {
|
|
73
74
|
this.browserClosedFailedKeepAlives = 0;
|
|
75
|
+
this.ignoreHiddenTagsText = _(browserOptions).get('company.activePlan.premiumFeatures.ignoreHiddenTagsText');
|
|
74
76
|
this.browserClosedCallbacks = [];
|
|
75
77
|
const capabilities = desiredCapabilitiesBuilder.buildSeleniumOptions(browserOptions, testName, testRunConfig, gridInfo, customExtensionLocalLocation, executionId, testResultId, lambdatestService);
|
|
76
78
|
if (capabilities.desiredCapabilities) {
|
|
@@ -330,7 +332,7 @@ class WebDriver extends WebDriverApi {
|
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
getElementTextJS(locatedElement) {
|
|
333
|
-
function extractTextCode(locatedElement) {
|
|
335
|
+
function extractTextCode(locatedElement, ignoreHiddenTagsText) {
|
|
334
336
|
// copy of utils.getElementTextContent to run inside content script
|
|
335
337
|
// sadly .children doesn't work for SVG elements in IE11
|
|
336
338
|
function clearTitleTags(node) {
|
|
@@ -360,7 +362,15 @@ class WebDriver extends WebDriverApi {
|
|
|
360
362
|
return element.shadowRoot.textContent.replace(/(\r\n|\n|\r)/gm, "");
|
|
361
363
|
}
|
|
362
364
|
} catch (err) { }
|
|
363
|
-
|
|
365
|
+
if (ignoreHiddenTagsText && Array.prototype.some.call(element.children, function (elem) { return elem.hidden; })) {
|
|
366
|
+
var dupElement = element.cloneNode(true);
|
|
367
|
+
var hiddenChildren = Array.prototype.filter.call(dupElement.children, function (elem) { return elem.hidden; });
|
|
368
|
+
hiddenChildren.forEach(function (child) {
|
|
369
|
+
dupElement.removeChild(child);
|
|
370
|
+
});
|
|
371
|
+
return dupElement.textContent.replace(/(\r\n|\n|\r)/gm, '');
|
|
372
|
+
}
|
|
373
|
+
return element.textContent.replace(/(\r\n|\n|\r)/gm, '');
|
|
364
374
|
}
|
|
365
375
|
|
|
366
376
|
function getElementTextContent(element) {
|
|
@@ -390,7 +400,7 @@ class WebDriver extends WebDriverApi {
|
|
|
390
400
|
var getLocatedElement = ${codeSnippets().getLocatedElementCode};
|
|
391
401
|
var extractText = ${extractTextCode.toString()};
|
|
392
402
|
return extractText.apply(null, arguments)
|
|
393
|
-
`, locatedElement)
|
|
403
|
+
`, locatedElement, this.ignoreHiddenTagsText)
|
|
394
404
|
.then(result => result.value);
|
|
395
405
|
}
|
|
396
406
|
|
package/runOptions.js
CHANGED
|
@@ -187,6 +187,8 @@ program
|
|
|
187
187
|
.option('--token [token]', 'identification token to testim')
|
|
188
188
|
.option('--is-regression-baseline-run', 'save doms and run results as regression baseline data')
|
|
189
189
|
.option('--parallel [number-of-tests]', 'number of tests to run on parallel')
|
|
190
|
+
.option('--before-parallel [number-of-tests]', 'number of tests to run on parallel in the before phase of a test plan')
|
|
191
|
+
.option('--after-parallel [number-of-tests]', 'number of tests to run on parallel in the after phase of a test plan')
|
|
190
192
|
.option('--canary [canary-mode]', 'enable canary mode', false)
|
|
191
193
|
.option('--test-plan [test-plan-name]', 'test plan to run', collect, [])
|
|
192
194
|
.option('--test-plan-id [test-plan-id]', 'test plan to run', collect, [])
|
|
@@ -322,6 +324,7 @@ program
|
|
|
322
324
|
// Agent mode
|
|
323
325
|
.option('connect, --agent [enable-agent-mode]', 'enable Testim CLI agent mode', false)
|
|
324
326
|
.option('start [enable-start]', 'Connect to testim and open the editor in a standalone browser', false)
|
|
327
|
+
.option('--download-browser', 'when used with the start option, downloads a fixed version to run Testim editor in', false)
|
|
325
328
|
.option('--agent-port [agent-port]', 'set agent port', Number, 42543)
|
|
326
329
|
.option('--agent-bind [agent-host-bind]', 'set agent host bind', '127.0.0.1')
|
|
327
330
|
|
|
@@ -761,7 +764,9 @@ module.exports = {
|
|
|
761
764
|
|
|
762
765
|
const timeoutWasGiven = Boolean(program.timeout);
|
|
763
766
|
program.timeout = !program.timeout || typeof program.timeout === 'boolean' ? 10 * 60 * 1000 : Number(program.timeout);
|
|
767
|
+
program.beforeParallel = !program.beforeParallel || typeof program.beforeParallel === 'boolean' ? 1 : Number(program.beforeParallel);
|
|
764
768
|
program.parallel = !program.parallel || typeof program.parallel === 'boolean' ? 1 : Number(program.parallel);
|
|
769
|
+
program.afterParallel = !program.afterParallel || typeof program.afterParallel === 'boolean' ? 1 : Number(program.afterParallel);
|
|
765
770
|
|
|
766
771
|
|
|
767
772
|
if (program.parallel > 1 && program.run && !program.gridId && !program.grid &&
|
|
@@ -816,10 +821,18 @@ module.exports = {
|
|
|
816
821
|
throw new ArgError('test run timeout could not be a negative number, --timeout <run-timeout>');
|
|
817
822
|
}
|
|
818
823
|
|
|
824
|
+
if (program.beforeParallel <= 0 || _.isNaN(program.beforeParallel)) {
|
|
825
|
+
throw new ArgError('before-parallel could not be a negative number or not number, --before-parallel <number-of-tests>');
|
|
826
|
+
}
|
|
827
|
+
|
|
819
828
|
if (program.parallel <= 0 || _.isNaN(program.parallel)) {
|
|
820
829
|
throw new ArgError('parallel could not be a negative number or not number, --parallel <number-of-tests>');
|
|
821
830
|
}
|
|
822
831
|
|
|
832
|
+
if (program.afterParallel <= 0 || _.isNaN(program.afterParallel)) {
|
|
833
|
+
throw new ArgError('after-parallel could not be a negative number or not number, --after-parallel <number-of-tests>');
|
|
834
|
+
}
|
|
835
|
+
|
|
823
836
|
if (![CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].includes(program.mode)) {
|
|
824
837
|
throw new ArgError(`runner mode <${program.mode}> is not supported`);
|
|
825
838
|
}
|
|
@@ -865,6 +878,10 @@ module.exports = {
|
|
|
865
878
|
);
|
|
866
879
|
}
|
|
867
880
|
|
|
881
|
+
if (!isTestPlanSpecified && (program.beforeParallel !== 1 || program.afterParallel !== 1)) {
|
|
882
|
+
throw new ArgError('cannot set --before-parallel or --after-parallel without --test-plan option');
|
|
883
|
+
}
|
|
884
|
+
|
|
868
885
|
if (
|
|
869
886
|
(program.testId.length ||
|
|
870
887
|
isTestPlanSpecified ||
|
|
@@ -1088,7 +1105,9 @@ module.exports = {
|
|
|
1088
1105
|
mode: program.mode,
|
|
1089
1106
|
isRegressionBaselineRun: program.isRegressionBaselineRun,
|
|
1090
1107
|
browser: program.browser,
|
|
1108
|
+
beforeParallel: program.beforeParallel,
|
|
1091
1109
|
parallel: program.parallel,
|
|
1110
|
+
afterParallel: program.afterParallel,
|
|
1092
1111
|
canary: program.canary,
|
|
1093
1112
|
rerunFailedByRunId: program.rerunFailedByRunId,
|
|
1094
1113
|
disableGridCheck: program.disableGridCheck,
|
package/runOptionsAgentFlow.js
CHANGED
|
@@ -5,12 +5,16 @@
|
|
|
5
5
|
const { ArgError } = require('./errors');
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
const runOptionsUtils = require('./runOptionsUtils');
|
|
8
|
+
const analytics = require('./commons/testimAnalytics');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
*
|
|
11
12
|
* @param {import("commander").CommanderStatic} program
|
|
12
13
|
*/
|
|
13
14
|
function isAgentFlow(program) {
|
|
15
|
+
if (program.start) {
|
|
16
|
+
analytics.track(null, 'cli-start-command', { downloadBrowser: Boolean(program.downloadBrowser) });
|
|
17
|
+
}
|
|
14
18
|
if (program.startV2 || program.start || program.agent) {
|
|
15
19
|
return true;
|
|
16
20
|
}
|
|
@@ -73,6 +77,7 @@ async function runAgentFlow(program) {
|
|
|
73
77
|
canary: program.canary,
|
|
74
78
|
playerPath: program.playerPath,
|
|
75
79
|
playerRequirePath: program.playerRequirePath,
|
|
80
|
+
downloadBrowser: Boolean(program.downloadBrowser),
|
|
76
81
|
};
|
|
77
82
|
}
|
|
78
83
|
|
package/runner.js
CHANGED
|
@@ -25,7 +25,6 @@ const FREE_PLAN_MINIMUM_BROWSER_TIMEOUT = 30 * 60 * 1000;
|
|
|
25
25
|
const TestPlanRunner = require('./runners/TestPlanRunner');
|
|
26
26
|
const labFeaturesService = require('./services/labFeaturesService');
|
|
27
27
|
const featureAvailabilityService = require('./commons/featureAvailabilityService');
|
|
28
|
-
const featureFlagService = require('./commons/featureFlags');
|
|
29
28
|
|
|
30
29
|
const logger = require('./commons/logger').getLogger('runner');
|
|
31
30
|
|
|
@@ -269,7 +268,7 @@ async function init(options) {
|
|
|
269
268
|
await labFeaturesService.loadLabFeatures(projectById.id, companyByProjectId.activePlan);
|
|
270
269
|
}
|
|
271
270
|
|
|
272
|
-
if (options.lightweightMode && options.lightweightMode.type === 'turboMode' && (
|
|
271
|
+
if (options.lightweightMode && options.lightweightMode.type === 'turboMode' && (featureFlags.flags.highSpeedMode.getValue() === 'disabled' || options.company.planType === 'free')) {
|
|
273
272
|
delete options.lightweightMode;
|
|
274
273
|
}
|
|
275
274
|
|
|
@@ -8,7 +8,6 @@ const config = require('../commons/config');
|
|
|
8
8
|
const ExecutionQueue = require('../executionQueue');
|
|
9
9
|
|
|
10
10
|
const testimCustomToken = require('../commons/testimCustomToken');
|
|
11
|
-
const testimServicesApi = require('../commons/testimServicesApi');
|
|
12
11
|
const labFeaturesService = require('../services/labFeaturesService');
|
|
13
12
|
const perf = require('../commons/performance-logger');
|
|
14
13
|
const { StopRunOnError } = require('../errors');
|
|
@@ -51,6 +50,8 @@ class ParallelWorkerManager {
|
|
|
51
50
|
return undefined;
|
|
52
51
|
}
|
|
53
52
|
|
|
53
|
+
let stoppedOnError = false;
|
|
54
|
+
let runningTests = 0;
|
|
54
55
|
const runAndWaitToComplete = token => new Promise((resolve, reject) => {
|
|
55
56
|
const projectId = options.project;
|
|
56
57
|
const executionQueue = new ExecutionQueue(executionId, executionName, testList, options, branchToUse, testStatus);
|
|
@@ -69,6 +70,7 @@ class ParallelWorkerManager {
|
|
|
69
70
|
const sessionType = utils.getSessionType(options);
|
|
70
71
|
|
|
71
72
|
const onTestStarted = (wid, testId, resultId, isRerun, testRetryKey) => {
|
|
73
|
+
runningTests++;
|
|
72
74
|
analyticsService.analyticsTestStart({
|
|
73
75
|
authData,
|
|
74
76
|
executionId,
|
|
@@ -89,6 +91,7 @@ class ParallelWorkerManager {
|
|
|
89
91
|
};
|
|
90
92
|
|
|
91
93
|
const onTestCompleted = async (wid, testId, testResult, sessionId, isRerun) => {
|
|
94
|
+
runningTests--;
|
|
92
95
|
const update = {};
|
|
93
96
|
if (lightweightMode && lightweightMode.onlyTestIdsNoSuite) {
|
|
94
97
|
update.show = true;
|
|
@@ -151,11 +154,11 @@ class ParallelWorkerManager {
|
|
|
151
154
|
isStartUp,
|
|
152
155
|
});
|
|
153
156
|
if (stopOnError && !testResult.success) {
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
executionQueue.stop();
|
|
158
|
+
stoppedOnError = true;
|
|
156
159
|
}
|
|
157
160
|
const completedTests = Object.keys(combinedTestResults).length;
|
|
158
|
-
if (completedTests === testCount) {
|
|
161
|
+
if (completedTests === testCount || (stoppedOnError && runningTests === 0)) {
|
|
159
162
|
resolve(combinedTestResults);
|
|
160
163
|
return undefined;
|
|
161
164
|
}
|
|
@@ -165,8 +168,9 @@ class ParallelWorkerManager {
|
|
|
165
168
|
const onTestIgnored = (wid, testResult) => {
|
|
166
169
|
combinedTestResults[testResult.resultId] = testResult;
|
|
167
170
|
testStatus.onTestIgnored(wid, testResult.resultId);
|
|
171
|
+
runningTests--;
|
|
168
172
|
const completedTests = Object.keys(combinedTestResults).length;
|
|
169
|
-
if (completedTests === testCount) {
|
|
173
|
+
if (completedTests === testCount || (stoppedOnError && runningTests === 0)) {
|
|
170
174
|
resolve(combinedTestResults);
|
|
171
175
|
}
|
|
172
176
|
};
|
|
@@ -196,7 +200,11 @@ class ParallelWorkerManager {
|
|
|
196
200
|
|
|
197
201
|
try {
|
|
198
202
|
const token = await testimCustomToken.getCustomTokenV3();
|
|
199
|
-
|
|
203
|
+
const result = await runAndWaitToComplete(token);
|
|
204
|
+
if (stoppedOnError) {
|
|
205
|
+
throw new StopRunOnError();
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
200
208
|
} catch (err) {
|
|
201
209
|
logger.error('failed running parallel workers', { executionId, err });
|
|
202
210
|
throw err;
|
|
@@ -20,7 +20,6 @@ const { getSuite, calcTestResultStatus, validateConfig } = require('./runnerUtil
|
|
|
20
20
|
const { StopRunOnError, ArgError } = require('../errors');
|
|
21
21
|
const Logger = require('../commons/logger');
|
|
22
22
|
const perf = require('../commons/performance-logger');
|
|
23
|
-
const featureFlags = require('../commons/featureFlags');
|
|
24
23
|
|
|
25
24
|
const guid = utils.guid;
|
|
26
25
|
const logger = Logger.getLogger('test-plan-runner');
|
|
@@ -35,14 +34,14 @@ class TestPlanRunner {
|
|
|
35
34
|
const executionResults = {};
|
|
36
35
|
const authData = testimCustomToken.getTokenV3UserData();
|
|
37
36
|
|
|
38
|
-
const runBeforeTests = (
|
|
39
|
-
const workerCount = 1;
|
|
37
|
+
const runBeforeTests = () => {
|
|
38
|
+
const workerCount = tpOptions.beforeParallel || 1;
|
|
40
39
|
const stopOnError = true;
|
|
41
40
|
return this.workerManager.runTests(beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
|
42
41
|
.then(beforeTestsResults => Object.assign(executionResults, beforeTestsResults));
|
|
43
42
|
};
|
|
44
43
|
|
|
45
|
-
const runTestPlanTests = (
|
|
44
|
+
const runTestPlanTests = () => {
|
|
46
45
|
const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
|
|
47
46
|
const stopOnError = false;
|
|
48
47
|
perf.log('right before this.workerManager.runTests');
|
|
@@ -51,30 +50,30 @@ class TestPlanRunner {
|
|
|
51
50
|
.then(testsResults => Object.assign(executionResults, testsResults));
|
|
52
51
|
};
|
|
53
52
|
|
|
54
|
-
const runAfterTests = (
|
|
55
|
-
const workerCount = 1;
|
|
53
|
+
const runAfterTests = () => {
|
|
54
|
+
const workerCount = tpOptions.afterParallel || 1;
|
|
56
55
|
const stopOnError = false;
|
|
57
56
|
return this.workerManager.runTests(afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
|
58
57
|
.then(afterTestsResults => Object.assign(executionResults, afterTestsResults));
|
|
59
58
|
};
|
|
60
59
|
|
|
61
|
-
function catchBeforeTestsFailed(
|
|
60
|
+
function catchBeforeTestsFailed() {
|
|
62
61
|
return testStatus.markAllQueuedTests(executionId, constants.runnerTestStatus.ABORTED, 'aborted', false);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
const sessionType = utils.getSessionType(tpOptions);
|
|
66
65
|
analyticsService.analyticsExecsStart({ authData, executionId, projectId: tpOptions.project, sessionType });
|
|
67
66
|
perf.log('right before runBeforeTests');
|
|
68
|
-
return runBeforeTests(
|
|
67
|
+
return runBeforeTests()
|
|
69
68
|
.log('right before runTestPlanTests')
|
|
70
|
-
.then(() => runTestPlanTests(
|
|
69
|
+
.then(() => runTestPlanTests())
|
|
71
70
|
.log('right after runTestPlanTests')
|
|
72
|
-
.then(() => runAfterTests(
|
|
71
|
+
.then(() => runAfterTests())
|
|
73
72
|
.then(() => executionResults)
|
|
74
73
|
.catch(err => {
|
|
75
74
|
logger.error('error running test plan', { err });
|
|
76
75
|
if (err instanceof StopRunOnError) {
|
|
77
|
-
return catchBeforeTestsFailed(
|
|
76
|
+
return catchBeforeTestsFailed();
|
|
78
77
|
}
|
|
79
78
|
throw err;
|
|
80
79
|
})
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
|
-
const
|
|
2
|
+
const childProcess = require('child_process');
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
4
|
const fse = require('fs-extra');
|
|
5
5
|
const portfinder = require('portfinder');
|
|
6
6
|
const ms = require('ms');
|
|
7
7
|
|
|
8
|
-
const {
|
|
9
|
-
|
|
10
|
-
} = require('../utils');
|
|
8
|
+
const { guid, isURL } = require('../utils');
|
|
9
|
+
const utils = require('../utils');
|
|
11
10
|
const { gridTypes, CLI_MODE } = require('../commons/constants');
|
|
12
11
|
const httpRequest = require('../commons/httpRequest');
|
|
13
12
|
const { ArgError } = require('../errors');
|
|
@@ -86,8 +85,8 @@ class LambdatestService {
|
|
|
86
85
|
throw new Error(`tunnel on ${os.platform() + os.arch()} platform is not supported.`);
|
|
87
86
|
}
|
|
88
87
|
const zipLocation = `${LT_TUNNEL_BINARY_DIRECTORY}.zip`;
|
|
89
|
-
await downloadAndSave(`${LT_TUNNEL_BINARY_ORIGIN}/${downloadUrl}`, zipLocation);
|
|
90
|
-
await unzipFile(zipLocation, LT_TUNNEL_BINARY_DIRECTORY);
|
|
88
|
+
await utils.downloadAndSave(`${LT_TUNNEL_BINARY_ORIGIN}/${downloadUrl}`, zipLocation);
|
|
89
|
+
await utils.unzipFile(zipLocation, LT_TUNNEL_BINARY_DIRECTORY);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
static async connectTunnel(runnerOptions) {
|
|
@@ -140,7 +139,7 @@ class LambdatestService {
|
|
|
140
139
|
tunnelArgs = [...tunnelArgs, '--mitm'];
|
|
141
140
|
}
|
|
142
141
|
|
|
143
|
-
LambdatestService.tunnel = spawn('./LT', tunnelArgs, { cwd: LT_TUNNEL_BINARY_DIRECTORY });
|
|
142
|
+
LambdatestService.tunnel = childProcess.spawn('./LT', tunnelArgs, { cwd: LT_TUNNEL_BINARY_DIRECTORY });
|
|
144
143
|
|
|
145
144
|
let stdoutResult = '';
|
|
146
145
|
let stderrResult = '';
|
|
@@ -155,7 +154,7 @@ class LambdatestService {
|
|
|
155
154
|
|
|
156
155
|
// verify that LT tunnel strated successfully
|
|
157
156
|
try {
|
|
158
|
-
const ltInfo = await runWithRetries(() => httpRequest.get(`http://127.0.0.1:${infoAPIPort}/api/v1.0/info`, {}, {}, undefined, { skipProxy: true }), 30, 2000);
|
|
157
|
+
const ltInfo = await utils.runWithRetries(() => httpRequest.get(`http://127.0.0.1:${infoAPIPort}/api/v1.0/info`, {}, {}, undefined, { skipProxy: true }), 30, 2000);
|
|
159
158
|
logger.info('LT tunnel info', ltInfo);
|
|
160
159
|
} catch (err) {
|
|
161
160
|
logger.error('Failed to start LT tunnel', { err, stdoutResult, stderrResult });
|
|
@@ -170,7 +169,7 @@ class LambdatestService {
|
|
|
170
169
|
return new Promise((resolve, reject) => {
|
|
171
170
|
LambdatestService.tunnel.on('close', (code) => {
|
|
172
171
|
if (code) {
|
|
173
|
-
reject();
|
|
172
|
+
reject(new Error(`tunnel process exited with code ${code}`));
|
|
174
173
|
}
|
|
175
174
|
resolve();
|
|
176
175
|
});
|