@testim/testim-cli 3.253.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 (79) 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 +7 -7
  11. package/agent/routers/playground/router.js +11 -10
  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/detectDebugger.js +4 -2
  31. package/commons/lazyRequire.js +10 -9
  32. package/commons/logger.js +4 -4
  33. package/commons/performance-logger.js +14 -8
  34. package/commons/prepareRunnerAndTestimStartUtils.js +6 -7
  35. package/commons/socket/baseSocketServiceSocketIO.js +32 -34
  36. package/commons/socket/realDataService.js +6 -5
  37. package/commons/socket/realDataServiceSocketIO.js +4 -4
  38. package/commons/socket/remoteStepService.js +4 -3
  39. package/commons/socket/remoteStepServiceSocketIO.js +11 -12
  40. package/commons/socket/socketService.js +50 -52
  41. package/commons/socket/testResultServiceSocketIO.js +11 -11
  42. package/commons/testimDesiredCapabilitiesBuilder.js +3 -2
  43. package/commons/testimNgrok.js +2 -2
  44. package/commons/testimNgrok.test.js +1 -1
  45. package/commons/testimServicesApi.js +27 -20
  46. package/commons/xhr2.js +97 -100
  47. package/errors.js +5 -0
  48. package/fixLocalBuild.js +2 -0
  49. package/npm-shrinkwrap.json +2515 -1256
  50. package/package.json +6 -6
  51. package/player/appiumTestPlayer.js +1 -1
  52. package/player/chromeLauncherTestPlayer.js +0 -1
  53. package/player/services/tabServiceMock.js +166 -0
  54. package/player/stepActions/navigationStepAction.js +11 -10
  55. package/player/stepActions/sleepStepAction.js +4 -5
  56. package/player/stepActions/textStepAction.js +4 -11
  57. package/player/utils/windowUtils.js +4 -3
  58. package/player/webdriver.js +1 -1
  59. package/processHandler.js +3 -3
  60. package/processHandler.test.js +1 -1
  61. package/reports/consoleReporter.js +3 -2
  62. package/reports/junitReporter.js +1 -2
  63. package/runOptions.js +6 -6
  64. package/runner.js +13 -0
  65. package/runners/TestPlanRunner.js +142 -74
  66. package/runners/buildCodeTests.js +38 -37
  67. package/runners/runnerUtils.js +3 -3
  68. package/services/lambdatestService.js +3 -5
  69. package/stepPlayers/cliJsStepPlayback.js +22 -17
  70. package/testRunHandler.js +8 -0
  71. package/testRunStatus.js +1 -1
  72. package/{utils.js → utils/index.js} +25 -117
  73. package/utils/promiseUtils.js +78 -0
  74. package/utils/stringUtils.js +96 -0
  75. package/{utils.test.js → utils/utils.test.js} +2 -2
  76. package/workers/BaseWorker.js +16 -14
  77. package/workers/WorkerAppium.js +1 -1
  78. package/workers/WorkerExtensionSingleBrowser.js +4 -4
  79. 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
  }
@@ -628,9 +628,10 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp })
628
628
  break;
629
629
  case 'android':
630
630
  appCaps = {
631
- appPackage: nativeApp.packageName,
632
- appActivity: nativeApp.activity,
631
+ platformName: 'Android',
633
632
  'appium:automationName': 'UiAutomator2',
633
+ 'appium:appPackage': nativeApp.packageName,
634
+ 'appium:appActivity': nativeApp.activity,
634
635
  };
635
636
  break;
636
637
  default:
@@ -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
 
@@ -84,6 +84,12 @@ function getTestPlan(projectId, testPlanNames) {
84
84
  }));
85
85
  }
86
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
+ }
87
93
 
88
94
  function loadTest({ testId, branch, projectId, skipSharedSteps = false, useBranchMap = true }) {
89
95
  return pRetry(() => getWithAuth(`/test/${testId}`, {
@@ -174,7 +180,7 @@ function reportExecutionFinished(status, executionId, projectId, success, tmsOpt
174
180
  tmsOptions,
175
181
  remoteRunId,
176
182
  resultExtraData,
177
- }), { reties: DEFAULT_REQUEST_RETRY });
183
+ }), { retries: DEFAULT_REQUEST_RETRY });
178
184
  }
179
185
 
180
186
  async function getTestPlanTestList(projectId, names, planIds, branch, intersections) {
@@ -183,7 +189,7 @@ async function getTestPlanTestList(projectId, names, planIds, branch, intersecti
183
189
  body: { projectId, names, planIds, branch, intersections },
184
190
  // people who send insane lists get a timeout :(
185
191
  timeout: 120000,
186
- }), { reties: DEFAULT_REQUEST_RETRY });
192
+ }), { retries: DEFAULT_REQUEST_RETRY });
187
193
  }
188
194
 
189
195
  function getSuiteTestList({
@@ -204,11 +210,11 @@ function getSuiteTestList({
204
210
  testConfigIds,
205
211
  intersections,
206
212
  },
207
- }), { reties: DEFAULT_REQUEST_RETRY });
213
+ }), { retries: DEFAULT_REQUEST_RETRY });
208
214
  }
209
215
 
210
216
  function getUsageForCurrentBillingPeriod(projectId) {
211
- 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 })
212
218
  .catch((error) => {
213
219
  logger.error('failed getting usage for current billing period', { projectId, error });
214
220
  return undefined;
@@ -216,11 +222,11 @@ function getUsageForCurrentBillingPeriod(projectId) {
216
222
  }
217
223
 
218
224
  function isTestResultCompleted(resultId, projectId, testRetryKey) {
219
- 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 });
220
226
  }
221
227
 
222
228
  function getTestResults(testId, resultId, projectId, branch) {
223
- 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 });
224
230
  }
225
231
 
226
232
  function keepAliveGrid(projectId, slots) {
@@ -250,11 +256,11 @@ function getHybridGridProvider(body) {
250
256
  function getGridByName(companyId, projectId, gridName, browser, executionId) {
251
257
  return pRetry(() => getWithAuth('/grid/name', {
252
258
  companyId, projectId, name: gridName, browser, executionId, reqId: utils.guid(),
253
- }), { reties: DEFAULT_REQUEST_RETRY });
259
+ }), { retries: DEFAULT_REQUEST_RETRY });
254
260
  }
255
261
 
256
262
  function getGridById(companyId, projectId, gridId, browser, executionId) {
257
- 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 });
258
264
  }
259
265
 
260
266
 
@@ -269,7 +275,7 @@ async function initializeUserWithAuth({ projectId, token, branchName, lightweigh
269
275
  lightweightMode,
270
276
  localGrid,
271
277
  },
272
- }), { reties: DEFAULT_REQUEST_RETRY });
278
+ }), { retries: DEFAULT_REQUEST_RETRY });
273
279
  } catch (e) {
274
280
  logger.error('error initializing info from server', e);
275
281
  if (e && e.message && e.message.includes('Bad Request')) {
@@ -292,7 +298,7 @@ async function getEditorUrl() {
292
298
  }
293
299
  try {
294
300
  return await pRetry(() => getWithAuth('/system-info/editor-url'), {
295
- reties: DEFAULT_REQUEST_RETRY,
301
+ retries: DEFAULT_REQUEST_RETRY,
296
302
  onFailedAttempt: error => {
297
303
  if (error.attemptNumber >= DEFAULT_REQUEST_RETRY) {
298
304
  throw error;
@@ -306,16 +312,16 @@ async function getEditorUrl() {
306
312
  }
307
313
 
308
314
  function getAllGrids(companyId) {
309
- return pRetry(() => getWithAuth('/grid', { companyId }), { reties: DEFAULT_REQUEST_RETRY });
315
+ return pRetry(() => getWithAuth('/grid', { companyId }), { retries: DEFAULT_REQUEST_RETRY });
310
316
  }
311
317
 
312
- 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 });
313
319
 
314
- 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 });
315
321
 
316
322
 
317
323
  function getRealData(projectId, channel, query) {
318
- 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 });
319
325
  }
320
326
 
321
327
  function updateTestResult(projectId, resultId, testId, testResult, remoteRunId) {
@@ -328,7 +334,7 @@ function updateTestResult(projectId, resultId, testId, testResult, remoteRunId)
328
334
  testResult,
329
335
  remoteRunId,
330
336
  },
331
- }), { reties: DEFAULT_REQUEST_RETRY });
337
+ }), { retries: DEFAULT_REQUEST_RETRY });
332
338
  }
333
339
 
334
340
  function clearTestResult(projectId, resultId, testId, testResult) {
@@ -340,7 +346,7 @@ function clearTestResult(projectId, resultId, testId, testResult) {
340
346
  testId,
341
347
  testResult,
342
348
  },
343
- }), { reties: DEFAULT_REQUEST_RETRY });
349
+ }), { retries: DEFAULT_REQUEST_RETRY });
344
350
  }
345
351
 
346
352
  function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
@@ -352,7 +358,7 @@ function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
352
358
  stepId,
353
359
  remoteStep,
354
360
  },
355
- }), { reties: DEFAULT_REQUEST_RETRY });
361
+ }), { retries: DEFAULT_REQUEST_RETRY });
356
362
  }
357
363
 
358
364
  function relativize(uri) {
@@ -393,7 +399,7 @@ function uploadArtifact(projectId, testId, testResultId, content, subType, mimeT
393
399
 
394
400
  return pRetry(() => postAuthFormData(`/storage${storagePath}`, {}, files, {
395
401
  'X-Asset-Encoding': 'gzip',
396
- }), { reties: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
402
+ }), { retries: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
397
403
  }
398
404
 
399
405
  const uploadRunDataArtifact = _.memoize(async (projectId, testId, testResultId, runData) => {
@@ -443,7 +449,7 @@ function addTestRetry({
443
449
  runId,
444
450
  testResult,
445
451
  },
446
- }), { reties: DEFAULT_REQUEST_RETRY });
452
+ }), { retries: DEFAULT_REQUEST_RETRY });
447
453
  }
448
454
 
449
455
  /**
@@ -518,6 +524,7 @@ module.exports = {
518
524
  initializeUserWithAuth: Promise.method(initializeUserWithAuth),
519
525
  addTestRetry,
520
526
  getHybridGridProvider,
527
+ loadSfdcCredential,
521
528
  loadTest,
522
529
  isTestResultCompleted,
523
530
  getApplitoolsIntegrationData,