@testim/testim-cli 3.261.0 → 3.262.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.
Files changed (32) hide show
  1. package/commons/testimServicesApi.js +10 -7
  2. package/executionQueue.js +9 -1
  3. package/npm-shrinkwrap.json +2 -2
  4. package/package.json +1 -1
  5. package/player/stepActions/RefreshStepAction.js +7 -4
  6. package/player/stepActions/baseJsStepAction.js +45 -46
  7. package/player/stepActions/dropFileStepAction.js +11 -12
  8. package/player/stepActions/evaluateExpressionStepAction.js +32 -33
  9. package/player/stepActions/extensionOnlyStepAction.js +3 -4
  10. package/player/stepActions/extractTextStepAction.js +8 -10
  11. package/player/stepActions/hoverStepAction.js +3 -3
  12. package/player/stepActions/locateStepAction.js +39 -34
  13. package/player/stepActions/mouseStepAction.js +36 -34
  14. package/player/stepActions/navigationStepAction.js +7 -8
  15. package/player/stepActions/scrollStepAction.js +22 -22
  16. package/player/stepActions/stepAction.js +21 -21
  17. package/player/stepActions/stepActionRegistrar.js +63 -58
  18. package/player/stepActions/submitStepAction.js +2 -3
  19. package/player/stepActions/textStepAction.js +14 -14
  20. package/player/stepActions/textValidationStepAction.js +50 -38
  21. package/player/stepActions/wheelStepAction.js +5 -11
  22. package/processHandler.js +2 -0
  23. package/reports/junitReporter.js +18 -1
  24. package/runOptions.d.ts +4 -0
  25. package/runOptions.js +8 -1
  26. package/runners/TestPlanRunner.js +20 -19
  27. package/runners/runnerUtils.js +1 -2
  28. package/testRunHandler.js +18 -9
  29. package/testRunStatus.js +205 -157
  30. package/workers/BaseWorker.js +11 -0
  31. package/workers/WorkerExtension.js +117 -91
  32. package/workers/WorkerSelenium.js +8 -3
@@ -1,17 +1,19 @@
1
1
  'use strict';
2
2
 
3
- const Promise = require('bluebird');
4
-
5
- const { timeoutMessages, stepResult } = require('../commons/constants');
6
3
  const BaseWorker = require('./BaseWorker');
7
- const logger = require('../commons/logger').getLogger('worker-ext');
4
+ const reporter = require('../reports/reporter');
8
5
  const perf = require('../commons/performance-logger');
9
6
  const ExtensionTestPlayer = require('../player/extensionTestPlayer');
10
7
  const ChromeLauncherTestPlayer = require('../player/chromeLauncherTestPlayer');
11
- const reporter = require('../reports/reporter');
8
+ const { TimeoutError } = require('../errors');
9
+ const { promiseTimeout } = require('../utils');
10
+ const { getLogger } = require('../commons/logger');
11
+ const { timeoutMessages, stepResult } = require('../commons/constants');
12
12
 
13
+ const logger = getLogger('worker-ext');
13
14
 
14
15
  class WorkerExtension extends BaseWorker {
16
+ /** @override */
15
17
  initPlayer() {
16
18
  if (this.options.useChromeLauncher) {
17
19
  return new ChromeLauncherTestPlayer(this.id);
@@ -31,7 +33,7 @@ class WorkerExtension extends BaseWorker {
31
33
  this.executionId,
32
34
  this.testResultId,
33
35
  testRunHandler.seleniumPerfStats,
34
- this.options.lightweightMode && this.options.lightweightMode.general,
36
+ this.options.lightweightMode?.general,
35
37
  this.lambdatestService
36
38
  );
37
39
  } catch (err) {
@@ -45,115 +47,139 @@ class WorkerExtension extends BaseWorker {
45
47
  }
46
48
  }
47
49
 
50
+ /** @override */
48
51
  async getBrowserOnce(testRunHandler, customExtensionLocalLocation, player, gridInfo) {
49
52
  reporter.onGetSession(this.id, this.testName, testRunHandler.getRunMode());
50
53
  return this._getBrowserOnce(testRunHandler, customExtensionLocalLocation, player, gridInfo);
51
54
  }
52
55
 
53
- runTestOnce(testRunHandler, player) {
56
+ /**
57
+ * @override
58
+ * @param {import('../testRunHandler')} testRunHandler
59
+ * @param {import('../player/extensionTestPlayer') | import('../player/chromeLauncherTestPlayer')} player
60
+ */
61
+ async runTestOnce(testRunHandler, player) {
54
62
  const { driver } = player;
55
63
  const { testResultId, executionId, testId } = this;
56
64
  perf.log('WorkerExtension runTestOnce');
57
65
 
58
- const runExtTest = (testRunHandler) => {
66
+ const runViaCdpOrFallbackToAPI = async () => {
67
+ const testTimeout = this.options.timeoutWasGiven ? Math.max(10000, this.options.timeout) : this.options.testStartTimeout;
68
+ try {
69
+ return await promiseTimeout(testRunHandler.runTestUsingCDP(driver.cdpTestRunner), testTimeout, timeoutMessages.TEST_START_TIMEOUT_MSG);
70
+ } catch (err) {
71
+ if (!(err instanceof TimeoutError)) {
72
+ throw err;
73
+ }
74
+ logger.warn('timeout while running test using CDP. Running checkViaRestAPIIfTestStarted', { testResultId });
75
+ return await testRunHandler.checkViaRestAPIIfTestStarted();
76
+ }
77
+ };
78
+ const navigateChromeSessionToRunTestim = async (url, startStatusDetails) => {
79
+ try {
80
+ const res = await driver.url(url);
81
+ startStatusDetails.driverUrlFinished = true;
82
+ return res;
83
+ } catch (err) {
84
+ logger.error('error from driver.url', { err, testResultId, executionId, testId, url, urlLength: url.length });
85
+ throw err;
86
+ }
87
+ };
88
+ const updateRunHandlerThatTestStartedAndChangeStatusDetails = async (startStatusDetails) => {
89
+ const res = await testRunHandler.onStarted(this.options.testStartTimeout);
90
+ startStatusDetails.testRunHandlerOnStartedHadFinished = true;
91
+ return res;
92
+ };
93
+
94
+ const runExtTest = async () => {
59
95
  perf.log('WorkerExtension runExtTest');
60
- const disableRemoteStep = (this.options.lightweightMode && this.options.lightweightMode.disableRemoteStep) || this.options.disableSockets;
96
+ const disableRemoteStep = this.options.lightweightMode?.disableRemoteStep || this.options.disableSockets;
61
97
  if (!disableRemoteStep) {
62
98
  testRunHandler.listenToRemoteStep(driver);
63
99
  }
64
100
  if (this.options.useChromeLauncher) {
65
- const testTimeout = this.options.timeoutWasGiven ?
66
- Math.max(10000, this.options.timeout) :
67
- this.options.testStartTimeout;
68
-
69
101
  reporter.onWaitToTestStart(this.id);
70
102
  reporter.onWaitToTestComplete(this.id, this.isCodeMode);
71
- return Promise.resolve(testRunHandler.runTestUsingCDP(driver.cdpTestRunner))
72
- .timeout(testTimeout, timeoutMessages.TEST_START_TIMEOUT_MSG)
73
- .catch(Promise.TimeoutError, () => {
74
- logger.warn('timeout while running test using CDP. Running checkViaRestAPIIfTestStarted', { testResultId });
75
- return testRunHandler.checkViaRestAPIIfTestStarted();
76
- })
77
- .then(testResult => ({ ...testResult, ...testRunHandler.seleniumPerfStats.getStats() }))
78
- .catch(err => {
79
- logger.warn('failed to run test via CDP', { err });
80
- throw err;
81
- });
103
+ try {
104
+ const testResult = await runViaCdpOrFallbackToAPI();
105
+ return { ...testResult, ...testRunHandler.seleniumPerfStats.getStats() };
106
+ } catch (err) {
107
+ logger.warn('failed to run test via CDP', { err });
108
+ throw err;
109
+ }
82
110
  }
83
111
 
84
112
  const startStatusDetails = { driverUrlFinished: false, testRunHandlerOnStartedHadFinished: false }; //for logging / debugging purposes
85
- return new Promise((resolve, reject) => testRunHandler.getRunTestUrl()
86
- .then(url => {
87
- reporter.onWaitToTestStart(this.id);
88
- return Promise.all([
89
- driver.url(url).tap(() => { startStatusDetails.driverUrlFinished = true; }).catch(err => {
90
- logger.error('error from driver.url', { err, testResultId, executionId, testId, url, urlLength: url.length });
91
- throw err;
92
- }),
93
- testRunHandler.onStarted(this.options.testStartTimeout).tap(() => { startStatusDetails.testRunHandlerOnStartedHadFinished = true; }),
94
- ])
95
- .timeout(this.options.testStartTimeout, timeoutMessages.TEST_START_TIMEOUT_MSG)
96
- .catch(Promise.TimeoutError, () => {
97
- logger.warn('timeout occurred (see log\'s payload). Running checkViaRestAPIIfTestStarted', { testResultId, executionId, testId, ...startStatusDetails });
98
- return testRunHandler.checkViaRestAPIIfTestStarted();
99
- });
100
- })
101
- .then(() => {
102
- reporter.onWaitToTestComplete(this.id, this.isCodeMode);
103
- const onBrowserClosed = (err) => {
104
- testRunHandler.onCompletedCleanup();
105
- logger.warn('on browser closed error detected', { err, testResultId, executionId, testId });
106
- driver.unregisterToClosedBrowser(onBrowserClosed);
107
- err.type = stepResult.BROWSER_CLOSED;
108
- reject(err);
109
- };
110
- driver.registerToClosedBrowser(onBrowserClosed);
111
- return testRunHandler.onCompleted().timeout(this.testRunTimeout, timeoutMessages.TEST_COMPLETE_TIMEOUT_MSG)
112
- .then(async testResult => {
113
- driver.unregisterToClosedBrowser(onBrowserClosed);
114
- if (this.lambdatestService.isLambdatestRun()) {
115
- await driver.executeJS(`lambda-status=${!testResult.success ? 'failed' : 'passed'}`).catch(() => { });
116
- }
117
- if (!driver.isAlive()) {
118
- logger.warn(`possible grid unresponsive for test ${this.testId}, result ${this.testResultId} (execution: ${this.executionId})`);
119
- testResult.gridIssues = 'could not validate grid is alive';
120
- }
121
- const maxKeepAliveGap = driver.maxKeepAliveGap();
122
- const MAX_KEEP_ALIVE_GAP = 30000;
123
- if (maxKeepAliveGap >= MAX_KEEP_ALIVE_GAP) {
124
- logger.warn(`possible browser keep alive issue ${this.testId}, result ${this.testResultId} (execution: ${this.executionId})`);
125
- testResult.keepAliveIssue = maxKeepAliveGap;
126
- }
127
- resolve({ ...testResult, ...testRunHandler.seleniumPerfStats.getStats() });
128
- })
129
- .catch(err => {
130
- logger.warn('timeout wait until test completed', { err, testResultId, executionId, testId });
131
- // complete time out
132
- reject(new Error(err));
133
- })
134
- .finally(() => {
135
- driver.unregisterToClosedBrowser(onBrowserClosed);
136
- });
137
- })
138
- .catch(err => {
139
- logger.warn('failed to start url', { err });
140
- reject(new Error(err));
141
- }));
113
+
114
+ try {
115
+ const url = await testRunHandler.getRunTestUrl();
116
+ reporter.onWaitToTestStart(this.id);
117
+ try {
118
+ await promiseTimeout(Promise.all([
119
+ navigateChromeSessionToRunTestim(url, startStatusDetails),
120
+ updateRunHandlerThatTestStartedAndChangeStatusDetails(startStatusDetails),
121
+ ]), this.options.testStartTimeout, timeoutMessages.TEST_START_TIMEOUT_MSG);
122
+ } catch (err) {
123
+ if (!(err instanceof TimeoutError)) {
124
+ throw err;
125
+ }
126
+ logger.warn('timeout occurred (see log\'s payload). Running checkViaRestAPIIfTestStarted', { testResultId, executionId, testId, ...startStatusDetails });
127
+ await testRunHandler.checkViaRestAPIIfTestStarted();
128
+ }
129
+
130
+ reporter.onWaitToTestComplete(this.id, this.isCodeMode);
131
+ const onBrowserClosed = (err) => {
132
+ testRunHandler.onCompletedCleanup();
133
+ logger.warn('on browser closed error detected', { err, testResultId, executionId, testId });
134
+ driver.unregisterToClosedBrowser(onBrowserClosed);
135
+ err.type = stepResult.BROWSER_CLOSED;
136
+ throw err;
137
+ };
138
+ driver.registerToClosedBrowser(onBrowserClosed);
139
+ try {
140
+ const testResult = await promiseTimeout(testRunHandler.onCompleted(), this.testRunTimeout, timeoutMessages.TEST_COMPLETE_TIMEOUT_MSG);
141
+ driver.unregisterToClosedBrowser(onBrowserClosed);
142
+ if (this.lambdatestService.isLambdatestRun()) {
143
+ await driver.executeJS(`lambda-status=${!testResult.success ? 'failed' : 'passed'}`).catch(() => { });
144
+ }
145
+ if (!driver.isAlive()) {
146
+ logger.warn(`possible grid unresponsive for test ${this.testId}, result ${this.testResultId} (execution: ${this.executionId})`);
147
+ testResult.gridIssues = 'could not validate grid is alive';
148
+ }
149
+ const maxKeepAliveGap = driver.maxKeepAliveGap();
150
+ const MAX_KEEP_ALIVE_GAP = 30000;
151
+ if (maxKeepAliveGap >= MAX_KEEP_ALIVE_GAP) {
152
+ logger.warn(`possible browser keep alive issue ${this.testId}, result ${this.testResultId} (execution: ${this.executionId})`);
153
+ testResult.keepAliveIssue = maxKeepAliveGap;
154
+ }
155
+ return { ...testResult, ...testRunHandler.seleniumPerfStats.getStats() };
156
+ } catch (err) {
157
+ logger.warn('timeout wait until test completed', { err, testResultId, executionId, testId });
158
+ // complete time out
159
+ throw new Error(err);
160
+ } finally {
161
+ driver.unregisterToClosedBrowser(onBrowserClosed);
162
+ }
163
+ } catch (err) {
164
+ logger.warn('failed to start url', { err });
165
+ throw new Error(err);
166
+ }
142
167
  };
143
168
 
144
169
  driver.start();
145
170
 
146
- return super.runTestOnce(testRunHandler, player)
147
- .log('WorkerExtension super.runTestOnce')
148
- .then(() => runExtTest(testRunHandler))
149
- .catch(err => {
150
- logger.error('failed to run test', {
151
- err,
152
- testId: testRunHandler.getTestId(),
153
- resultId: testRunHandler.getTestResultId(),
154
- });
155
- return Promise.reject(err);
171
+ try {
172
+ await super.runTestOnce(testRunHandler, player);
173
+ perf.log('WorkerExtension super.runTestOnce');
174
+ return await runExtTest();
175
+ } catch (err) {
176
+ logger.error('failed to run test', {
177
+ err,
178
+ testId: testRunHandler.getTestId(),
179
+ resultId: testRunHandler.getTestResultId(),
156
180
  });
181
+ throw err;
182
+ }
157
183
  }
158
184
  }
159
185
 
@@ -80,6 +80,10 @@ class WorkerSelenium extends BaseWorker {
80
80
  }
81
81
  }
82
82
 
83
+ /**
84
+ * @param {import('../testRunHandler')} testRunHandler
85
+ * @param {import('../player/seleniumTestPlayer')} seleniumTestPlayer
86
+ */
83
87
  async runTestOnce(testRunHandler, seleniumTestPlayer) {
84
88
  const { driver, sessionPlayer } = seleniumTestPlayer;
85
89
  const version = sessionPlayerInit.manifestVersion || 'runner';
@@ -111,10 +115,11 @@ class WorkerSelenium extends BaseWorker {
111
115
  if (!sessionPlayer.callOrderScheduler) { // old session player
112
116
  await testRunHandler.waitForExecutionStartedFinished();
113
117
  } else {
114
- sessionPlayer.callOrderScheduler.schedule(() =>
118
+ sessionPlayer.callOrderScheduler.schedule(
119
+ () => testRunHandler.waitForExecutionStartedFinished(),
115
120
  // this key is shared by clickim and this ensures that we do wait for the execution to be created before we do this.
116
- testRunHandler.waitForExecutionStartedFinished(),
117
- { key: `test-result:${this.userData.projectId}:${this.testResultId}` });
121
+ { key: `test-result:${this.userData.projectId}:${this.testResultId}` }
122
+ );
118
123
  }
119
124
  perf.log('right before playTestByCode');
120
125
  return new Promise((resolve, reject) => sessionPlayer.playTestByCode(