@testim/testim-cli 3.200.0 → 3.204.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.200.0",
3
+ "version": "3.204.0",
4
4
  "description": "Command line interface for running Testing on your CI",
5
5
  "author": "Oren Rubin",
6
6
  "contributors": [{
@@ -36,7 +36,7 @@
36
36
  "typescript": "3.9.3"
37
37
  },
38
38
  "lazyDependencies": {
39
- "ngrok": "3.2.3",
39
+ "ngrok": "3.4.0",
40
40
  "webpack": "4.43.0",
41
41
  "playwright": "0.12.1",
42
42
  "puppeteer": "2.1.1",
@@ -60,8 +60,8 @@
60
60
  "bluebird": "3.7.2",
61
61
  "bluebird-retry": "0.11.0",
62
62
  "body-parser": "1.19.0",
63
- "bunyan": "1.8.15",
64
- "bunyan-prettystream": "0.1.3",
63
+ "winston": "3.3.3",
64
+ "winston-transport": "4.4.0",
65
65
  "chalk": "4.1.0",
66
66
  "chrome-launcher": "0.13.4",
67
67
  "combine-source-map": "0.8.0",
@@ -79,10 +79,10 @@
79
79
  "glob": "7.1.6",
80
80
  "istanbul-lib-report": "3.0.0",
81
81
  "istanbul-reports": "3.0.2",
82
- "jimp": "0.2.28",
82
+ "jimp": "0.16.1",
83
83
  "jsdom": "16.7.0",
84
84
  "jsonwebtoken": "8.5.1",
85
- "lodash": "4.17.20",
85
+ "lodash": "4.17.21",
86
86
  "memory-fs": "0.5.0",
87
87
  "memorystream": "0.3.1",
88
88
  "mkdirp": "1.0.4",
@@ -105,9 +105,9 @@
105
105
  "superagent-proxy": "3.0.0",
106
106
  "test-exclude": "6.0.0",
107
107
  "threads": "0.12.0",
108
- "ua-parser-js": "0.7.22",
108
+ "ua-parser-js": "0.7.28",
109
109
  "validate-npm-package-name": "3.0.0",
110
- "ws": "7.3.0",
110
+ "ws": "8.2.3",
111
111
  "xml2js": "0.4.23",
112
112
  "yaml": "1.10.0"
113
113
  },
@@ -7,21 +7,24 @@ const logger = require('../../commons/logger').getLogger('pixel-validation-step-
7
7
 
8
8
  class PixelValidationStepAction extends StepAction {
9
9
  async performAction() {
10
- const { shouldUseVisualGrid, applitoolsSdkConfig: config } = this.context;
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);
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,5 +1,10 @@
1
- // https://github.com/applitools/eyes.sdk.javascript1/blob/master/packages/eyes-webdriverio-4/src/spec-driver.ts
1
+ /**
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
+ */
2
6
 
7
+ const { EyeSdkBuilder } = require('../../commons/getSessionPlayerRequire');
3
8
  const { makeSDK } = require('@applitools/eyes-sdk-core');
4
9
  const { W3C_ELEMENT_ID } = require('../constants');
5
10
  const _ = require('lodash');
@@ -27,7 +32,8 @@ function getValueOrFallbackIfNullOrUndefined(value, fallback) {
27
32
  }
28
33
 
29
34
  /**
30
- * @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
31
37
  * @implements {SpecDriver}
32
38
  */
33
39
  class EyesSpec {
@@ -211,19 +217,20 @@ class EyesSpec {
211
217
 
212
218
  class EyeSdkService {
213
219
  constructor() {
214
- /**
215
- * @typedef {import('@applitools/types').Core} Core
216
- * @type {Core}
217
- */
220
+ /** @type {Core} */
218
221
  this.sdk = makeSDK({
219
222
  name: 'Testim.io',
220
223
  version: '4.0.0',
221
224
  spec: new EyesSpec(),
222
225
  VisualGridClient: require('@applitools/visual-grid-client'),
223
226
  });
227
+ /** @type {EyeSdkBuilder['handleApplitoolsSdkResult']} */
228
+ this.handleApplitoolsSdkResult = EyeSdkBuilder.handleApplitoolsSdkResult;
224
229
  }
225
- getManager(useVisualGrid, concurrency) {
226
- return this.sdk.makeManager({ type: useVisualGrid ? 'vg' : 'classic', concurrency });
230
+ async getManager(useVisualGrid, concurrency, batchId, applitoolsIntegrationData) {
231
+ const manager = await this.sdk.makeManager({ type: useVisualGrid ? 'vg' : 'classic', concurrency });
232
+ EyeSdkBuilder.rememberCreatedBatch(batchId, applitoolsIntegrationData);
233
+ return manager;
227
234
  }
228
235
  }
229
236
 
@@ -50,9 +50,6 @@ class JunitReporter {
50
50
  }
51
51
 
52
52
  function getPrintName(testResult) {
53
- if (!featureFlags.flags.testNameTestDataInJunitReport.isEnabled()) {
54
- return testResult.name;
55
- }
56
53
  const testData = testResult.testData || {};
57
54
  const testDataNumber = typeof testData.total === 'number' ? ` - ${testData.index} / ${testData.total} Data set` : '';
58
55
  return `${testResult.name}${testDataNumber}`;
package/runner.js CHANGED
@@ -286,16 +286,7 @@ async function init(options) {
286
286
  reporter.setOptions(options, branchToUse);
287
287
  }
288
288
 
289
- function run(options, customExtensionLocalLocation) {
290
- perf.log('in runner.js run');
291
-
292
- if (options.files.length > 0 && !featureFlags.flags.enableTDKRun.isEnabled()) {
293
- throw new ArgError('run command is not supported, please sign up to the Testim Development Kit beta - https://go.testim.io/testims-new-beta-testim-tdk-testim-development-kit-testautomation');
294
- }
295
- return runRunner(options, customExtensionLocalLocation);
296
- }
297
-
298
289
  module.exports = {
299
- run,
290
+ run: runRunner,
300
291
  init: Promise.method(init),
301
292
  };
@@ -46,14 +46,14 @@ class ParallelWorkerManager {
46
46
  return Array.from(new Array(count), createWorker);
47
47
  }
48
48
 
49
- async runTests(testList, testStatus, executionId, options, branchToUse, authData, workerCount, stopOnError) {
49
+ async runTests(testList, testStatus, executionId, executionName, options, branchToUse, authData, workerCount, stopOnError) {
50
50
  if (testList && testList.length === 0) {
51
51
  return undefined;
52
52
  }
53
53
 
54
54
  const runAndWaitToComplete = token => new Promise((resolve, reject) => {
55
55
  const projectId = options.project;
56
- const executionQueue = new ExecutionQueue(executionId, testList, options, branchToUse, testStatus);
56
+ const executionQueue = new ExecutionQueue(executionId, executionName, testList, options, branchToUse, testStatus);
57
57
 
58
58
  const combinedTestResults = {};
59
59
  const testCount = testList.length;
@@ -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');
@@ -29,30 +30,30 @@ class TestPlanRunner {
29
30
  this.workerManager = new ParallelWorkerManager(customExtensionLocalLocation);
30
31
  this.startTime = Date.now();
31
32
  }
32
- runTestAllPhases(beforeTests, tests, afterTests, branchToUse, tpOptions, executionId, testStatus) {
33
+ runTestAllPhases(beforeTests, tests, afterTests, branchToUse, tpOptions, executionId, executionName, testStatus) {
33
34
  const executionResults = {};
34
35
  const authData = testimCustomToken.getTokenV3UserData();
35
36
 
36
- const runBeforeTests = (beforeTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
37
+ const runBeforeTests = (beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData) => {
37
38
  const workerCount = 1;
38
39
  const stopOnError = true;
39
- return this.workerManager.runTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
40
+ return this.workerManager.runTests(beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
40
41
  .then(beforeTestsResults => Object.assign(executionResults, beforeTestsResults));
41
42
  };
42
43
 
43
- const runTestPlanTests = (tests, testStatus, executionId, tpOptions, branchToUse, authData) => {
44
+ const runTestPlanTests = (tests, testStatus, executionId, executionName, tpOptions, branchToUse, authData) => {
44
45
  const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
45
46
  const stopOnError = false;
46
47
  perf.log('right before this.workerManager.runTests');
47
- return this.workerManager.runTests(tests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
48
+ return this.workerManager.runTests(tests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
48
49
  .log('right after this.workerManager.runTests')
49
50
  .then(testsResults => Object.assign(executionResults, testsResults));
50
51
  };
51
52
 
52
- const runAfterTests = (afterTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
53
+ const runAfterTests = (afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData) => {
53
54
  const workerCount = 1;
54
55
  const stopOnError = false;
55
- return this.workerManager.runTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
56
+ return this.workerManager.runTests(afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
56
57
  .then(afterTestsResults => Object.assign(executionResults, afterTestsResults));
57
58
  };
58
59
 
@@ -63,11 +64,11 @@ class TestPlanRunner {
63
64
  const sessionType = utils.getSessionType(tpOptions);
64
65
  analyticsService.analyticsExecsStart({ authData, executionId, projectId: tpOptions.project, sessionType });
65
66
  perf.log('right before runBeforeTests');
66
- return runBeforeTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData)
67
+ return runBeforeTests(beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData)
67
68
  .log('right before runTestPlanTests')
68
- .then(() => runTestPlanTests(tests, testStatus, executionId, tpOptions, branchToUse, authData))
69
+ .then(() => runTestPlanTests(tests, testStatus, executionId, executionName, tpOptions, branchToUse, authData))
69
70
  .log('right after runTestPlanTests')
70
- .then(() => runAfterTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData))
71
+ .then(() => runAfterTests(afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData))
71
72
  .then(() => executionResults)
72
73
  .catch(err => {
73
74
  logger.error('error running test plan', { err });
@@ -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
 
@@ -167,7 +196,7 @@ class TestPlanRunner {
167
196
  }
168
197
 
169
198
  perf.log('before runTestAllPhases');
170
- const results = await this.runTestAllPhases(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, branch, tpOptions, executionId, testStatus);
199
+ const results = await this.runTestAllPhases(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, branch, tpOptions, executionId, testPlanName || 'All Tests', testStatus);
171
200
  const childResults = await Bluebird.resolve(childTestResults)
172
201
  .timeout(TDK_CHILD_RESULTS_TIMEOUT)
173
202
  .catch(async () => {
@@ -50,13 +50,12 @@ function getSerializableObject(grid) {
50
50
  (tunnel && grid.hybrid.external && grid.hybrid.external[grid.hybrid.tunnel] && grid.hybrid.external[grid.hybrid.tunnel].user) : user;
51
51
  const tunnelKey = type === gridTypes.HYBRID ?
52
52
  (tunnel && grid.hybrid.external && grid.hybrid.external[grid.hybrid.tunnel] && grid.hybrid.external[grid.hybrid.tunnel].key) : key;
53
- const arn = (grid && grid.external && grid.external.arn) || (tunnel && grid.hybrid.external && grid.hybrid.external[grid.hybrid.tunnel] && grid.hybrid.external[grid.hybrid.tunnel].arn);
54
53
  const name = grid && grid.name;
55
54
  const gridId = grid && (grid._id || grid.gridId);
56
55
  const provider = grid && grid.provider;
57
56
 
58
57
  return {
59
- host, port, path, protocol, accessToken, slotId, gridId, tunnel, user, key, type, name, arn, provider, tunnelUser, tunnelKey,
58
+ host, port, path, protocol, accessToken, slotId, gridId, tunnel, user, key, type, name, provider, tunnelUser, tunnelKey,
60
59
  };
61
60
  }
62
61
 
package/testRunHandler.js CHANGED
@@ -15,13 +15,13 @@ const utils = require('./utils');
15
15
  const config = require('./commons/config');
16
16
  const analytics = require('./commons/testimAnalytics');
17
17
  const { SeleniumPerfStats } = require('./commons/SeleniumPerfStats');
18
- const featureFlags = require('./commons/featureFlags');
19
18
  const { preloadTests } = require('./commons/preloadTests');
20
19
 
21
20
  const RETRIES_ON_TIMEOUT = 3;
22
21
 
23
- const TestRun = function (executionId, test, options, branchToUse, testRunStatus) {
22
+ const TestRun = function (executionId, executionName, test, options, branchToUse, testRunStatus) {
24
23
  this._executionId = executionId;
24
+ this._executionName = executionName;
25
25
  this._testStatus = test.testStatus;
26
26
  this._testId = test.testId;
27
27
  this._testName = test.name;
@@ -81,6 +81,10 @@ TestRun.prototype.getExecutionId = function () {
81
81
  return this._executionId;
82
82
  };
83
83
 
84
+ TestRun.prototype.getExecutionName = function () {
85
+ return this._executionName;
86
+ };
87
+
84
88
  TestRun.prototype.getNativeAppData = function () {
85
89
  if (this._nativeApp && !this._options.baseUrl) {
86
90
  return this._nativeApp;
@@ -122,6 +126,7 @@ TestRun.prototype.getRunRequestParams = async function () {
122
126
  refreshToken: testimCustomToken.getRefreshToken(),
123
127
  projectId: this._options.project,
124
128
  executionId: this._executionId,
129
+ executionName: this._executionName,
125
130
  testId: this._testId,
126
131
  resultId: this._testResultId,
127
132
  baseUrl: this._baseUrl,
@@ -232,6 +237,12 @@ TestRun.prototype.clearTestResult = function () {
232
237
  if (this._options.mockNetworkRules) {
233
238
  runData.mockNetworkRules = this._options.mockNetworkRules;
234
239
  }
240
+ const mustClearPreviousStepResults = !this.isAllowReportTestResultRetries() && (this._timeoutRetryCount > 1 || this._retryCount > 1);
241
+
242
+ if (this._options.lightweightMode && this._options.lightweightMode.disableResults &&
243
+ !mustClearPreviousStepResults) {
244
+ return Promise.resolve();
245
+ }
235
246
 
236
247
  this.clearTestResultFinished = testimServicesApi.uploadRunDataArtifact(this._options.project, this._testId, this._testResultId, runData)
237
248
  .catch(err => {
@@ -528,7 +539,7 @@ TestRun.prototype.isAllowReportTestResultRetries = function () {
528
539
  TestRun.prototype.onRetry = async function () {
529
540
  this._previousTestResultId = this._testResultId;
530
541
 
531
- if (!featureFlags.flags.countRetries.isEnabled() || !this.isAllowReportTestResultRetries()) {
542
+ if (!this.isAllowReportTestResultRetries()) {
532
543
  return;
533
544
  }
534
545
 
@@ -90,9 +90,7 @@ class BaseWorker {
90
90
  resultId: testRunHandler.getTestResultId(),
91
91
  seleniumSession: player.getSessionId(),
92
92
  });
93
- if (this.options.lightweightMode && this.options.lightweightMode.disableResults) {
94
- return undefined;
95
- }
93
+
96
94
  return await testRunHandler.clearTestResult();
97
95
  }
98
96
 
@@ -88,6 +88,9 @@ class WorkerSelenium extends BaseWorker {
88
88
 
89
89
  setupCliPerformanceMonitoring(sessionPlayer);
90
90
 
91
+ sessionPlayer.playbackManager.executionId = testRunHandler.getExecutionId();
92
+ sessionPlayer.playbackManager.executionName = testRunHandler.getExecutionName();
93
+
91
94
  sessionPlayer.setLightweightMode(this.options.lightweightMode);
92
95
  if (sessionPlayerInit.localAssetService) {
93
96
  sessionPlayerInit.localAssetService.initialize({ serverUrl: this.options.localRCASaver });
@@ -1,56 +0,0 @@
1
- 'use strict';
2
-
3
- // This is copied from coralogix-bunyan-stream pacakge and altered to expose waitForFlush
4
-
5
- const coralogixLogger = require('@testim/coralogix-logger');
6
-
7
- const sevMap = {
8
- 10: coralogixLogger.Severity.debug,
9
- 30: coralogixLogger.Severity.info,
10
- 40: coralogixLogger.Severity.warning,
11
- 50: coralogixLogger.Severity.error,
12
- 60: coralogixLogger.Severity.critical,
13
- 20: coralogixLogger.Severity.debug,
14
- };
15
- const CoralogixStream = (function () {
16
- function CoralogixStream(options) {
17
- if (!options) options = {};
18
- CoralogixStream.logger = this.logger = new coralogixLogger.CoralogixLogger(options.category);
19
- }
20
- CoralogixStream.waitForFlush = function () {
21
- return CoralogixStream.logger.waitForFlush();
22
- };
23
- CoralogixStream.prototype.write = function (rec) {
24
- const log = new coralogixLogger.Log();
25
- log.severity = sevMap[rec.level];
26
- log.category = rec.category;
27
- if (rec.className) log.className = rec.className;
28
- if (rec.methodName) log.methodName = rec.methodName;
29
- if (rec.threadId) log.threadId = rec.threadId;
30
- log.text = this.removeStaticFields(rec);
31
- this.logger.addLog(log);
32
- };
33
- CoralogixStream.prototype.removeStaticFields = function (json) {
34
- delete json.threadId;
35
- delete json.methodName;
36
- delete json.className;
37
- delete json.category;
38
- return JSON.stringify(json, this.replaceErrors);
39
- };
40
- CoralogixStream.prototype.replaceErrors = function (key, value) {
41
- if (value instanceof Error) {
42
- const error = {};
43
- Object.getOwnPropertyNames(value).forEach((key) => {
44
- error[key] = value[key];
45
- });
46
- return error;
47
- }
48
- return value;
49
- };
50
- CoralogixStream.configure = function (config) {
51
- coralogixLogger.CoralogixLogger.configure(config);
52
- };
53
- return CoralogixStream;
54
- }());
55
-
56
- module.exports = { CoralogixStream };