@testim/testim-cli 3.202.0 → 3.206.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.
@@ -54,6 +54,8 @@ class FeatureFlagsService {
54
54
  useSameBrowserForMultiTests: new LabFeatureFlag('labs'),
55
55
  highSpeedMode: new LabFeatureFlag(),
56
56
  usePortedHtml5DragDrop: new Rox.Flag(),
57
+ applitoolsNewIntegration: new Rox.Flag(),
58
+ testNamesToBeforeSuiteHook: new Rox.Flag(),
57
59
  };
58
60
  Rox.register('default', this.flags);
59
61
  }
@@ -1,10 +1,30 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  const perf = require('./performance-logger');
4
4
 
5
5
  perf.log('getSessionPlayerRequire start');
6
6
  const getSessionPlayerFolder = require('./prepareRunnerAndTestimStartUtils').getSessionPlayerFolder;
7
+
7
8
  const testimAppDataFolder = getSessionPlayerFolder();
8
- const sessionPlayer = require(require('path').join(testimAppDataFolder, "sessionPlayer.js"));
9
+ /**
10
+ * @type {{
11
+ sessionPlayer: typeof import('../../../clickim/src/background/session/sessionPlayer').SessionPlayer;
12
+ utils: typeof import('../../../clickim/src/lib/utils').utils;
13
+ commonConstants: typeof import('../../../clickim/src/common/commonConstantsStrong');
14
+ locatorBuilderUtils: import('../../../clickim/src/locators/locatorBuilderUtils')['locatorBuilderUtils'];
15
+ assetService: import('../../../clickim/src/background/assetService')['assetService'];
16
+ localAssetService: import('../../../clickim/src/background/localAssetService');
17
+ urlUtils: import('../../../clickim/src/background/portMatch/urlUtils');
18
+ positionUtils: import('../../../clickim/src/lib/positionUtils');
19
+ visibilityUtils: import('../../../clickim/src/background/visibilityUtils');
20
+ apiCall: import('../../../clickim/src/common/playback/apiCall')['apiCall'];
21
+ stepParamBuilder: typeof import('../../../clickim/src/common/stepParamsBuilder').StepParamsBuilder;
22
+ stepParamExpressionEvaluator: import('../../../clickim/src/common/stepParamExpressionEvaluator');
23
+ manifestVersion: string | undefined;
24
+ EyeSdkBuilder: typeof import('../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder
25
+ }}
26
+ */
27
+ const sessionPlayer = require(require('path').join(testimAppDataFolder, 'sessionPlayer.js')); // eslint-disable-line import/no-dynamic-require
28
+
9
29
  module.exports = sessionPlayer;
10
30
  perf.log('getSessionPlayerRequire end');
@@ -428,6 +428,19 @@ function addTestRetry({
428
428
  }), DEFAULT_REQUEST_RETRY);
429
429
  }
430
430
 
431
+ /**
432
+ * @param {string} projectId
433
+ * @returns {Promise<import('../../../clickim/src/common/api/testimApplitoolsApi').ApplitoolsIntegrationData>}
434
+ */
435
+ function getApplitoolsIntegrationData(projectId) {
436
+ try {
437
+ return getWithAuth(`/integration/applitools/v3/connected?projectId=${projectId}`);
438
+ } catch (err) {
439
+ logger.warn('could\'nt get applitools integration data.', { err });
440
+ return {};
441
+ }
442
+ }
443
+
431
444
  module.exports = {
432
445
  getS3Artifact,
433
446
  getTestPlan,
@@ -459,4 +472,5 @@ module.exports = {
459
472
  getHybridGridProvider,
460
473
  loadTest,
461
474
  isTestResultCompleted,
475
+ getApplitoolsIntegrationData,
462
476
  };
@@ -15,8 +15,9 @@ const severityMap = {
15
15
  debug: Severity.debug,
16
16
  };
17
17
 
18
+ const errorProps = ['err', 'error', 'reason', 'e'];
19
+
18
20
  class CoralogixTransport extends TransportStream {
19
- static options;
20
21
  constructor(options) {
21
22
  options = Object.assign({}, CoralogixTransport.options, options);
22
23
  super(options);
@@ -59,26 +60,18 @@ class CoralogixTransport extends TransportStream {
59
60
  meta.msg = `${msg}\n${meta.msg}`;
60
61
  }
61
62
  }
62
- if (infoMeta.err instanceof Error) {
63
- meta.err = {
64
- message: infoMeta.err.message,
65
- stack: infoMeta.err.stack,
66
- name: infoMeta.err.name,
67
- type: infoMeta.err.type,
68
- cause: infoMeta.err.cause,
69
- ...infoMeta.err,
70
- };
71
- }
72
63
 
73
- if (infoMeta.reason instanceof Error) {
74
- meta.reason = {
75
- message: infoMeta.reason.message,
76
- stack: infoMeta.reason.stack,
77
- name: infoMeta.reason.name,
78
- type: infoMeta.reason.type,
79
- cause: infoMeta.reason.cause,
80
- ...infoMeta.reason,
81
- };
64
+ for (const prop of errorProps) {
65
+ if (infoMeta[prop] instanceof Error) {
66
+ meta[prop] = {
67
+ message: infoMeta[prop].message,
68
+ stack: infoMeta[prop].stack,
69
+ name: infoMeta[prop].name,
70
+ type: infoMeta[prop].type,
71
+ cause: infoMeta[prop].cause,
72
+ ...infoMeta[prop],
73
+ };
74
+ }
82
75
  }
83
76
 
84
77
  // still have keys after deleting the above
@@ -2552,9 +2552,9 @@
2552
2552
  },
2553
2553
  "dependencies": {
2554
2554
  "@types/node": {
2555
- "version": "16.11.10",
2556
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz",
2557
- "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA=="
2555
+ "version": "16.11.11",
2556
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz",
2557
+ "integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw=="
2558
2558
  },
2559
2559
  "mkdirp": {
2560
2560
  "version": "0.5.5",
@@ -2758,9 +2758,9 @@
2758
2758
  "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
2759
2759
  },
2760
2760
  "color-string": {
2761
- "version": "1.6.0",
2762
- "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz",
2763
- "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==",
2761
+ "version": "1.8.2",
2762
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.8.2.tgz",
2763
+ "integrity": "sha512-w5ZkKRdLsc5NOYsmnpS2DpyRW71npwZGwbRpLrJTuqjfTs2Bhrba7UiV59IX9siBlCPl2pne5NtiwnVWUzvYFA==",
2764
2764
  "requires": {
2765
2765
  "color-name": "^1.0.0",
2766
2766
  "simple-swizzle": "^0.2.2"
@@ -3554,9 +3554,9 @@
3554
3554
  "integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ=="
3555
3555
  },
3556
3556
  "electron-to-chromium": {
3557
- "version": "1.4.1",
3558
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.1.tgz",
3559
- "integrity": "sha512-9ldvb6QMHiDpUNF1iSwBTiTT0qXEN+xIO5WlCJrC5gt0z74ofOiqR698vaJqYWnri0XZiF0YmnrFmGq/EmpGAA==",
3557
+ "version": "1.4.7",
3558
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.7.tgz",
3559
+ "integrity": "sha512-UPy2MsQw1OdcbxR7fvwWZH/rXcv+V26+uvQVHx0fGa1kqRfydtfOw+NMGAvZJ63hyaH4aEBxbhSEtqbpliSNWA==",
3560
3560
  "dev": true
3561
3561
  },
3562
3562
  "emoji-regex": {
@@ -6116,9 +6116,9 @@
6116
6116
  "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
6117
6117
  },
6118
6118
  "json-schema": {
6119
- "version": "0.2.3",
6120
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
6121
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
6119
+ "version": "0.4.0",
6120
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
6121
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
6122
6122
  },
6123
6123
  "json-schema-traverse": {
6124
6124
  "version": "0.4.1",
@@ -6178,13 +6178,13 @@
6178
6178
  }
6179
6179
  },
6180
6180
  "jsprim": {
6181
- "version": "1.4.1",
6182
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
6183
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
6181
+ "version": "1.4.2",
6182
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
6183
+ "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
6184
6184
  "requires": {
6185
6185
  "assert-plus": "1.0.0",
6186
6186
  "extsprintf": "1.3.0",
6187
- "json-schema": "0.2.3",
6187
+ "json-schema": "0.4.0",
6188
6188
  "verror": "1.10.0"
6189
6189
  }
6190
6190
  },
@@ -12949,9 +12949,9 @@
12949
12949
  },
12950
12950
  "dependencies": {
12951
12951
  "debug": {
12952
- "version": "4.3.2",
12953
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
12954
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
12952
+ "version": "4.3.3",
12953
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
12954
+ "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
12955
12955
  "requires": {
12956
12956
  "ms": "2.1.2"
12957
12957
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testim/testim-cli",
3
- "version": "3.202.0",
3
+ "version": "3.206.0",
4
4
  "description": "Command line interface for running Testing on your CI",
5
5
  "author": "Oren Rubin",
6
6
  "contributors": [{
@@ -9,19 +9,22 @@ class PixelValidationStepAction extends StepAction {
9
9
  async performAction() {
10
10
  const { shouldUseVisualGrid, applitoolsSdkConfig: config, testResultId } = this.context;
11
11
  this.runContext = this.context.getRunContext(undefined);
12
- const eyeManager = await eyeSdkService.getManager(shouldUseVisualGrid, this.context.config.applitoolsConcurrency || 5, testResultId);
12
+ const batchId = (config.batch && config.batch.id) || testResultId;
13
+ const eyeManager = await eyeSdkService.getManager(shouldUseVisualGrid, this.context.config.applitoolsConcurrency || 5, batchId, this.runContext.applitoolsIntegrationData);
13
14
  const targetElementData = this.getTarget() || {};
15
+ let result;
14
16
  try {
15
17
  const openedEye = await eyeManager.openEyes({ driver: this.driver.client, config });
16
18
  const region = (this.step.action === 'element' && targetElementData.seleniumElement) || undefined;
17
19
  await openedEye.check({ settings: { region, fully: this.step.action === 'stitched' } });
18
20
  const eyesResults = await openedEye.close();
19
21
 
20
- return { isApplitoolsSdkResult: true, success: true, eyesResults };
22
+ result = { isApplitoolsSdkResult: true, success: true, eyesResults };
21
23
  } catch (err) {
22
24
  logger.error('Applitools SDK step failed', { err, info: err.info });
23
- return { isApplitoolsSdkResult: true, success: false, err };
25
+ result = { isApplitoolsSdkResult: true, success: false, err };
24
26
  }
27
+ return await eyeSdkService.handleApplitoolsSdkResult(this.context, result);
25
28
  }
26
29
  }
27
30
 
@@ -1,9 +1,10 @@
1
- // https://github.com/applitools/eyes.sdk.javascript1/blob/master/packages/eyes-webdriverio-4/src/spec-driver.ts
2
-
3
1
  /**
4
- * @type {{ EyeSdkBuilder: typeof import('../../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder }}
2
+ * @typedef {typeof import('../../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder} EyeSdkBuilder
3
+ * @typedef {import('@applitools/types').SpecDriver} SpecDriver
4
+ * @typedef {import('@applitools/types').Core} Core
5
5
  */
6
- const sessionPlayer = require('../../commons/getSessionPlayerRequire');
6
+
7
+ const { EyeSdkBuilder } = require('../../commons/getSessionPlayerRequire');
7
8
  const { makeSDK } = require('@applitools/eyes-sdk-core');
8
9
  const { W3C_ELEMENT_ID } = require('../constants');
9
10
  const _ = require('lodash');
@@ -31,7 +32,8 @@ function getValueOrFallbackIfNullOrUndefined(value, fallback) {
31
32
  }
32
33
 
33
34
  /**
34
- * @typedef {import('@applitools/types').SpecDriver} SpecDriver
35
+ * Applitools Spec Driver for webdriverIO 4.
36
+ * @see https://github.com/applitools/eyes.sdk.javascript1/blob/master/packages/eyes-webdriverio-4/src/spec-driver.ts
35
37
  * @implements {SpecDriver}
36
38
  */
37
39
  class EyesSpec {
@@ -215,20 +217,19 @@ class EyesSpec {
215
217
 
216
218
  class EyeSdkService {
217
219
  constructor() {
218
- /**
219
- * @typedef {import('@applitools/types').Core} Core
220
- * @type {Core}
221
- */
220
+ /** @type {Core} */
222
221
  this.sdk = makeSDK({
223
222
  name: 'Testim.io',
224
223
  version: '4.0.0',
225
224
  spec: new EyesSpec(),
226
225
  VisualGridClient: require('@applitools/visual-grid-client'),
227
226
  });
227
+ /** @type {EyeSdkBuilder['handleApplitoolsSdkResult']} */
228
+ this.handleApplitoolsSdkResult = EyeSdkBuilder.handleApplitoolsSdkResult;
228
229
  }
229
- async getManager(useVisualGrid, concurrency, batchId) {
230
+ async getManager(useVisualGrid, concurrency, batchId, applitoolsIntegrationData) {
230
231
  const manager = await this.sdk.makeManager({ type: useVisualGrid ? 'vg' : 'classic', concurrency });
231
- sessionPlayer.EyeSdkBuilder.rememberCreatedBatch(batchId);
232
+ EyeSdkBuilder.rememberCreatedBatch(batchId, applitoolsIntegrationData);
232
233
  return manager;
233
234
  }
234
235
  }
@@ -19,6 +19,7 @@ const { getSuite, calcTestResultStatus, validateConfig } = require('./runnerUtil
19
19
  const { StopRunOnError, ArgError } = require('../errors');
20
20
  const Logger = require('../commons/logger');
21
21
  const perf = require('../commons/performance-logger');
22
+ const featureFlags = require('../commons/featureFlags');
22
23
 
23
24
  const guid = utils.guid;
24
25
  const logger = Logger.getLogger('test-plan-runner');
@@ -75,6 +76,34 @@ class TestPlanRunner {
75
76
  return catchBeforeTestsFailed(executionId);
76
77
  }
77
78
  throw err;
79
+ })
80
+ .finally(async () => {
81
+ if ((tpOptions.lightweightMode && tpOptions.lightweightMode.disablePixelValidation) || !featureFlags.flags.applitoolsNewIntegration.isEnabled()) {
82
+ return;
83
+ }
84
+ // When sessionPlayer is available, use it - as it only attempts to close batches that exist.
85
+ if (tpOptions.mode === constants.CLI_MODE.SELENIUM) {
86
+ const { EyeSdkBuilder } = require('../commons/getSessionPlayerRequire');
87
+ await EyeSdkBuilder.closeBatch(executionId);
88
+ return;
89
+ }
90
+ try {
91
+ if (!tpOptions.company || !tpOptions.company.activePlan || !tpOptions.company.activePlan.premiumFeatures || !tpOptions.company.activePlan.premiumFeatures.applitools) {
92
+ return;
93
+ }
94
+ const applitoolsIntegrationData = await testimServicesApi.getApplitoolsIntegrationData(tpOptions.project);
95
+ if (_.isEmpty(applitoolsIntegrationData)) {
96
+ return;
97
+ }
98
+ const { runKey: apiKey, url: serverUrl } = applitoolsIntegrationData;
99
+ const tmpSDK = require('@applitools/eyes-sdk-core').makeSDK({ name: 'Testim.io', version: '4.0.0', spec: {} });
100
+ await tmpSDK.closeBatches({ batchIds: [executionId], serverUrl, apiKey });
101
+ } catch (err) {
102
+ 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.
103
+ return;
104
+ }
105
+ logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project });
106
+ }
78
107
  });
79
108
  }
80
109
 
@@ -149,10 +178,11 @@ class TestPlanRunner {
149
178
  const configName = configs && configs.length === 1 ? configs[0] : null;
150
179
 
151
180
  const isCodeMode = tpOptions.files.length > 0;
181
+ const testNames = tpOptions.lightweightMode && tpOptions.lightweightMode.onlyTestIdsNoSuite ? [] : _.concat(beforeTests, tests, afterTests).map(test => test.name);
152
182
 
153
183
  const testListInfoPromise = tpOptions.lightweightMode && tpOptions.lightweightMode.onlyTestIdsNoSuite ?
154
184
  { beforeTests, tests, afterTests } :
155
- testStatus.executionStart(executionId, projectId, this.startTime, testPlanName);
185
+ testStatus.executionStart(executionId, projectId, this.startTime, testPlanName, testNames);
156
186
  let childTestResults;
157
187
  if (isCodeMode) {
158
188
  childTestResults = Bluebird.try(async () => {
package/testRunStatus.js CHANGED
@@ -15,6 +15,7 @@ const _ = require('lodash');
15
15
  const { registerExitHook } = require('./processHandler');
16
16
  const { calculateCoverage } = require('./coverage/jsCoverage');
17
17
  const featureAvailabilityService = require('./commons/featureAvailabilityService');
18
+ const featureFlags = require('./commons/featureFlags');
18
19
  const { mapFilesToLocalDrive } = require('./services/localRCASaver');
19
20
 
20
21
  const gitBranch = utils.getEnvironmentGitBranch();
@@ -333,7 +334,7 @@ RunStatus.prototype.calcTestRunStatus = function () {
333
334
  }, {});
334
335
  };
335
336
 
336
- RunStatus.prototype.executionStart = function (executionId, projectId, startTime, testPlanName) {
337
+ RunStatus.prototype.executionStart = function (executionId, projectId, startTime, testPlanName, testNames) {
337
338
  logger.info('execution started', { executionId });
338
339
  const { options } = this;
339
340
  const { remoteRunId, projectData } = options;
@@ -352,8 +353,11 @@ RunStatus.prototype.executionStart = function (executionId, projectId, startTime
352
353
  ]));
353
354
 
354
355
  this.startTime = startTime || Date.now();
355
-
356
- return runHook(options.beforeSuite, { projectId, executionId })
356
+ const runHooksProps = { projectId, executionId };
357
+ if (featureFlags.flags.testNamesToBeforeSuiteHook.isEnabled()) {
358
+ runHooksProps.testNames = testNames;
359
+ }
360
+ return runHook(options.beforeSuite, runHooksProps)
357
361
  .then(params => {
358
362
  const overrideTestDataBuilder = new OverrideTestDataBuilder(params, _.cloneDeep(this.testInfoList), projectId);
359
363
  this.testInfoList = overrideTestDataBuilder.overrideTestData();