@testim/testim-cli 3.252.0 → 3.254.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 (97) hide show
  1. package/OverrideTestDataBuilder.js +1 -1
  2. package/agent/routers/cliJsCode/index.js +4 -4
  3. package/agent/routers/cliJsCode/router.js +46 -42
  4. package/agent/routers/cliJsCode/service.js +18 -13
  5. package/agent/routers/codim/router.js +14 -17
  6. package/agent/routers/codim/router.test.js +15 -14
  7. package/agent/routers/codim/service.js +1 -1
  8. package/agent/routers/general/index.js +4 -8
  9. package/agent/routers/hybrid/registerRoutes.js +18 -18
  10. package/agent/routers/index.js +9 -8
  11. package/agent/routers/playground/router.js +12 -11
  12. package/agent/routers/playground/service.js +19 -18
  13. package/agent/routers/standalone-browser/registerRoutes.js +10 -10
  14. package/cdpTestRunner.js +4 -3
  15. package/chromiumInstaller.js +4 -5
  16. package/cli/onExit.js +2 -2
  17. package/cli.js +7 -6
  18. package/cliAgentMode.js +4 -5
  19. package/codim/codim-cli.js +11 -10
  20. package/codim/hybrid-utils.js +1 -1
  21. package/codim/measure-perf.js +9 -6
  22. package/codim/template.js/tests/examples/01-simple-text-validation.test.js +6 -6
  23. package/codim/template.js/tests/examples/02-using-locators.test.js +13 -15
  24. package/codim/template.js/tests/examples/03-using-hooks.test.js +17 -19
  25. package/codim/template.js/tests/examples/04-skip-and-only.test.js +16 -17
  26. package/codim/template.js/tests/examples/05-multiple-windows.test.js +16 -17
  27. package/codim/template.js/webpack.config.js +1 -1
  28. package/codim/template.ts/webpack.config.js +3 -3
  29. package/commons/AbortError.js +4 -4
  30. package/commons/chrome-launcher.js +6 -6
  31. package/commons/constants.js +2 -0
  32. package/commons/detectDebugger.js +4 -2
  33. package/commons/getSessionPlayerRequire.js +2 -20
  34. package/commons/initializeUserWithAuth.js +2 -2
  35. package/commons/lazyRequire.js +10 -9
  36. package/commons/logger.js +4 -4
  37. package/commons/performance-logger.js +14 -8
  38. package/commons/prepareRunnerAndTestimStartUtils.js +6 -7
  39. package/commons/socket/baseSocketServiceSocketIO.js +32 -34
  40. package/commons/socket/realDataService.js +6 -5
  41. package/commons/socket/realDataServiceSocketIO.js +4 -4
  42. package/commons/socket/remoteStepService.js +4 -3
  43. package/commons/socket/remoteStepServiceSocketIO.js +11 -12
  44. package/commons/socket/socketService.js +50 -52
  45. package/commons/socket/testResultServiceSocketIO.js +11 -11
  46. package/commons/testimDesiredCapabilitiesBuilder.js +44 -0
  47. package/commons/testimNgrok.js +2 -2
  48. package/commons/testimNgrok.test.js +1 -1
  49. package/commons/testimServicesApi.js +37 -21
  50. package/commons/xhr2.js +97 -100
  51. package/credentialsManager.js +17 -20
  52. package/errors.js +5 -0
  53. package/fixLocalBuild.js +2 -0
  54. package/npm-shrinkwrap.json +4455 -1576
  55. package/package.json +9 -7
  56. package/player/WebdriverioWebDriverApi.js +7 -2
  57. package/player/appiumTestPlayer.js +102 -0
  58. package/player/chromeLauncherTestPlayer.js +0 -1
  59. package/player/seleniumTestPlayer.js +3 -2
  60. package/player/services/frameLocator.js +2 -1
  61. package/player/services/mobileFrameLocatorMock.js +32 -0
  62. package/player/services/playbackTimeoutCalculator.js +1 -0
  63. package/player/services/portSelector.js +10 -8
  64. package/player/services/tabService.js +29 -0
  65. package/player/services/tabServiceMock.js +166 -0
  66. package/player/stepActions/navigationStepAction.js +11 -10
  67. package/player/stepActions/sleepStepAction.js +4 -5
  68. package/player/stepActions/stepAction.js +15 -1
  69. package/player/stepActions/textStepAction.js +4 -11
  70. package/player/utils/stepActionUtils.js +4 -2
  71. package/player/utils/windowUtils.js +139 -125
  72. package/player/webdriver.js +40 -26
  73. package/processHandler.js +3 -3
  74. package/processHandler.test.js +1 -1
  75. package/reports/consoleReporter.js +3 -2
  76. package/reports/debugReporter.js +41 -39
  77. package/reports/jsonReporter.js +53 -50
  78. package/reports/junitReporter.js +1 -2
  79. package/reports/reporter.js +135 -136
  80. package/runOptions.js +8 -7
  81. package/runner.js +13 -0
  82. package/runners/ParallelWorkerManager.js +2 -0
  83. package/runners/TestPlanRunner.js +142 -74
  84. package/runners/buildCodeTests.js +38 -37
  85. package/runners/runnerUtils.js +3 -3
  86. package/services/lambdatestService.js +3 -5
  87. package/stepPlayers/cliJsStepPlayback.js +22 -17
  88. package/testRunHandler.js +8 -0
  89. package/testRunStatus.js +458 -460
  90. package/{utils.js → utils/index.js} +25 -117
  91. package/utils/promiseUtils.js +78 -0
  92. package/utils/stringUtils.js +96 -0
  93. package/{utils.test.js → utils/utils.test.js} +2 -2
  94. package/workers/BaseWorker.js +29 -20
  95. package/workers/WorkerAppium.js +123 -0
  96. package/workers/WorkerExtensionSingleBrowser.js +4 -4
  97. package/workers/WorkerSelenium.js +5 -2
@@ -1,10 +1,10 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  const WebSocket = require('ws');
4
- const {WEBSOCKET_HOST} = require('../config');
4
+ const { WEBSOCKET_HOST } = require('../config');
5
5
  const utils = require('../../utils');
6
- const logger = require('../logger').getLogger("socket-ng-service");
7
- const {EventEmitter} = require('events');
6
+ const logger = require('../logger').getLogger('socket-ng-service');
7
+ const { EventEmitter } = require('events');
8
8
  const _ = require('lodash');
9
9
  const Promise = require('bluebird');
10
10
  const testimCustomToken = require('../testimCustomToken');
@@ -21,16 +21,16 @@ class SocketService extends EventEmitter {
21
21
  }
22
22
 
23
23
  onReconnect(projectId) {
24
- logger.info(`test result websocket re-connect`);
24
+ logger.info('test result websocket re-connect');
25
25
  setTimeout(() => this.connect(projectId), WAIT_BETWEEN_RECONNECT_MS);
26
26
  }
27
27
 
28
28
  formatUrl(url) {
29
- if(_.startsWith(url, "http://")) {
29
+ if (_.startsWith(url, 'http://')) {
30
30
  return _.replace(url, 'http://', 'ws://');
31
31
  }
32
32
 
33
- if(_.startsWith(url, "https://")) {
33
+ if (_.startsWith(url, 'https://')) {
34
34
  return _.replace(url, 'https://', 'wss://');
35
35
  }
36
36
 
@@ -41,50 +41,48 @@ class SocketService extends EventEmitter {
41
41
  try {
42
42
  return JSON.parse(event);
43
43
  } catch (err) {
44
- logger.error(`failed to parse or trigger event`, {err});
44
+ logger.error('failed to parse or trigger event', { err });
45
45
  }
46
+ return undefined;
46
47
  }
47
48
 
48
-
49
49
  connect(projectId) {
50
50
  const wsBaseUrl = this.formatUrl(WEBSOCKET_HOST);
51
51
  return testimCustomToken.getCustomTokenV3()
52
- .then(token => {
53
- return new Promise((resolve) => {
54
- const options = {};
55
- if(global.proxyUri) {
56
- options.agent = new global.ProxyAgent(global.proxyUri);
52
+ .then(token => new Promise((resolve) => {
53
+ const options = {};
54
+ if (global.proxyUri) {
55
+ options.agent = new global.ProxyAgent(global.proxyUri);
56
+ }
57
+ this.ws = new WebSocket(`${wsBaseUrl}?projectId=${projectId}&clientId=${this.clientId}&token=${token}`, options);
58
+
59
+ this.ws.on('open', () => {
60
+ logger.info('websocket opened');
61
+ this.reSendAllExistingFilters();
62
+ if (this.onConnect) {
63
+ this.onConnect();
64
+ }
65
+ return resolve();
66
+ });
67
+
68
+ this.ws.on('close', (event) => {
69
+ logger.info('websocket closed', { event });
70
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
71
+ this.onReconnect(projectId, token, wsBaseUrl);
72
+ }
73
+ });
74
+
75
+ this.ws.on('error', (event) => {
76
+ logger.info('websocket error', { event });
77
+ });
78
+
79
+ this.ws.on('message', (event) => {
80
+ const evObject = this.parseEvent(event);
81
+ if (evObject?.type) {
82
+ this.emit(evObject.type, evObject.data);
57
83
  }
58
- this.ws = new WebSocket(`${wsBaseUrl}?projectId=${projectId}&clientId=${this.clientId}&token=${token}`, options);
59
-
60
- this.ws.on("open", () => {
61
- logger.info(`websocket opened`);
62
- this.reSendAllExistingFilters();
63
- if (this.onConnect) {
64
- this.onConnect();
65
- }
66
- return resolve();
67
- });
68
-
69
- this.ws.on("close", (event) => {
70
- logger.info(`websocket closed`, {event});
71
- if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
72
- this.onReconnect(projectId, token, wsBaseUrl);
73
- }
74
- });
75
-
76
- this.ws.on("error", (event) => {
77
- logger.info(`websocket error`, {event});
78
- });
79
-
80
- this.ws.on("message", (event) => {
81
- const evObject = this.parseEvent(event);
82
- if (evObject && evObject.type) {
83
- this.emit(evObject.type, evObject.data);
84
- }
85
- });
86
84
  });
87
- });
85
+ }));
88
86
  }
89
87
 
90
88
  // this is private because our sockets are supposed to be read-only to
@@ -99,7 +97,7 @@ class SocketService extends EventEmitter {
99
97
  try {
100
98
  this.ws.send(JSON.stringify(msg));
101
99
  } catch (err) {
102
- logger.error('failed to stringify message for sending', {err});
100
+ logger.error('failed to stringify message for sending', { err });
103
101
  }
104
102
  }
105
103
 
@@ -125,25 +123,25 @@ class SocketService extends EventEmitter {
125
123
  const eventNameArray = Array.isArray(eventName) ? eventName : [eventName];
126
124
  eventNameArray.forEach(name => {
127
125
  this.listeners[`${key}:${name}`] = this.listeners[`${key}:${name}`] || [];
128
- const listener = fireIfSameMatchEventMatcher.bind(this);
129
- this.listeners[`${key}:${name}`].push(listener);
130
- this.on(name, listener);
126
+ const _listener = fireIfSameMatchEventMatcher.bind(this);
127
+ this.listeners[`${key}:${name}`].push(_listener);
128
+ this.on(name, _listener);
131
129
  });
132
130
  }
133
131
 
134
132
  reSendAllExistingFilters() {
135
133
  Object.keys(this.filterMap).forEach(key => {
136
134
  const filter = this.filterMap[key];
137
- this.sendMessage({type: "add-filter", filter});
135
+ this.sendMessage({ type: 'add-filter', filter });
138
136
  });
139
137
  }
140
138
 
141
139
  addFilter(key, query, type, returnFullDocument = false) {
142
140
  return new Promise(resolve => {
143
141
  const filterId = utils.guid();
144
- const filter = {query, id: filterId, type, fullDocument: returnFullDocument};
145
- this.listenOnce("add-filter:done", data => data.id === filterId, resolve);
146
- this.sendMessage({type: "add-filter", filter});
142
+ const filter = { query, id: filterId, type, fullDocument: returnFullDocument };
143
+ this.listenOnce('add-filter:done', data => data.id === filterId, resolve);
144
+ this.sendMessage({ type: 'add-filter', filter });
147
145
  this.filterMap[key] = filter;
148
146
  });
149
147
  }
@@ -170,7 +168,7 @@ class SocketService extends EventEmitter {
170
168
  const typeArray = Array.isArray(type) ? type : [type];
171
169
  this.removeListeners(key, typeArray);
172
170
  delete this.filterMap[key];
173
- this.sendMessage({type: "remove-filter", filter});
171
+ this.sendMessage({ type: 'remove-filter', filter });
174
172
  }
175
173
  }
176
174
 
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  const Promise = require('bluebird');
4
4
  const BaseSocketService = require('./baseSocketServiceSocketIO');
@@ -10,8 +10,8 @@ class TestResultServiceSocketIO extends BaseSocketService {
10
10
  }
11
11
 
12
12
  listenToTestResult(resultId, testId, onTestResultStatus) {
13
- if(this.listerers[resultId]) {
14
- this._socket.off("testResult:updated", this.listerers[resultId]);
13
+ if (this.listerers[resultId]) {
14
+ this._socket.off('testResult:updated', this.listerers[resultId]);
15
15
  delete this.listerers[resultId];
16
16
  }
17
17
 
@@ -21,18 +21,18 @@ class TestResultServiceSocketIO extends BaseSocketService {
21
21
  }
22
22
  };
23
23
 
24
- this._socket.on("testResult:updated", this.listerers[resultId]);
24
+ this._socket.on('testResult:updated', this.listerers[resultId]);
25
25
  }
26
26
 
27
27
  emitJoinRoom(resultId, testId) {
28
- return this.emitPromise("testResult:join", {
28
+ return this.emitPromise('testResult:join', {
29
29
  resultId,
30
- testId
30
+ testId,
31
31
  });
32
32
  }
33
33
 
34
34
  joinToTestResult(resultId, testId) {
35
- if(this.rooms[resultId]) {
35
+ if (this.rooms[resultId]) {
36
36
  return Promise.resolve();
37
37
  }
38
38
  this.joinRoom(resultId, testId);
@@ -40,19 +40,19 @@ class TestResultServiceSocketIO extends BaseSocketService {
40
40
  }
41
41
 
42
42
  emitLeaveRoom(resultId, testId) {
43
- return this.emitPromise("testResult:leave", {
43
+ return this.emitPromise('testResult:leave', {
44
44
  resultId,
45
- testId
45
+ testId,
46
46
  });
47
47
  }
48
48
 
49
49
  leaveTestResult(resultId, testId) {
50
- if(!this.listerers[resultId]) {
50
+ if (!this.listerers[resultId]) {
51
51
  return Promise.resolve();
52
52
  }
53
53
 
54
54
  this.leaveRoom(resultId);
55
- this._socket.off("testResult:updated", this.listerers[resultId]);
55
+ this._socket.off('testResult:updated', this.listerers[resultId]);
56
56
  delete this.listerers[resultId];
57
57
  return this.emitLeaveRoom(resultId, testId);
58
58
  }
@@ -602,6 +602,50 @@ function buildSeleniumOptions(browserOptions, testName, testRunConfig, gridInfo,
602
602
  return opts;
603
603
  }
604
604
 
605
+ //testRunConfig not in used for now
606
+ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp }) {
607
+ if (!nativeApp) {
608
+ throw Error('missing mobile app!');
609
+ }
610
+ if (gridInfo.type !== gridTypes.TESTIM_HEADSPIN) {
611
+ throw Error('unsupported grid was detected please make sure to select supported mobile grid');
612
+ }
613
+ const connection = {
614
+ protocol: gridInfo.protocol || 'https',
615
+ hostname: gridInfo.host,
616
+ port: gridInfo.port,
617
+ path: `/v0/${gridInfo.accessToken}/wd/hub`,
618
+ };
619
+
620
+ let appCaps = {};
621
+ switch (projectType) {
622
+ case 'ios':
623
+ appCaps = {
624
+ 'appium:bundleId': nativeApp.id,
625
+ platformName: 'iOS',
626
+ 'appium:automationName': 'XCUITest',
627
+ };
628
+ break;
629
+ case 'android':
630
+ appCaps = {
631
+ platformName: 'Android',
632
+ 'appium:automationName': 'UiAutomator2',
633
+ 'appium:appPackage': nativeApp.packageName,
634
+ 'appium:appActivity': nativeApp.activity,
635
+ };
636
+ break;
637
+ default:
638
+ throw Error(`unsupported mobile project ${projectType}`);
639
+ }
640
+ return {
641
+ ...connection,
642
+ desiredCapabilities: appCaps,
643
+ capabilities: appCaps,
644
+ };
645
+ }
646
+
605
647
  module.exports = {
606
648
  buildSeleniumOptions,
649
+ buildAppiumOptions,
650
+
607
651
  };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const { ArgError } = require('../errors.js');
4
- const utils = require('../utils.js');
3
+ const { ArgError } = require('../errors');
4
+ const utils = require('../utils');
5
5
  const lazyRequire = require('./lazyRequire');
6
6
  const logger = require('./logger').getLogger('testimNgrok');
7
7
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- const { ArgError } = require('../errors.js');
5
+ const { ArgError } = require('../errors');
6
6
  const { sinon, expect } = require('../../test/utils/testUtils');
7
7
  const testimNgrok = require('./testimNgrok');
8
8
  const utils = require('../utils');
@@ -6,7 +6,7 @@ const _ = require('lodash');
6
6
  const testimCustomToken = require('./testimCustomToken');
7
7
  const constants = require('./constants');
8
8
  const Promise = require('bluebird');
9
- const utils = require('../utils.js');
9
+ const utils = require('../utils');
10
10
  const config = require('./config');
11
11
  const httpRequest = require('./httpRequest');
12
12
 
@@ -21,7 +21,7 @@ function getTokenHeader() {
21
21
  return testimCustomToken.getCustomTokenV3()
22
22
  .then(brearToken => {
23
23
  if (!brearToken) {
24
- return Promise.reject(new Error('Failed to get token from server'));
24
+ throw new Error('Failed to get token from server');
25
25
  }
26
26
  return { Authorization: `Bearer ${brearToken}` };
27
27
  });
@@ -43,6 +43,7 @@ function postAuth({
43
43
  });
44
44
  }
45
45
 
46
+ // eslint-disable-next-line default-param-last
46
47
  function postAuthFormData(url, fields, files, headers = {}, timeout) {
47
48
  return getTokenHeader()
48
49
  .then(tokenHeaders => {
@@ -83,6 +84,12 @@ function getTestPlan(projectId, testPlanNames) {
83
84
  }));
84
85
  }
85
86
 
87
+ async function loadSfdcCredential({ branch, projectId }) {
88
+ const branchData = await pRetry(() => getWithAuth(`/branch/branchData/${branch}`, {
89
+ projectId,
90
+ }), { retries: DEFAULT_REQUEST_RETRY });
91
+ return branchData?.sfdcCredential;
92
+ }
86
93
 
87
94
  function loadTest({ testId, branch, projectId, skipSharedSteps = false, useBranchMap = true }) {
88
95
  return pRetry(() => getWithAuth(`/test/${testId}`, {
@@ -160,6 +167,7 @@ function reportExecutionStarted({
160
167
  });
161
168
  }
162
169
 
170
+ // eslint-disable-next-line default-param-last
163
171
  function reportExecutionFinished(status, executionId, projectId, success, tmsOptions = {}, remoteRunId, resultExtraData) {
164
172
  const endTime = Date.now();
165
173
 
@@ -172,7 +180,7 @@ function reportExecutionFinished(status, executionId, projectId, success, tmsOpt
172
180
  tmsOptions,
173
181
  remoteRunId,
174
182
  resultExtraData,
175
- }), { reties: DEFAULT_REQUEST_RETRY });
183
+ }), { retries: DEFAULT_REQUEST_RETRY });
176
184
  }
177
185
 
178
186
  async function getTestPlanTestList(projectId, names, planIds, branch, intersections) {
@@ -181,7 +189,7 @@ async function getTestPlanTestList(projectId, names, planIds, branch, intersecti
181
189
  body: { projectId, names, planIds, branch, intersections },
182
190
  // people who send insane lists get a timeout :(
183
191
  timeout: 120000,
184
- }), { reties: DEFAULT_REQUEST_RETRY });
192
+ }), { retries: DEFAULT_REQUEST_RETRY });
185
193
  }
186
194
 
187
195
  function getSuiteTestList({
@@ -202,11 +210,11 @@ function getSuiteTestList({
202
210
  testConfigIds,
203
211
  intersections,
204
212
  },
205
- }), { reties: DEFAULT_REQUEST_RETRY });
213
+ }), { retries: DEFAULT_REQUEST_RETRY });
206
214
  }
207
215
 
208
216
  function getUsageForCurrentBillingPeriod(projectId) {
209
- return pRetry(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`), { reties: DEFAULT_REQUEST_RETRY })
217
+ return pRetry(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`), { retries: DEFAULT_REQUEST_RETRY })
210
218
  .catch((error) => {
211
219
  logger.error('failed getting usage for current billing period', { projectId, error });
212
220
  return undefined;
@@ -214,11 +222,11 @@ function getUsageForCurrentBillingPeriod(projectId) {
214
222
  }
215
223
 
216
224
  function isTestResultCompleted(resultId, projectId, testRetryKey) {
217
- return pRetry(() => getWithAuth(`/result/${resultId}/isComplete`, { projectId, testRetryKey }), { reties: DEFAULT_REQUEST_RETRY });
225
+ return pRetry(() => getWithAuth(`/result/${resultId}/isComplete`, { projectId, testRetryKey }), { retries: DEFAULT_REQUEST_RETRY });
218
226
  }
219
227
 
220
228
  function getTestResults(testId, resultId, projectId, branch) {
221
- return pRetry(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }), { reties: DEFAULT_REQUEST_RETRY });
229
+ return pRetry(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }), { retries: DEFAULT_REQUEST_RETRY });
222
230
  }
223
231
 
224
232
  function keepAliveGrid(projectId, slots) {
@@ -248,11 +256,11 @@ function getHybridGridProvider(body) {
248
256
  function getGridByName(companyId, projectId, gridName, browser, executionId) {
249
257
  return pRetry(() => getWithAuth('/grid/name', {
250
258
  companyId, projectId, name: gridName, browser, executionId, reqId: utils.guid(),
251
- }), { reties: DEFAULT_REQUEST_RETRY });
259
+ }), { retries: DEFAULT_REQUEST_RETRY });
252
260
  }
253
261
 
254
262
  function getGridById(companyId, projectId, gridId, browser, executionId) {
255
- return pRetry(() => getWithAuth(`/grid/${gridId}`, { companyId, projectId, browser, executionId, reqId: utils.guid() }), { reties: DEFAULT_REQUEST_RETRY });
263
+ return pRetry(() => getWithAuth(`/grid/${gridId}`, { companyId, projectId, browser, executionId, reqId: utils.guid() }), { retries: DEFAULT_REQUEST_RETRY });
256
264
  }
257
265
 
258
266
 
@@ -267,7 +275,7 @@ async function initializeUserWithAuth({ projectId, token, branchName, lightweigh
267
275
  lightweightMode,
268
276
  localGrid,
269
277
  },
270
- }), { reties: DEFAULT_REQUEST_RETRY });
278
+ }), { retries: DEFAULT_REQUEST_RETRY });
271
279
  } catch (e) {
272
280
  logger.error('error initializing info from server', e);
273
281
  if (e && e.message && e.message.includes('Bad Request')) {
@@ -289,7 +297,14 @@ async function getEditorUrl() {
289
297
  return config.EDITOR_URL;
290
298
  }
291
299
  try {
292
- return await pRetry(() => getWithAuth('/system-info/editor-url'), { reties: DEFAULT_REQUEST_RETRY });
300
+ return await pRetry(() => getWithAuth('/system-info/editor-url'), {
301
+ retries: DEFAULT_REQUEST_RETRY,
302
+ onFailedAttempt: error => {
303
+ if (error.attemptNumber >= DEFAULT_REQUEST_RETRY) {
304
+ throw error;
305
+ }
306
+ },
307
+ });
293
308
  } catch (err) {
294
309
  logger.error('cannot retrieve editor-url from server');
295
310
  return 'https://app.testim.io';
@@ -297,16 +312,16 @@ async function getEditorUrl() {
297
312
  }
298
313
 
299
314
  function getAllGrids(companyId) {
300
- return pRetry(() => getWithAuth('/grid', { companyId }), { reties: DEFAULT_REQUEST_RETRY });
315
+ return pRetry(() => getWithAuth('/grid', { companyId }), { retries: DEFAULT_REQUEST_RETRY });
301
316
  }
302
317
 
303
- const fetchLambdatestConfig = async () => pRetry(() => getWithAuth('/grid/lt/config'), { reties: DEFAULT_REQUEST_RETRY });
318
+ const fetchLambdatestConfig = async () => pRetry(() => getWithAuth('/grid/lt/config'), { retries: DEFAULT_REQUEST_RETRY });
304
319
 
305
- const getLabFeaturesByProjectId = async (projectId) => pRetry(() => getWithAuth(`/labFeature/v2/project/${projectId}`), { reties: DEFAULT_REQUEST_RETRY });
320
+ const getLabFeaturesByProjectId = async (projectId) => pRetry(() => getWithAuth(`/labFeature/v2/project/${projectId}`), { retries: DEFAULT_REQUEST_RETRY });
306
321
 
307
322
 
308
323
  function getRealData(projectId, channel, query) {
309
- return pRetry(() => getWithAuth(`/real-data/${channel}?${query}&projectId=${projectId}`), { reties: DEFAULT_REQUEST_RETRY });
324
+ return pRetry(() => getWithAuth(`/real-data/${channel}?${query}&projectId=${projectId}`), { retries: DEFAULT_REQUEST_RETRY });
310
325
  }
311
326
 
312
327
  function updateTestResult(projectId, resultId, testId, testResult, remoteRunId) {
@@ -319,7 +334,7 @@ function updateTestResult(projectId, resultId, testId, testResult, remoteRunId)
319
334
  testResult,
320
335
  remoteRunId,
321
336
  },
322
- }), { reties: DEFAULT_REQUEST_RETRY });
337
+ }), { retries: DEFAULT_REQUEST_RETRY });
323
338
  }
324
339
 
325
340
  function clearTestResult(projectId, resultId, testId, testResult) {
@@ -331,7 +346,7 @@ function clearTestResult(projectId, resultId, testId, testResult) {
331
346
  testId,
332
347
  testResult,
333
348
  },
334
- }), { reties: DEFAULT_REQUEST_RETRY });
349
+ }), { retries: DEFAULT_REQUEST_RETRY });
335
350
  }
336
351
 
337
352
  function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
@@ -343,7 +358,7 @@ function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
343
358
  stepId,
344
359
  remoteStep,
345
360
  },
346
- }), { reties: DEFAULT_REQUEST_RETRY });
361
+ }), { retries: DEFAULT_REQUEST_RETRY });
347
362
  }
348
363
 
349
364
  function relativize(uri) {
@@ -384,7 +399,7 @@ function uploadArtifact(projectId, testId, testResultId, content, subType, mimeT
384
399
 
385
400
  return pRetry(() => postAuthFormData(`/storage${storagePath}`, {}, files, {
386
401
  'X-Asset-Encoding': 'gzip',
387
- }), { reties: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
402
+ }), { retries: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
388
403
  }
389
404
 
390
405
  const uploadRunDataArtifact = _.memoize(async (projectId, testId, testResultId, runData) => {
@@ -434,7 +449,7 @@ function addTestRetry({
434
449
  runId,
435
450
  testResult,
436
451
  },
437
- }), { reties: DEFAULT_REQUEST_RETRY });
452
+ }), { retries: DEFAULT_REQUEST_RETRY });
438
453
  }
439
454
 
440
455
  /**
@@ -509,6 +524,7 @@ module.exports = {
509
524
  initializeUserWithAuth: Promise.method(initializeUserWithAuth),
510
525
  addTestRetry,
511
526
  getHybridGridProvider,
527
+ loadSfdcCredential,
512
528
  loadTest,
513
529
  isTestResultCompleted,
514
530
  getApplitoolsIntegrationData,