@testim/testim-cli 3.231.0 → 3.234.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testim/testim-cli",
3
- "version": "3.231.0",
3
+ "version": "3.234.0",
4
4
  "description": "Command line interface for running Testing on your CI",
5
5
  "author": "Oren Rubin",
6
6
  "contributors": [{
@@ -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,
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement, expectedX, expectedY, shouldScrollLeft, shouldScrollTop) {
2
+ var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement, isDynamicScroll, expectedX, expectedY, shouldScrollLeft, shouldScrollTop) {
3
3
 
4
4
  function doScroll(expectedPosition, element) {
5
5
  if (!element) {
@@ -21,6 +21,11 @@ var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement,
21
21
  }
22
22
 
23
23
  var target = getLocatedElement(locatedElement);
24
+
25
+ if (isDynamicScroll && !target) {
26
+ return { x: parentElement.scrollWidth, y: parentElement.scrollHeight };
27
+ }
28
+
24
29
  if(!target) {
25
30
  throw new Error('could not find target element');
26
31
  }
@@ -63,8 +68,13 @@ var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement,
63
68
 
64
69
  var actualXString = result.actualX;
65
70
  var actualYString = result.actualY;
71
+ var actualScrollToElement = getLocatedElement(elementToScrollTo);
72
+
73
+ if (isScrollToElement && isDynamicScroll && !actualScrollToElement) {
74
+ return { success: false, expectedPosition };
75
+ }
76
+
66
77
  if (isScrollToElement) {
67
- var actualScrollToElement = getLocatedElement(elementToScrollTo);
68
78
  if (!actualScrollToElement) {
69
79
  throw new Error('could not find target to scroll to');
70
80
  }
@@ -38,7 +38,7 @@ class ScrollStepAction extends StepAction {
38
38
  return scroll.apply(null, arguments)
39
39
  `;
40
40
 
41
- return this.driver.executeJSWithArray(scrollCode, [elementToScrollOn, elementToScrollTo, !!step.isScrollToElement, expectedX, expectedY, step.shouldScrollLeft, step.shouldScrollTop])
41
+ return this.driver.executeJSWithArray(scrollCode, [elementToScrollOn, elementToScrollTo, Boolean(step.isScrollToElement), Boolean(step.isDynamicScroll), expectedX, expectedY, step.shouldScrollLeft, step.shouldScrollTop])
42
42
  .then((res) => {
43
43
  if(!res || !res.value) {
44
44
  return {
@@ -23,8 +23,6 @@ const ExtractTextStepAction = require('./extractTextStepAction');
23
23
  const TdkHybridStepAction = require('./tdkHybridStepAction');
24
24
  const PixelValidationStepAction = require('./pixelValidationStepAction');
25
25
 
26
- const SalesforceAutoLoginStepAction = require('./salesforceAutoLoginStepAction');
27
-
28
26
  const CliJsStepAction = require('./cliJsStepAction');
29
27
  const CliConditionStepAction = require('./cliConditionStepAction');
30
28
  const NodePackageStepAction = require('./nodePackageStepAction');
@@ -84,8 +82,6 @@ module.exports = function (driver, stepActionFactory, runMode) {
84
82
  'email-code-step': JsCodeStepAction,
85
83
  'cli-email-code-step': CliJsStepAction,
86
84
  'tdk-hybrid': TdkHybridStepAction,
87
-
88
- 'salesforce-autologin': SalesforceAutoLoginStepAction,
89
85
  };
90
86
 
91
87
  register(STEP_ACTION_MAPPING, stepActionFactory);
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
- process.on('uncaughtException', async (err) => {
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
- onExit(err);
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
- onExit(err);
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
- onExit(err);
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')
@@ -522,6 +524,23 @@ module.exports = {
522
524
  throw err;
523
525
  }
524
526
 
527
+ if (program.tunneld) {
528
+ return {
529
+ tunnel: true,
530
+ tunnelPort: program.tunnelPort,
531
+ tunnelRoutes: program.tunnelRoutes,
532
+ tunnelRoutesOutput: program.tunnelRoutesOutput,
533
+ tunnelHostHeader: program.tunnelHostHeader,
534
+ tunnelRegion: program.tunnelRegion,
535
+ tunnelDiagnostics: program.tunnelDiagnostics,
536
+ tunnelUseHttpAddress: program.tunnelUseHttpAddress,
537
+ tunnelOnlyMode: true,
538
+ token: program.token,
539
+ project: program.project,
540
+ };
541
+ }
542
+
543
+
525
544
  const isTestConfigSpecified = (program.testConfig && program.testConfig.length) || (program.testConfigId && program.testConfigId.length);
526
545
  const isTestPlanSpecified = (program.testPlan && program.testPlan.length) || (program.testPlanId && program.testPlanId.length);
527
546
  const isSuiteSpecified = (program.suite && program.suite.length) || (program.suiteId && program.suiteId.length);
@@ -1108,6 +1127,8 @@ module.exports = {
1108
1127
  // Tunnel
1109
1128
  tunnel: program.tunnel,
1110
1129
  tunnelPort: program.tunnelPort,
1130
+ tunnelRoutes: program.tunnelRoutes,
1131
+ tunnelRoutesOutput: program.tunnelRoutesOutput,
1111
1132
  tunnelHostHeader: program.tunnelHostHeader,
1112
1133
  tunnelRegion: program.tunnelRegion,
1113
1134
  tunnelDiagnostics: program.tunnelDiagnostics,
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, testimCustomToken.getTokenV3UserData()))
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')
@@ -79,7 +79,7 @@ class TestPlanRunner {
79
79
  throw err;
80
80
  })
81
81
  .finally(async () => {
82
- if ((tpOptions.lightweightMode && tpOptions.lightweightMode.disablePixelValidation) || !featureFlags.flags.applitoolsNewIntegration.isEnabled()) {
82
+ if ((tpOptions.lightweightMode && tpOptions.lightweightMode.disablePixelValidation)) {
83
83
  return;
84
84
  }
85
85
  // When sessionPlayer is available, use it - as it only attempts to close batches that exist.
@@ -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
- const applitoolsIntegrationData = await testimServicesApi.getApplitoolsIntegrationData(tpOptions.project);
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
- if (err.message && err.message.startsWith('Request failed with status code 404')) { // If a batch with this name did not exist, do not log an error.
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
  }
@@ -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
  }
@@ -13,6 +13,7 @@ const httpRequest = require('../commons/httpRequest');
13
13
  const { ArgError } = require('../errors');
14
14
  const servicesApi = require('../commons/testimServicesApi');
15
15
  const { getExtensionsUrl } = require('../runOptionsUtils');
16
+ const featureFlagService = require('../commons/featureFlags');
16
17
 
17
18
  const logger = require('../commons/logger').getLogger('lambdatestService');
18
19
 
@@ -215,7 +216,7 @@ class LambdatestService {
215
216
  console: true,
216
217
  queueTimeout: 300, // time a session spends in the LT queue, in seconds (apparently 300 is the minimum)
217
218
  // visual: true, // [NOTE]: activate LT screenshots feature (can slow test).
218
- // network: true, // [NOTE]: activate LT capture network logs feature (can cause network issues).
219
+ network: featureFlagService.flags.LTNetworkCapabilities.isEnabled(), // [NOTE]: activate LT capture network logs feature (can cause network issues).
219
220
  // fixedIP: '10.80.34.143', // [NOTE]: this is for debug purposes with LT team.
220
221
  };
221
222
  }
@@ -1,39 +0,0 @@
1
- const NavigationStepAction = require('./navigationStepAction');
2
- const Promise = require('bluebird');
3
-
4
- class SalesforceAutoLoginStepAction extends NavigationStepAction {
5
- async performAction() {
6
- let salesforceUrl = this.context.data.testimNavigationStepDestination || this.context.data.url;
7
- try {
8
- salesforceUrl = await this.updateBaseUrl(salesforceUrl);
9
- await this.driver.url(salesforceUrl);
10
- await Promise.delay(5000); // wait a little for the page to load (fixes screenshots and clicking on elements in username verification screen)
11
- let newUrl = await this.driver.getUrl();
12
- // Verify username screen
13
- const isUsernameVerificationNeeded = newUrl.includes(this.step.USERNAME_VERIFICATION_PATH_ID);
14
- const timeout = this.context.data.timeToPlayStep + 3000;
15
- if (isUsernameVerificationNeeded) {
16
- await this.driver.executeCodeAsync(`
17
- function ${this.step.handleUsernameVerificationAUTFunc.toString()}
18
- handleUsernameVerificationAUTFunc();
19
- var done = arguments[1];
20
- done();
21
- `, timeout);
22
- await Promise.delay(5000);
23
- newUrl = await this.driver.getUrl(); // If we managed to continue correctly we want to get the new redirected url
24
- }
25
- await Promise.delay(1500);
26
- return {
27
- success: true,
28
- newUrl,
29
- };
30
- } catch (err) {
31
- return {
32
- success: false,
33
- reason: err.message,
34
- };
35
- }
36
- }
37
- }
38
-
39
- module.exports = SalesforceAutoLoginStepAction;