@testim/testim-cli 3.232.0 → 3.235.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/cli.js +6 -0
- package/commons/httpRequest.js +4 -3
- package/commons/testimCloudflare.js +76 -0
- package/commons/testimServicesApi.js +34 -0
- package/commons/testimTunnel.js +18 -2
- package/npm-shrinkwrap.json +205 -172
- package/package.json +1 -2
- package/player/WebDriverHttpRequest.js +1 -1
- package/processHandler.js +9 -4
- package/runOptions.js +90 -70
- package/runner.js +1 -1
- package/runners/TestPlanRunner.js +7 -4
- package/services/gridService.js +1 -1
- package/services/lambdatestService.js +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.235.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",
|
|
@@ -154,7 +154,7 @@ class WebDriverHttpRequest {
|
|
|
154
154
|
httpDeleteRequest(path) {
|
|
155
155
|
const requestId = utils.guid();
|
|
156
156
|
logger.info("DELETE REQUEST", {requestId, path, testResultId: this.testResultId});
|
|
157
|
-
return httpRequest.deleteFullRes(`${this.gridUrl}${path}`, this.headers, this.connectionRetryTimeout)
|
|
157
|
+
return httpRequest.deleteFullRes(`${this.gridUrl}${path}`, undefined, this.headers, this.connectionRetryTimeout)
|
|
158
158
|
.tap((response) => logger.info("DELETE RESPONSE", {
|
|
159
159
|
requestId,
|
|
160
160
|
path,
|
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
|
@@ -295,7 +295,9 @@ program
|
|
|
295
295
|
.option('--require-credentials', 'Log in to Testim if not already logged in')
|
|
296
296
|
|
|
297
297
|
// Tunnel
|
|
298
|
+
.option('tunneld', 'run a tunnel daemon only')
|
|
298
299
|
.option('--tunnel [tunnel]', 'enable tunnel')
|
|
300
|
+
.option('--tunnel-routes [routes]', 'tunnel routes for cloudflare tunnels')
|
|
299
301
|
.option('--tunnel-port [tunnel-port]', 'tunnel port address')
|
|
300
302
|
.option('--tunnel-host-header [tunnel-host-header]', 'tunnel host header')
|
|
301
303
|
.option('--tunnel-region [tunnel-region]', 'ngrok tunnel region')
|
|
@@ -304,6 +306,7 @@ program
|
|
|
304
306
|
.option('--external-lambdatest-tunnel-id [tunnel-id]', 'use existing lambdatest tunnel ID')
|
|
305
307
|
.option('--external-lambdatest-use-wss', 'use wss instead of ssh for LT', false)
|
|
306
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)
|
|
307
310
|
|
|
308
311
|
.option('--w3c-capabilities [enable-w3c-caps-mode]', 'enable/disable w3c capabilities format (default enable)', JSON.parse, true)
|
|
309
312
|
.option('--old-capabilities [enable-old-caps-mode]', 'enable/disable old capabilities format (default enable)', JSON.parse, true)
|
|
@@ -492,7 +495,7 @@ module.exports = {
|
|
|
492
495
|
}
|
|
493
496
|
|
|
494
497
|
if (program.proxyForGrid && !program.proxy) {
|
|
495
|
-
|
|
498
|
+
throw new ArgError('missing --proxy option');
|
|
496
499
|
}
|
|
497
500
|
|
|
498
501
|
if (runOptionsAgentFlow.isAgentFlow(program)) {
|
|
@@ -522,6 +525,23 @@ module.exports = {
|
|
|
522
525
|
throw err;
|
|
523
526
|
}
|
|
524
527
|
|
|
528
|
+
if (program.tunneld) {
|
|
529
|
+
return {
|
|
530
|
+
tunnel: true,
|
|
531
|
+
tunnelPort: program.tunnelPort,
|
|
532
|
+
tunnelRoutes: program.tunnelRoutes,
|
|
533
|
+
tunnelRoutesOutput: program.tunnelRoutesOutput,
|
|
534
|
+
tunnelHostHeader: program.tunnelHostHeader,
|
|
535
|
+
tunnelRegion: program.tunnelRegion,
|
|
536
|
+
tunnelDiagnostics: program.tunnelDiagnostics,
|
|
537
|
+
tunnelUseHttpAddress: program.tunnelUseHttpAddress,
|
|
538
|
+
tunnelOnlyMode: true,
|
|
539
|
+
token: program.token,
|
|
540
|
+
project: program.project,
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
|
|
525
545
|
const isTestConfigSpecified = (program.testConfig && program.testConfig.length) || (program.testConfigId && program.testConfigId.length);
|
|
526
546
|
const isTestPlanSpecified = (program.testPlan && program.testPlan.length) || (program.testPlanId && program.testPlanId.length);
|
|
527
547
|
const isSuiteSpecified = (program.suite && program.suite.length) || (program.suiteId && program.suiteId.length);
|
|
@@ -534,20 +554,20 @@ module.exports = {
|
|
|
534
554
|
}
|
|
535
555
|
}
|
|
536
556
|
|
|
537
|
-
if (program.reporters && program.reporters.
|
|
557
|
+
if (program.reporters && program.reporters.includes('junit') && !program.reportFile) {
|
|
538
558
|
console.log('Warning: please define --report-file option for JUnit reporter');
|
|
539
559
|
}
|
|
540
560
|
|
|
541
561
|
if (!program.tunnel && program.externalLambdatestTunnelId) {
|
|
542
|
-
|
|
562
|
+
throw new ArgError('missing --tunnel parameter');
|
|
543
563
|
}
|
|
544
564
|
|
|
545
565
|
if (!program.tunnel && program.externalLambdatestUseWss) {
|
|
546
|
-
|
|
566
|
+
throw new ArgError('missing --tunnel parameter');
|
|
547
567
|
}
|
|
548
568
|
|
|
549
569
|
if (!program.tunnel && [program.tunnelPort, program.tunnelHostHeader, program.tunnelRegion, program.tunnelDiagnostics].some(Boolean)) {
|
|
550
|
-
|
|
570
|
+
throw new ArgError('missing --tunnel parameter');
|
|
551
571
|
}
|
|
552
572
|
if (program.chromeExtraPrefs) {
|
|
553
573
|
try {
|
|
@@ -590,7 +610,7 @@ module.exports = {
|
|
|
590
610
|
|
|
591
611
|
// SauceLabs Options
|
|
592
612
|
if ((program.sauceUser && !program.sauceKey) || (!program.sauceUser && program.sauceKey)) {
|
|
593
|
-
|
|
613
|
+
throw new ArgError('missing --sauce-user <sauce-user> or --sauce-key <sauce-key>');
|
|
594
614
|
}
|
|
595
615
|
|
|
596
616
|
if (program.sauceUser && program.sauceKey) {
|
|
@@ -636,7 +656,7 @@ module.exports = {
|
|
|
636
656
|
|
|
637
657
|
// BrowserStack options
|
|
638
658
|
if ((program.browserstackUser && !program.browserstackKey) || (!program.browserstackUser && program.browserstackKey)) {
|
|
639
|
-
|
|
659
|
+
throw new ArgError('missing --browserstack-user <browserstack-user> or --browserstack-key <browserstack-key>');
|
|
640
660
|
}
|
|
641
661
|
if (program.browserstackUser && program.browserstackKey) {
|
|
642
662
|
setHostAndPortForBrowserStack();
|
|
@@ -707,7 +727,7 @@ module.exports = {
|
|
|
707
727
|
if (projectId) {
|
|
708
728
|
program.project = projectId;
|
|
709
729
|
} else {
|
|
710
|
-
|
|
730
|
+
throw new ArgError('missing project-id info, either --login to provide new credentials or use --project <project-id>');
|
|
711
731
|
}
|
|
712
732
|
}
|
|
713
733
|
|
|
@@ -718,12 +738,12 @@ module.exports = {
|
|
|
718
738
|
|
|
719
739
|
if (program.testConfig) {
|
|
720
740
|
// convert single test config inputs to array (e.g. from configFile)
|
|
721
|
-
program.testConfig = [].
|
|
741
|
+
program.testConfig = [program.testConfig].flat();
|
|
722
742
|
}
|
|
723
743
|
|
|
724
744
|
if (program.testConfigId) {
|
|
725
745
|
// convert single test config inputs to array (e.g. from configFile)
|
|
726
|
-
program.testConfigId = [].
|
|
746
|
+
program.testConfigId = [program.testConfigId].flat();
|
|
727
747
|
}
|
|
728
748
|
|
|
729
749
|
program.retries = !program.retries || typeof program.retries === 'boolean' ? 1 : Number(program.retries) + 1;
|
|
@@ -745,21 +765,19 @@ module.exports = {
|
|
|
745
765
|
|
|
746
766
|
|
|
747
767
|
if (program.parallel > 1 && program.run && !program.gridId && !program.grid &&
|
|
748
|
-
((!program.testPlan || program.testPlan.length === 0) && (!program.testPlanId || !program.testPlanId.length))) {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
process.exit(0);
|
|
762
|
-
}
|
|
768
|
+
((!program.testPlan || program.testPlan.length === 0) && (!program.testPlanId || !program.testPlanId.length)) && process.stdout.isTTY && !program.headless && !process.env.TERM) {
|
|
769
|
+
const prompts = require('prompts');
|
|
770
|
+
const response = await prompts({
|
|
771
|
+
type: 'toggle',
|
|
772
|
+
name: 'isSure',
|
|
773
|
+
message: 'Running in parallel without --headless flag will open several browsers on your computer. Are you sure?',
|
|
774
|
+
initial: false,
|
|
775
|
+
active: 'yes',
|
|
776
|
+
inactive: 'no',
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
if (!response.isSure) {
|
|
780
|
+
process.exit(0);
|
|
763
781
|
}
|
|
764
782
|
}
|
|
765
783
|
|
|
@@ -768,11 +786,11 @@ module.exports = {
|
|
|
768
786
|
program.port = program.port && Number(program.port);
|
|
769
787
|
|
|
770
788
|
if (program.retries <= 0 || _.isNaN(program.retries)) {
|
|
771
|
-
|
|
789
|
+
throw new ArgError('test failure retry count could not be a negative number or string, --retries <max_num_of_retries>');
|
|
772
790
|
}
|
|
773
791
|
|
|
774
792
|
if (program.retries > 21) {
|
|
775
|
-
|
|
793
|
+
throw new ArgError('Max number of retries exceeded. Number cannot be greater than 20, --retries <max_num_of_retries>');
|
|
776
794
|
}
|
|
777
795
|
|
|
778
796
|
if (!program.token) {
|
|
@@ -782,33 +800,32 @@ module.exports = {
|
|
|
782
800
|
if (credentialToken) {
|
|
783
801
|
program.token = credentialToken;
|
|
784
802
|
} else {
|
|
785
|
-
|
|
786
|
-
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.'));
|
|
803
|
+
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.');
|
|
787
804
|
}
|
|
788
805
|
}
|
|
789
806
|
|
|
790
807
|
if (program.browserTimeout <= 0 || _.isNaN(program.browserTimeout)) {
|
|
791
|
-
|
|
808
|
+
throw new ArgError('get browser timeout could not be a negative number, --browser-timeout <get-browser-timeout>');
|
|
792
809
|
}
|
|
793
810
|
|
|
794
811
|
if (program.newBrowserWaitTimeout <= 0 || _.isNaN(program.newBrowserWaitTimeout)) {
|
|
795
|
-
|
|
812
|
+
throw new ArgError('max new browser wait timeout could not be a negative number, --new-browser-wait-timeout <max-wait-to-browser>');
|
|
796
813
|
}
|
|
797
814
|
|
|
798
815
|
if (program.timeout <= 0 || _.isNaN(program.timeout)) {
|
|
799
|
-
|
|
816
|
+
throw new ArgError('test run timeout could not be a negative number, --timeout <run-timeout>');
|
|
800
817
|
}
|
|
801
818
|
|
|
802
819
|
if (program.parallel <= 0 || _.isNaN(program.parallel)) {
|
|
803
|
-
|
|
820
|
+
throw new ArgError('parallel could not be a negative number or not number, --parallel <number-of-tests>');
|
|
804
821
|
}
|
|
805
822
|
|
|
806
|
-
if ([CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].
|
|
807
|
-
|
|
823
|
+
if (![CLI_MODE.EXTENSION, CLI_MODE.SELENIUM].includes(program.mode)) {
|
|
824
|
+
throw new ArgError(`runner mode <${program.mode}> is not supported`);
|
|
808
825
|
}
|
|
809
826
|
|
|
810
827
|
if ((program.mode !== CLI_MODE.SELENIUM) && program.disableNativeEvents) {
|
|
811
|
-
|
|
828
|
+
throw new ArgError('disable-native-events is only applicable in selenium mode');
|
|
812
829
|
}
|
|
813
830
|
|
|
814
831
|
if (
|
|
@@ -829,9 +846,9 @@ module.exports = {
|
|
|
829
846
|
!program.useChromeLauncher &&
|
|
830
847
|
!program.createPrefechedData
|
|
831
848
|
) {
|
|
832
|
-
|
|
849
|
+
throw new ArgError(
|
|
833
850
|
'missing remote grid address parameter, specify --host <host-name-or-ip> or --grid <grid-name> or --grid-id <grid-id>'
|
|
834
|
-
)
|
|
851
|
+
);
|
|
835
852
|
}
|
|
836
853
|
} else if (
|
|
837
854
|
program.testId.length ||
|
|
@@ -843,9 +860,9 @@ module.exports = {
|
|
|
843
860
|
program.useLocalChromeDriver ||
|
|
844
861
|
program.useChromeLauncher
|
|
845
862
|
) {
|
|
846
|
-
|
|
863
|
+
throw new ArgError(
|
|
847
864
|
'cannot set --testId, --label, --name, --browser, --test-config, --test-config-id, --use-local-chrome-driver --use-chrome-launcher or --suite with --test-plan option'
|
|
848
|
-
)
|
|
865
|
+
);
|
|
849
866
|
}
|
|
850
867
|
|
|
851
868
|
if (
|
|
@@ -856,17 +873,17 @@ module.exports = {
|
|
|
856
873
|
isSuiteSpecified) &&
|
|
857
874
|
program.file
|
|
858
875
|
) {
|
|
859
|
-
|
|
876
|
+
throw new ArgError(
|
|
860
877
|
'Cannot pass codeful automation tests with --testId --label --name or --suite'
|
|
861
|
-
)
|
|
878
|
+
);
|
|
862
879
|
}
|
|
863
880
|
|
|
864
881
|
const numberOfDefinedHosts = [program.host, program.grid, program.gridId].filter(Boolean).length;
|
|
865
882
|
if (numberOfDefinedHosts > 1) {
|
|
866
|
-
|
|
883
|
+
throw new ArgError('please define exactly one of --grid or --grid-id or --host');
|
|
867
884
|
}
|
|
868
885
|
|
|
869
|
-
if (program.host && program.host.
|
|
886
|
+
if (program.host && program.host.includes('/')) {
|
|
870
887
|
if (!/^(f|ht)tps?:\/\//i.test(program.host)) {
|
|
871
888
|
program.host = `http://${program.host}`;
|
|
872
889
|
}
|
|
@@ -877,7 +894,7 @@ module.exports = {
|
|
|
877
894
|
program.resultLabel = program.resultLabel.map(label => label.trim()).filter(Boolean);
|
|
878
895
|
const invalidLabels = program.resultLabel.filter(label => label.length >= 250).filter(Boolean);
|
|
879
896
|
if (invalidLabels.length) {
|
|
880
|
-
|
|
897
|
+
throw new ArgError('A result label cannot exceed 250 characters');
|
|
881
898
|
}
|
|
882
899
|
}
|
|
883
900
|
|
|
@@ -885,66 +902,66 @@ module.exports = {
|
|
|
885
902
|
const playerUrl = runOptionsUtils.getPlayerUrl(program);
|
|
886
903
|
|
|
887
904
|
if (!program.w3cCapabilities && !program.oldCapabilities) {
|
|
888
|
-
|
|
905
|
+
throw new ArgError('cannot set --w3c-capabilities and --old-capabilities options as false');
|
|
889
906
|
}
|
|
890
907
|
program.protocol = program.protocol || (program.port === 443 ? 'https' : 'http');
|
|
891
908
|
if (!['http', 'https'].includes(program.protocol)) {
|
|
892
|
-
|
|
909
|
+
throw new ArgError('invalid --protocol value, allow --protocol http or https');
|
|
893
910
|
}
|
|
894
911
|
|
|
895
912
|
if (program.rerunFailedByRunId && program.branch) {
|
|
896
|
-
|
|
913
|
+
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');
|
|
897
914
|
}
|
|
898
915
|
|
|
899
916
|
if (program.rerunFailedByRunId &&
|
|
900
917
|
(isSuiteSpecified || program.name.length ||
|
|
901
918
|
program.testId.length || program.label.length || isTestPlanSpecified)) {
|
|
902
|
-
|
|
903
|
-
' label (--label), plan (--test-plan), or other test flags (--test) are provided. Please remove these flags and try again')
|
|
919
|
+
throw new ArgError('Re-running failed tests is not possible when suite (--suite),' +
|
|
920
|
+
' label (--label), plan (--test-plan), or other test flags (--test) are provided. Please remove these flags and try again');
|
|
904
921
|
}
|
|
905
922
|
|
|
906
923
|
if (program.run.length) {
|
|
907
924
|
const glob = require('glob');
|
|
908
925
|
program.files = _.flatMap(program.run, files => glob.sync(files));
|
|
909
926
|
if (program.files.length === 0) {
|
|
910
|
-
|
|
927
|
+
throw new ArgError(`No files found at path '${program.run}'.`);
|
|
911
928
|
}
|
|
912
929
|
} else {
|
|
913
930
|
program.files = [];
|
|
914
931
|
}
|
|
915
932
|
|
|
916
933
|
if (program.setRetention && !_.inRange(_.parseInt(program.setRetention), 1, 11)) {
|
|
917
|
-
|
|
934
|
+
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)');
|
|
918
935
|
}
|
|
919
936
|
program.setRetention = program.setRetention && Number(program.setRetention);
|
|
920
937
|
|
|
921
938
|
const mockNetworkDeprecationMsg = 'is no longer supported, please use --override-mapping-file';
|
|
922
939
|
if (program.mockNetworkHar) {
|
|
923
|
-
|
|
940
|
+
throw new ArgError(`--mock-network-har ${mockNetworkDeprecationMsg}`);
|
|
924
941
|
}
|
|
925
942
|
if (program.mockNetworkPattern) {
|
|
926
|
-
|
|
943
|
+
throw new ArgError(`--mock-network-pattern ${mockNetworkDeprecationMsg}`);
|
|
927
944
|
}
|
|
928
945
|
|
|
929
946
|
if (program.disableMockNetwork && program.overrideMappingFile) {
|
|
930
|
-
|
|
947
|
+
throw new ArgError('You can either use --disable-mock-network or --override-mapping-file');
|
|
931
948
|
}
|
|
932
949
|
|
|
933
950
|
if (!program.collectCodeCoverage && program.codeCoverageSourceMapPath) {
|
|
934
|
-
|
|
951
|
+
throw new ArgError('cannot set --code-coverage-source-map-path without passing --collect-code-coverage');
|
|
935
952
|
}
|
|
936
953
|
|
|
937
954
|
if (!program.collectCodeCoverage && program.codeCoverageReporter.length) {
|
|
938
|
-
|
|
955
|
+
throw new ArgError('cannot set --code-coverage-reporter without passing --collect-code-coverage');
|
|
939
956
|
}
|
|
940
957
|
|
|
941
958
|
if (!program.collectCodeCoverage && program.codeCoverageInclude.length) {
|
|
942
|
-
|
|
959
|
+
throw new ArgError('cannot set --code-coverage-include without passing --collect-code-coverage');
|
|
943
960
|
}
|
|
944
961
|
|
|
945
962
|
if (program.collectCodeCoverage && program.codeCoverageReporter && _.difference(program.codeCoverageReporter, CODE_COVERAGE_REPORTER_OPTIONS).length) {
|
|
946
963
|
const diff = _.difference(program.codeCoverageReporter, CODE_COVERAGE_REPORTER_OPTIONS);
|
|
947
|
-
|
|
964
|
+
throw new ArgError(`invalid --code-coverage-reporter parameters ${diff.join('/')}`);
|
|
948
965
|
}
|
|
949
966
|
|
|
950
967
|
program.codeCoverageReporter = program.codeCoverageReporter.length === 0 ? ['html', 'text'] : program.codeCoverageReporter;
|
|
@@ -963,7 +980,7 @@ module.exports = {
|
|
|
963
980
|
|
|
964
981
|
if (program.mode !== CLI_MODE.EXTENSION && usedExtensionOptions.length) {
|
|
965
982
|
const multi = usedExtensionOptions.length > 1 ? 'are' : 'is';
|
|
966
|
-
|
|
983
|
+
throw new ArgError(`${usedExtensionOptions.map(key => extensionOnlyOptions[key]).join(' and ')} ${multi} only applicable in extension mode`);
|
|
967
984
|
}
|
|
968
985
|
|
|
969
986
|
if (program.tmsFieldFile) {
|
|
@@ -1035,18 +1052,18 @@ module.exports = {
|
|
|
1035
1052
|
}
|
|
1036
1053
|
|
|
1037
1054
|
if (typeof program.baseUrl === 'boolean') {
|
|
1038
|
-
|
|
1055
|
+
throw new ArgError('base url cannot be used as a flag, and must contain a string value');
|
|
1039
1056
|
}
|
|
1040
1057
|
|
|
1041
1058
|
return ({
|
|
1042
|
-
testId: [].
|
|
1043
|
-
name: [].
|
|
1044
|
-
label: [].
|
|
1045
|
-
suites: [].
|
|
1046
|
-
suiteIds: [].
|
|
1047
|
-
testPlan: [].
|
|
1048
|
-
testPlanIds: [].
|
|
1049
|
-
files: [].
|
|
1059
|
+
testId: [program.testId].flat(),
|
|
1060
|
+
name: [program.name].flat(),
|
|
1061
|
+
label: [program.label].flat(),
|
|
1062
|
+
suites: [program.suite].flat(),
|
|
1063
|
+
suiteIds: [program.suiteId].flat(),
|
|
1064
|
+
testPlan: [program.testPlan].flat(),
|
|
1065
|
+
testPlanIds: [program.testPlanId].flat(),
|
|
1066
|
+
files: [program.files].flat(),
|
|
1050
1067
|
webpackConfig: program.webpackConfig,
|
|
1051
1068
|
reportFile: program.reportFile,
|
|
1052
1069
|
reportFileClassname: program.overrideReportFileClassname,
|
|
@@ -1097,7 +1114,7 @@ module.exports = {
|
|
|
1097
1114
|
|
|
1098
1115
|
// Extension
|
|
1099
1116
|
ext: program.ext,
|
|
1100
|
-
extensionLocation: [
|
|
1117
|
+
extensionLocation: [program.extensionPath || extHeadlessUrl].flat(),
|
|
1101
1118
|
extensionPath: program.extensionPath,
|
|
1102
1119
|
|
|
1103
1120
|
// Player
|
|
@@ -1108,6 +1125,8 @@ module.exports = {
|
|
|
1108
1125
|
// Tunnel
|
|
1109
1126
|
tunnel: program.tunnel,
|
|
1110
1127
|
tunnelPort: program.tunnelPort,
|
|
1128
|
+
tunnelRoutes: program.tunnelRoutes,
|
|
1129
|
+
tunnelRoutesOutput: program.tunnelRoutesOutput,
|
|
1111
1130
|
tunnelHostHeader: program.tunnelHostHeader,
|
|
1112
1131
|
tunnelRegion: program.tunnelRegion,
|
|
1113
1132
|
tunnelDiagnostics: program.tunnelDiagnostics,
|
|
@@ -1115,6 +1134,7 @@ module.exports = {
|
|
|
1115
1134
|
externalLambdatestTunnelId: program.externalLambdatestTunnelId,
|
|
1116
1135
|
externalLambdatestUseWss: program.externalLambdatestUseWss || false,
|
|
1117
1136
|
externalLambdatestDisableAutomationTunneling: Boolean(program.externalLambdatestDisableAutomationTunneling),
|
|
1137
|
+
externalLambdatestMitm: Boolean(program.externalLambdatestMitm),
|
|
1118
1138
|
|
|
1119
1139
|
// Hooks
|
|
1120
1140
|
beforeTest: program.beforeTest,
|
package/runner.js
CHANGED
|
@@ -213,7 +213,7 @@ function runRunner(options, customExtensionLocalLocation) {
|
|
|
213
213
|
|
|
214
214
|
return validateCliAccount(options)
|
|
215
215
|
.log('in runRunner before tunnel.connect')
|
|
216
|
-
.then(() => tunnel.connect(options
|
|
216
|
+
.then(() => tunnel.connect(options))
|
|
217
217
|
.log('in runRunner after tunnel.connect')
|
|
218
218
|
.then(() => new TestPlanRunner(customExtensionLocalLocation).run(options))
|
|
219
219
|
.log('before tunnel.disconnect')
|
|
@@ -88,22 +88,25 @@ class TestPlanRunner {
|
|
|
88
88
|
await EyeSdkBuilder.closeBatch(executionId);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
|
+
/** @type {Awaited<ReturnType<typeof testimServicesApi['getApplitoolsIntegrationData']>>} */
|
|
92
|
+
let applitoolsIntegrationData;
|
|
91
93
|
try {
|
|
92
94
|
if (!tpOptions.company || !tpOptions.company.activePlan || !tpOptions.company.activePlan.premiumFeatures || !tpOptions.company.activePlan.premiumFeatures.applitools) {
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
|
-
|
|
96
|
-
if (_.isEmpty(applitoolsIntegrationData)) {
|
|
97
|
+
applitoolsIntegrationData = await testimServicesApi.getApplitoolsIntegrationData(tpOptions.project);
|
|
98
|
+
if (_.isEmpty(applitoolsIntegrationData) || !executionId) {
|
|
97
99
|
return;
|
|
98
100
|
}
|
|
99
101
|
const { runKey: apiKey, url: serverUrl } = applitoolsIntegrationData;
|
|
100
102
|
const tmpSDK = require('@applitools/eyes-sdk-core').makeSDK({ name: 'Testim.io', version: '4.0.0', spec: {} });
|
|
101
103
|
await tmpSDK.closeBatches({ batchIds: [executionId], serverUrl, apiKey });
|
|
102
104
|
} catch (err) {
|
|
103
|
-
|
|
105
|
+
// If a batch with this name did not exist, do not log an error.
|
|
106
|
+
if (err.message && (err.message.startsWith('Request failed with status code 404') || err.message.startsWith('no batchIds were set'))) {
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
|
-
logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project });
|
|
109
|
+
logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project, applitoolsIntegrationData, batchIds: [executionId] });
|
|
107
110
|
}
|
|
108
111
|
});
|
|
109
112
|
}
|
package/services/gridService.js
CHANGED
|
@@ -258,7 +258,7 @@ async function getGridData(options) {
|
|
|
258
258
|
if (grid) {
|
|
259
259
|
return getGridDataByGridName(companyId, grid, allGrids);
|
|
260
260
|
}
|
|
261
|
-
if (hasTestPlanFlag(options)) {
|
|
261
|
+
if (hasTestPlanFlag(options) || options.tunnelOnlyMode) {
|
|
262
262
|
logger.info('skipping getting grid, as it is set on test plan', { companyId });
|
|
263
263
|
return undefined;
|
|
264
264
|
}
|
|
@@ -136,6 +136,10 @@ class LambdatestService {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
if (runnerOptions.externalLambdatestMitm) {
|
|
140
|
+
tunnelArgs = [...tunnelArgs, '--mitm'];
|
|
141
|
+
}
|
|
142
|
+
|
|
139
143
|
LambdatestService.tunnel = spawn('./LT', tunnelArgs, { cwd: LT_TUNNEL_BINARY_DIRECTORY });
|
|
140
144
|
|
|
141
145
|
let stdoutResult = '';
|
|
@@ -207,6 +211,7 @@ class LambdatestService {
|
|
|
207
211
|
build: executionId,
|
|
208
212
|
name: `${testResultId} - ${testName}`,
|
|
209
213
|
platform: LambdatestService.lambdatestConfig.PLATFORM,
|
|
214
|
+
// eslint-disable-next-line camelcase
|
|
210
215
|
selenium_version: LambdatestService.lambdatestConfig.SELENIUM_VERSION,
|
|
211
216
|
resolution: LambdatestService.lambdatestConfig.RESOLUTION,
|
|
212
217
|
timezone: LambdatestService.lambdatestConfig.TIMEZONE,
|