@testim/testim-cli 3.233.0 → 3.236.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 +4 -38
- 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 +16 -13
- 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/npm-shrinkwrap.json +261 -245
- package/package.json +1 -2
- package/player/stepActions/inputFileStepAction.js +23 -14
- package/player/stepActions/textValidationStepAction.js +3 -0
- package/player/webdriver.js +10 -1
- package/processHandler.js +9 -4
- package/runOptions.js +70 -70
- package/runOptionsAgentFlow.js +5 -0
- package/runner.js +1 -2
- package/runners/ParallelWorkerManager.js +0 -1
- package/runners/TestPlanRunner.js +8 -9
- package/services/lambdatestService.js +13 -9
- package/services/lambdatestService.test.js +259 -0
- package/testRunStatus.js +34 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.236.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -69,7 +69,6 @@
|
|
|
69
69
|
"data-uri-to-buffer": "2.0.2",
|
|
70
70
|
"decompress": "4.2.1",
|
|
71
71
|
"express": "4.17.3",
|
|
72
|
-
"find-root": "1.1.0",
|
|
73
72
|
"fkill": "7.2.1",
|
|
74
73
|
"form-data": "3.0.0",
|
|
75
74
|
"fs-extra": "10.0.1",
|
|
@@ -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) {
|
|
@@ -360,7 +362,14 @@ 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 (this.ignoreHiddenTagsText && Array.prototype.some.call(element.children, elem => elem.hidden)) {
|
|
366
|
+
const dupElement = element.cloneNode(true);
|
|
367
|
+
const hiddenChildren = Array.prototype.filter.call(dupElement.children, elem => elem.hidden);
|
|
368
|
+
hiddenChildren.forEach(child => {
|
|
369
|
+
dupElement.removeChild(child);
|
|
370
|
+
});
|
|
371
|
+
return dupElement.textContent.replace(/(\r\n|\n|\r)/gm, "");
|
|
372
|
+
} return element.textContent.replace(/(\r\n|\n|\r)/gm, "");
|
|
364
373
|
}
|
|
365
374
|
|
|
366
375
|
function getElementTextContent(element) {
|
package/processHandler.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const logger = require('./commons/logger').getLogger('process-handler');
|
|
@@ -6,9 +8,12 @@ const exitHooks = [];
|
|
|
6
8
|
const Promise = require('bluebird');
|
|
7
9
|
|
|
8
10
|
module.exports = function (onExit) {
|
|
9
|
-
|
|
11
|
+
async function cleanup(err) {
|
|
10
12
|
// give cleanup and socket reports a chance to run
|
|
11
13
|
await Promise.all(exitHooks.map(x => x())).timeout(10000).catch(() => {});
|
|
14
|
+
onExit(err);
|
|
15
|
+
}
|
|
16
|
+
process.on('uncaughtException', async (err) => {
|
|
12
17
|
logger.error('Caught exception', { err });
|
|
13
18
|
console.log('Uncaught exception');
|
|
14
19
|
if (err.message) {
|
|
@@ -17,7 +22,7 @@ module.exports = function (onExit) {
|
|
|
17
22
|
if (err.reason) {
|
|
18
23
|
console.log('Reason =', err.reason);
|
|
19
24
|
}
|
|
20
|
-
|
|
25
|
+
await cleanup(err);
|
|
21
26
|
});
|
|
22
27
|
|
|
23
28
|
process.on('unhandledRejection', (reason) => {
|
|
@@ -40,7 +45,7 @@ module.exports = function (onExit) {
|
|
|
40
45
|
const msg = 'Runner aborted - SIGTERM event';
|
|
41
46
|
const err = new Error(msg);
|
|
42
47
|
logger.error(msg);
|
|
43
|
-
|
|
48
|
+
cleanup(err);
|
|
44
49
|
throw err;
|
|
45
50
|
});
|
|
46
51
|
|
|
@@ -48,7 +53,7 @@ module.exports = function (onExit) {
|
|
|
48
53
|
const msg = 'Runner aborted - SIGINT event';
|
|
49
54
|
const err = new Error(msg);
|
|
50
55
|
logger.error(msg);
|
|
51
|
-
|
|
56
|
+
cleanup(err);
|
|
52
57
|
throw err;
|
|
53
58
|
});
|
|
54
59
|
|
package/runOptions.js
CHANGED
|
@@ -306,6 +306,7 @@ program
|
|
|
306
306
|
.option('--external-lambdatest-tunnel-id [tunnel-id]', 'use existing lambdatest tunnel ID')
|
|
307
307
|
.option('--external-lambdatest-use-wss', 'use wss instead of ssh for LT', false)
|
|
308
308
|
.option('--external-lambdatest-disable-automation-tunneling', 'don\'t tunnel Testim calls in LT tunnel', true)
|
|
309
|
+
.option('--external-lambdatest-mitm', 'Turn on LT Man in the middle', false)
|
|
309
310
|
|
|
310
311
|
.option('--w3c-capabilities [enable-w3c-caps-mode]', 'enable/disable w3c capabilities format (default enable)', JSON.parse, true)
|
|
311
312
|
.option('--old-capabilities [enable-old-caps-mode]', 'enable/disable old capabilities format (default enable)', JSON.parse, true)
|
|
@@ -321,6 +322,7 @@ program
|
|
|
321
322
|
// Agent mode
|
|
322
323
|
.option('connect, --agent [enable-agent-mode]', 'enable Testim CLI agent mode', false)
|
|
323
324
|
.option('start [enable-start]', 'Connect to testim and open the editor in a standalone browser', false)
|
|
325
|
+
.option('--download-browser', 'when used with the start option, downloads a fixed version to run Testim editor in', false)
|
|
324
326
|
.option('--agent-port [agent-port]', 'set agent port', Number, 42543)
|
|
325
327
|
.option('--agent-bind [agent-host-bind]', 'set agent host bind', '127.0.0.1')
|
|
326
328
|
|
|
@@ -494,7 +496,7 @@ module.exports = {
|
|
|
494
496
|
}
|
|
495
497
|
|
|
496
498
|
if (program.proxyForGrid && !program.proxy) {
|
|
497
|
-
|
|
499
|
+
throw new ArgError('missing --proxy option');
|
|
498
500
|
}
|
|
499
501
|
|
|
500
502
|
if (runOptionsAgentFlow.isAgentFlow(program)) {
|
|
@@ -553,20 +555,20 @@ module.exports = {
|
|
|
553
555
|
}
|
|
554
556
|
}
|
|
555
557
|
|
|
556
|
-
if (program.reporters && program.reporters.
|
|
558
|
+
if (program.reporters && program.reporters.includes('junit') && !program.reportFile) {
|
|
557
559
|
console.log('Warning: please define --report-file option for JUnit reporter');
|
|
558
560
|
}
|
|
559
561
|
|
|
560
562
|
if (!program.tunnel && program.externalLambdatestTunnelId) {
|
|
561
|
-
|
|
563
|
+
throw new ArgError('missing --tunnel parameter');
|
|
562
564
|
}
|
|
563
565
|
|
|
564
566
|
if (!program.tunnel && program.externalLambdatestUseWss) {
|
|
565
|
-
|
|
567
|
+
throw new ArgError('missing --tunnel parameter');
|
|
566
568
|
}
|
|
567
569
|
|
|
568
570
|
if (!program.tunnel && [program.tunnelPort, program.tunnelHostHeader, program.tunnelRegion, program.tunnelDiagnostics].some(Boolean)) {
|
|
569
|
-
|
|
571
|
+
throw new ArgError('missing --tunnel parameter');
|
|
570
572
|
}
|
|
571
573
|
if (program.chromeExtraPrefs) {
|
|
572
574
|
try {
|
|
@@ -609,7 +611,7 @@ module.exports = {
|
|
|
609
611
|
|
|
610
612
|
// SauceLabs Options
|
|
611
613
|
if ((program.sauceUser && !program.sauceKey) || (!program.sauceUser && program.sauceKey)) {
|
|
612
|
-
|
|
614
|
+
throw new ArgError('missing --sauce-user <sauce-user> or --sauce-key <sauce-key>');
|
|
613
615
|
}
|
|
614
616
|
|
|
615
617
|
if (program.sauceUser && program.sauceKey) {
|
|
@@ -655,7 +657,7 @@ module.exports = {
|
|
|
655
657
|
|
|
656
658
|
// BrowserStack options
|
|
657
659
|
if ((program.browserstackUser && !program.browserstackKey) || (!program.browserstackUser && program.browserstackKey)) {
|
|
658
|
-
|
|
660
|
+
throw new ArgError('missing --browserstack-user <browserstack-user> or --browserstack-key <browserstack-key>');
|
|
659
661
|
}
|
|
660
662
|
if (program.browserstackUser && program.browserstackKey) {
|
|
661
663
|
setHostAndPortForBrowserStack();
|
|
@@ -726,7 +728,7 @@ module.exports = {
|
|
|
726
728
|
if (projectId) {
|
|
727
729
|
program.project = projectId;
|
|
728
730
|
} else {
|
|
729
|
-
|
|
731
|
+
throw new ArgError('missing project-id info, either --login to provide new credentials or use --project <project-id>');
|
|
730
732
|
}
|
|
731
733
|
}
|
|
732
734
|
|
|
@@ -737,12 +739,12 @@ module.exports = {
|
|
|
737
739
|
|
|
738
740
|
if (program.testConfig) {
|
|
739
741
|
// convert single test config inputs to array (e.g. from configFile)
|
|
740
|
-
program.testConfig = [].
|
|
742
|
+
program.testConfig = [program.testConfig].flat();
|
|
741
743
|
}
|
|
742
744
|
|
|
743
745
|
if (program.testConfigId) {
|
|
744
746
|
// convert single test config inputs to array (e.g. from configFile)
|
|
745
|
-
program.testConfigId = [].
|
|
747
|
+
program.testConfigId = [program.testConfigId].flat();
|
|
746
748
|
}
|
|
747
749
|
|
|
748
750
|
program.retries = !program.retries || typeof program.retries === 'boolean' ? 1 : Number(program.retries) + 1;
|
|
@@ -764,21 +766,19 @@ module.exports = {
|
|
|
764
766
|
|
|
765
767
|
|
|
766
768
|
if (program.parallel > 1 && program.run && !program.gridId && !program.grid &&
|
|
767
|
-
((!program.testPlan || program.testPlan.length === 0) && (!program.testPlanId || !program.testPlanId.length))) {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
process.exit(0);
|
|
781
|
-
}
|
|
769
|
+
((!program.testPlan || program.testPlan.length === 0) && (!program.testPlanId || !program.testPlanId.length)) && process.stdout.isTTY && !program.headless && !process.env.TERM) {
|
|
770
|
+
const prompts = require('prompts');
|
|
771
|
+
const response = await prompts({
|
|
772
|
+
type: 'toggle',
|
|
773
|
+
name: 'isSure',
|
|
774
|
+
message: 'Running in parallel without --headless flag will open several browsers on your computer. Are you sure?',
|
|
775
|
+
initial: false,
|
|
776
|
+
active: 'yes',
|
|
777
|
+
inactive: 'no',
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
if (!response.isSure) {
|
|
781
|
+
process.exit(0);
|
|
782
782
|
}
|
|
783
783
|
}
|
|
784
784
|
|
|
@@ -787,11 +787,11 @@ module.exports = {
|
|
|
787
787
|
program.port = program.port && Number(program.port);
|
|
788
788
|
|
|
789
789
|
if (program.retries <= 0 || _.isNaN(program.retries)) {
|
|
790
|
-
|
|
790
|
+
throw new ArgError('test failure retry count could not be a negative number or string, --retries <max_num_of_retries>');
|
|
791
791
|
}
|
|
792
792
|
|
|
793
793
|
if (program.retries > 21) {
|
|
794
|
-
|
|
794
|
+
throw new ArgError('Max number of retries exceeded. Number cannot be greater than 20, --retries <max_num_of_retries>');
|
|
795
795
|
}
|
|
796
796
|
|
|
797
797
|
if (!program.token) {
|
|
@@ -801,33 +801,32 @@ module.exports = {
|
|
|
801
801
|
if (credentialToken) {
|
|
802
802
|
program.token = credentialToken;
|
|
803
803
|
} else {
|
|
804
|
-
|
|
805
|
-
new ArgError('missing Testim Access Token, either --login to provide new credentials or use --token <testim-access-token>, contact info@testim.io if you need a new one.'));
|
|
804
|
+
throw new ArgError('missing Testim Access Token, either --login to provide new credentials or use --token <testim-access-token>, contact info@testim.io if you need a new one.');
|
|
806
805
|
}
|
|
807
806
|
}
|
|
808
807
|
|
|
809
808
|
if (program.browserTimeout <= 0 || _.isNaN(program.browserTimeout)) {
|
|
810
|
-
|
|
809
|
+
throw new ArgError('get browser timeout could not be a negative number, --browser-timeout <get-browser-timeout>');
|
|
811
810
|
}
|
|
812
811
|
|
|
813
812
|
if (program.newBrowserWaitTimeout <= 0 || _.isNaN(program.newBrowserWaitTimeout)) {
|
|
814
|
-
|
|
813
|
+
throw new ArgError('max new browser wait timeout could not be a negative number, --new-browser-wait-timeout <max-wait-to-browser>');
|
|
815
814
|
}
|
|
816
815
|
|
|
817
816
|
if (program.timeout <= 0 || _.isNaN(program.timeout)) {
|
|
818
|
-
|
|
817
|
+
throw new ArgError('test run timeout could not be a negative number, --timeout <run-timeout>');
|
|
819
818
|
}
|
|
820
819
|
|
|
821
820
|
if (program.parallel <= 0 || _.isNaN(program.parallel)) {
|
|
822
|
-
|
|
821
|
+
throw new ArgError('parallel could not be a negative number or not number, --parallel <number-of-tests>');
|
|
823
822
|
}
|
|
824
823
|
|
|
825
|
-
if ([CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].
|
|
826
|
-
|
|
824
|
+
if (![CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].includes(program.mode)) {
|
|
825
|
+
throw new ArgError(`runner mode <${program.mode}> is not supported`);
|
|
827
826
|
}
|
|
828
827
|
|
|
829
828
|
if ((program.mode !== CLI_MODE.SELENIUM) && program.disableNativeEvents) {
|
|
830
|
-
|
|
829
|
+
throw new ArgError('disable-native-events is only applicable in selenium mode');
|
|
831
830
|
}
|
|
832
831
|
|
|
833
832
|
if (
|
|
@@ -848,9 +847,9 @@ module.exports = {
|
|
|
848
847
|
!program.useChromeLauncher &&
|
|
849
848
|
!program.createPrefechedData
|
|
850
849
|
) {
|
|
851
|
-
|
|
850
|
+
throw new ArgError(
|
|
852
851
|
'missing remote grid address parameter, specify --host <host-name-or-ip> or --grid <grid-name> or --grid-id <grid-id>'
|
|
853
|
-
)
|
|
852
|
+
);
|
|
854
853
|
}
|
|
855
854
|
} else if (
|
|
856
855
|
program.testId.length ||
|
|
@@ -862,9 +861,9 @@ module.exports = {
|
|
|
862
861
|
program.useLocalChromeDriver ||
|
|
863
862
|
program.useChromeLauncher
|
|
864
863
|
) {
|
|
865
|
-
|
|
864
|
+
throw new ArgError(
|
|
866
865
|
'cannot set --testId, --label, --name, --browser, --test-config, --test-config-id, --use-local-chrome-driver --use-chrome-launcher or --suite with --test-plan option'
|
|
867
|
-
)
|
|
866
|
+
);
|
|
868
867
|
}
|
|
869
868
|
|
|
870
869
|
if (
|
|
@@ -875,17 +874,17 @@ module.exports = {
|
|
|
875
874
|
isSuiteSpecified) &&
|
|
876
875
|
program.file
|
|
877
876
|
) {
|
|
878
|
-
|
|
877
|
+
throw new ArgError(
|
|
879
878
|
'Cannot pass codeful automation tests with --testId --label --name or --suite'
|
|
880
|
-
)
|
|
879
|
+
);
|
|
881
880
|
}
|
|
882
881
|
|
|
883
882
|
const numberOfDefinedHosts = [program.host, program.grid, program.gridId].filter(Boolean).length;
|
|
884
883
|
if (numberOfDefinedHosts > 1) {
|
|
885
|
-
|
|
884
|
+
throw new ArgError('please define exactly one of --grid or --grid-id or --host');
|
|
886
885
|
}
|
|
887
886
|
|
|
888
|
-
if (program.host && program.host.
|
|
887
|
+
if (program.host && program.host.includes('/')) {
|
|
889
888
|
if (!/^(f|ht)tps?:\/\//i.test(program.host)) {
|
|
890
889
|
program.host = `http://${program.host}`;
|
|
891
890
|
}
|
|
@@ -896,7 +895,7 @@ module.exports = {
|
|
|
896
895
|
program.resultLabel = program.resultLabel.map(label => label.trim()).filter(Boolean);
|
|
897
896
|
const invalidLabels = program.resultLabel.filter(label => label.length >= 250).filter(Boolean);
|
|
898
897
|
if (invalidLabels.length) {
|
|
899
|
-
|
|
898
|
+
throw new ArgError('A result label cannot exceed 250 characters');
|
|
900
899
|
}
|
|
901
900
|
}
|
|
902
901
|
|
|
@@ -904,66 +903,66 @@ module.exports = {
|
|
|
904
903
|
const playerUrl = runOptionsUtils.getPlayerUrl(program);
|
|
905
904
|
|
|
906
905
|
if (!program.w3cCapabilities && !program.oldCapabilities) {
|
|
907
|
-
|
|
906
|
+
throw new ArgError('cannot set --w3c-capabilities and --old-capabilities options as false');
|
|
908
907
|
}
|
|
909
908
|
program.protocol = program.protocol || (program.port === 443 ? 'https' : 'http');
|
|
910
909
|
if (!['http', 'https'].includes(program.protocol)) {
|
|
911
|
-
|
|
910
|
+
throw new ArgError('invalid --protocol value, allow --protocol http or https');
|
|
912
911
|
}
|
|
913
912
|
|
|
914
913
|
if (program.rerunFailedByRunId && program.branch) {
|
|
915
|
-
|
|
914
|
+
throw new ArgError('It is not possible to use --branch with --rerun-failed-by-run-id. Tests will automatically run on the same branch that was used in the original run');
|
|
916
915
|
}
|
|
917
916
|
|
|
918
917
|
if (program.rerunFailedByRunId &&
|
|
919
918
|
(isSuiteSpecified || program.name.length ||
|
|
920
919
|
program.testId.length || program.label.length || isTestPlanSpecified)) {
|
|
921
|
-
|
|
922
|
-
' label (--label), plan (--test-plan), or other test flags (--test) are provided. Please remove these flags and try again')
|
|
920
|
+
throw new ArgError('Re-running failed tests is not possible when suite (--suite),' +
|
|
921
|
+
' label (--label), plan (--test-plan), or other test flags (--test) are provided. Please remove these flags and try again');
|
|
923
922
|
}
|
|
924
923
|
|
|
925
924
|
if (program.run.length) {
|
|
926
925
|
const glob = require('glob');
|
|
927
926
|
program.files = _.flatMap(program.run, files => glob.sync(files));
|
|
928
927
|
if (program.files.length === 0) {
|
|
929
|
-
|
|
928
|
+
throw new ArgError(`No files found at path '${program.run}'.`);
|
|
930
929
|
}
|
|
931
930
|
} else {
|
|
932
931
|
program.files = [];
|
|
933
932
|
}
|
|
934
933
|
|
|
935
934
|
if (program.setRetention && !_.inRange(_.parseInt(program.setRetention), 1, 11)) {
|
|
936
|
-
|
|
935
|
+
throw new ArgError('Please provide the number of days that the test results will be retained for (--set-retention must be a whole number between 1 to 10)');
|
|
937
936
|
}
|
|
938
937
|
program.setRetention = program.setRetention && Number(program.setRetention);
|
|
939
938
|
|
|
940
939
|
const mockNetworkDeprecationMsg = 'is no longer supported, please use --override-mapping-file';
|
|
941
940
|
if (program.mockNetworkHar) {
|
|
942
|
-
|
|
941
|
+
throw new ArgError(`--mock-network-har ${mockNetworkDeprecationMsg}`);
|
|
943
942
|
}
|
|
944
943
|
if (program.mockNetworkPattern) {
|
|
945
|
-
|
|
944
|
+
throw new ArgError(`--mock-network-pattern ${mockNetworkDeprecationMsg}`);
|
|
946
945
|
}
|
|
947
946
|
|
|
948
947
|
if (program.disableMockNetwork && program.overrideMappingFile) {
|
|
949
|
-
|
|
948
|
+
throw new ArgError('You can either use --disable-mock-network or --override-mapping-file');
|
|
950
949
|
}
|
|
951
950
|
|
|
952
951
|
if (!program.collectCodeCoverage && program.codeCoverageSourceMapPath) {
|
|
953
|
-
|
|
952
|
+
throw new ArgError('cannot set --code-coverage-source-map-path without passing --collect-code-coverage');
|
|
954
953
|
}
|
|
955
954
|
|
|
956
955
|
if (!program.collectCodeCoverage && program.codeCoverageReporter.length) {
|
|
957
|
-
|
|
956
|
+
throw new ArgError('cannot set --code-coverage-reporter without passing --collect-code-coverage');
|
|
958
957
|
}
|
|
959
958
|
|
|
960
959
|
if (!program.collectCodeCoverage && program.codeCoverageInclude.length) {
|
|
961
|
-
|
|
960
|
+
throw new ArgError('cannot set --code-coverage-include without passing --collect-code-coverage');
|
|
962
961
|
}
|
|
963
962
|
|
|
964
963
|
if (program.collectCodeCoverage && program.codeCoverageReporter && _.difference(program.codeCoverageReporter, CODE_COVERAGE_REPORTER_OPTIONS).length) {
|
|
965
964
|
const diff = _.difference(program.codeCoverageReporter, CODE_COVERAGE_REPORTER_OPTIONS);
|
|
966
|
-
|
|
965
|
+
throw new ArgError(`invalid --code-coverage-reporter parameters ${diff.join('/')}`);
|
|
967
966
|
}
|
|
968
967
|
|
|
969
968
|
program.codeCoverageReporter = program.codeCoverageReporter.length === 0 ? ['html', 'text'] : program.codeCoverageReporter;
|
|
@@ -982,7 +981,7 @@ module.exports = {
|
|
|
982
981
|
|
|
983
982
|
if (program.mode !== CLI_MODE.EXTENSION && usedExtensionOptions.length) {
|
|
984
983
|
const multi = usedExtensionOptions.length > 1 ? 'are' : 'is';
|
|
985
|
-
|
|
984
|
+
throw new ArgError(`${usedExtensionOptions.map(key => extensionOnlyOptions[key]).join(' and ')} ${multi} only applicable in extension mode`);
|
|
986
985
|
}
|
|
987
986
|
|
|
988
987
|
if (program.tmsFieldFile) {
|
|
@@ -1054,18 +1053,18 @@ module.exports = {
|
|
|
1054
1053
|
}
|
|
1055
1054
|
|
|
1056
1055
|
if (typeof program.baseUrl === 'boolean') {
|
|
1057
|
-
|
|
1056
|
+
throw new ArgError('base url cannot be used as a flag, and must contain a string value');
|
|
1058
1057
|
}
|
|
1059
1058
|
|
|
1060
1059
|
return ({
|
|
1061
|
-
testId: [].
|
|
1062
|
-
name: [].
|
|
1063
|
-
label: [].
|
|
1064
|
-
suites: [].
|
|
1065
|
-
suiteIds: [].
|
|
1066
|
-
testPlan: [].
|
|
1067
|
-
testPlanIds: [].
|
|
1068
|
-
files: [].
|
|
1060
|
+
testId: [program.testId].flat(),
|
|
1061
|
+
name: [program.name].flat(),
|
|
1062
|
+
label: [program.label].flat(),
|
|
1063
|
+
suites: [program.suite].flat(),
|
|
1064
|
+
suiteIds: [program.suiteId].flat(),
|
|
1065
|
+
testPlan: [program.testPlan].flat(),
|
|
1066
|
+
testPlanIds: [program.testPlanId].flat(),
|
|
1067
|
+
files: [program.files].flat(),
|
|
1069
1068
|
webpackConfig: program.webpackConfig,
|
|
1070
1069
|
reportFile: program.reportFile,
|
|
1071
1070
|
reportFileClassname: program.overrideReportFileClassname,
|
|
@@ -1116,7 +1115,7 @@ module.exports = {
|
|
|
1116
1115
|
|
|
1117
1116
|
// Extension
|
|
1118
1117
|
ext: program.ext,
|
|
1119
|
-
extensionLocation: [
|
|
1118
|
+
extensionLocation: [program.extensionPath || extHeadlessUrl].flat(),
|
|
1120
1119
|
extensionPath: program.extensionPath,
|
|
1121
1120
|
|
|
1122
1121
|
// Player
|
|
@@ -1136,6 +1135,7 @@ module.exports = {
|
|
|
1136
1135
|
externalLambdatestTunnelId: program.externalLambdatestTunnelId,
|
|
1137
1136
|
externalLambdatestUseWss: program.externalLambdatestUseWss || false,
|
|
1138
1137
|
externalLambdatestDisableAutomationTunneling: Boolean(program.externalLambdatestDisableAutomationTunneling),
|
|
1138
|
+
externalLambdatestMitm: Boolean(program.externalLambdatestMitm),
|
|
1139
1139
|
|
|
1140
1140
|
// Hooks
|
|
1141
1141
|
beforeTest: program.beforeTest,
|
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');
|