@testim/testim-cli 3.267.0 → 3.269.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.
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  'use strict';
2
4
 
3
5
  const path = require('path');
@@ -5,7 +7,8 @@ const os = require('os');
5
7
  const dataUriToBuffer = require('data-uri-to-buffer');
6
8
  const { spawn: threadSpawn, config } = require('threads');
7
9
  const Promise = require('bluebird');
8
- const fs = require('fs-extra');
10
+ const fse = require('fs-extra');
11
+ const fs = require('fs');
9
12
  const utils = require('../../../utils');
10
13
  const logger = require('../../../commons/logger').getLogger('cli-service');
11
14
  const { getS3Artifact } = require('../../../commons/testimServicesApi');
@@ -13,6 +16,7 @@ const npmWrapper = require('../../../commons/npmWrapper');
13
16
  const featureFlags = require('../../../commons/featureFlags');
14
17
  const { TimeoutError } = require('../../../errors');
15
18
 
19
+ /** @type {import('worker_threads') | false} */
16
20
  let workerThreads;
17
21
 
18
22
  config.set({
@@ -32,6 +36,15 @@ function convertWindowsBackslash(input) {
32
36
  return input.replace(/\\/g, '/');
33
37
  }
34
38
 
39
+ /**
40
+ * @param {string} transactionId
41
+ * @param {any} incomingParams
42
+ * @param {any} context
43
+ * @param {any} code
44
+ * @param {Record<string, any>} packageLocalLocations
45
+ * @param {number=} timeout
46
+ * @param {string=} fileDataUrl
47
+ */
35
48
  function runCode(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
36
49
  const requireCode = Object.keys(packageLocalLocations).reduce((all, pMember) => {
37
50
  all += `
@@ -204,7 +217,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
204
217
 
205
218
  const testimConsoleLogDataAggregates = [];
206
219
  const thread = threadSpawn(constructWithArguments(Function, ['input', 'done', 'progress', runFn]));
207
- return new Promise((resolve) => {
220
+ return utils.promiseTimeout(new Promise((resolve) => {
208
221
  thread
209
222
  .send({ incomingParams, context, code })
210
223
  .on('message', message => {
@@ -226,7 +239,7 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
226
239
  tstConsoleLogs: testimConsoleLogDataAggregates,
227
240
  status: 'failed',
228
241
  result: {
229
- resultValue: err && err.toString(),
242
+ resultValue: err?.toString(),
230
243
  exports: {},
231
244
  exportsTest: {},
232
245
  exportsGlobal: {},
@@ -237,22 +250,25 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
237
250
  .on('exit', () => {
238
251
  logger.debug('Run code worker has been terminated', { transactionId });
239
252
  });
240
- }).timeout(timeout)
241
- .catch(Promise.TimeoutError, err => {
253
+ }), timeout)
254
+ .catch(err => {
255
+ if (!(err instanceof utils.TimeoutError)) {
256
+ throw err;
257
+ }
242
258
  logger.warn('timeout to run code', { transactionId, err });
243
- return Promise.resolve({
259
+ return {
244
260
  tstConsoleLogs: testimConsoleLogDataAggregates,
245
261
  status: 'failed',
246
262
  result: {
247
- resultValue: err && err.toString(),
263
+ resultValue: err?.toString(),
248
264
  exports: {},
249
265
  exportsTest: {},
250
266
  exportsGlobal: {},
251
267
  },
252
268
  success: false,
253
- });
269
+ };
254
270
  })
255
- .finally(() => thread && thread.kill());
271
+ .finally(() => thread?.kill());
256
272
  }
257
273
 
258
274
  function requireOrImportMethod(path) {
@@ -260,7 +276,6 @@ function requireOrImportMethod(path) {
260
276
  return { sync: true, lib: require(path) };
261
277
  } catch (err) {
262
278
  if (err.code === 'ERR_REQUIRE_ESM') {
263
- const fs = require('fs');
264
279
  const pathModule = require('path');
265
280
 
266
281
  const lib = fs.promises.readFile(`${path}${pathModule.sep}package.json`).then(file => {
@@ -275,7 +290,22 @@ function requireOrImportMethod(path) {
275
290
  }
276
291
  }
277
292
 
278
- function runCodeWithWorkerThread(transactionId, incomingParams, context, code, packageLocalLocations = {}, timeout = undefined, fileDataUrl = undefined) {
293
+ /**
294
+ * @param {string} transactionId
295
+ * @param {any} incomingParams
296
+ * @param {any} context
297
+ * @param {any} code
298
+ * @param {number=} timeout
299
+ */
300
+ function runCodeWithWorkerThread(
301
+ transactionId,
302
+ incomingParams,
303
+ context,
304
+ code,
305
+ packageLocalLocations = {},
306
+ timeout = undefined,
307
+ fileDataUrl = undefined,
308
+ ) {
279
309
  // technically shouldn't happen, but better safe than sorry.
280
310
  if (!workerThreads) {
281
311
  workerThreads = require('worker_threads');
@@ -477,7 +507,7 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
477
507
  const thread = new Worker(runFn, {
478
508
  eval: true,
479
509
  });
480
- return new Promise((resolve) => {
510
+ return utils.promiseTimeout(new Promise((resolve) => {
481
511
  thread
482
512
  .on('message', message => {
483
513
  if (message.action === 'finish') {
@@ -500,7 +530,7 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
500
530
  tstConsoleLogs: testimConsoleLogDataAggregates,
501
531
  status: 'failed',
502
532
  result: {
503
- resultValue: err && err.toString(),
533
+ resultValue: err?.toString(),
504
534
  exports: {},
505
535
  exportsTest: {},
506
536
  exportsGlobal: {},
@@ -513,26 +543,29 @@ function runCodeWithWorkerThread(transactionId, incomingParams, context, code, p
513
543
  });
514
544
  // context can contain methods and proxies which cannot pass.
515
545
  thread.postMessage({ incomingParams, context: JSON.parse(JSON.stringify(context)), code });
516
- }).timeout(timeout)
517
- .catch(Promise.TimeoutError, err => {
546
+ }), timeout)
547
+ .catch(err => {
548
+ if (!(err instanceof utils.TimeoutError)) {
549
+ throw err;
550
+ }
518
551
  logger.warn('timeout to run code', { transactionId, err });
519
- return Promise.resolve({
552
+ return {
520
553
  tstConsoleLogs: testimConsoleLogDataAggregates,
521
554
  status: 'failed',
522
555
  result: {
523
- resultValue: err && err.toString(),
556
+ resultValue: err?.toString(),
524
557
  exports: {},
525
558
  exportsTest: {},
526
559
  exportsGlobal: {},
527
560
  },
528
561
  success: false,
529
- });
562
+ };
530
563
  })
531
- .finally(() => thread && thread.terminate());
564
+ .finally(() => thread?.terminate());
532
565
  }
533
566
 
534
567
  function removeFolder(installFolder) {
535
- return new Promise(resolve => fs.remove(installFolder)
568
+ return new Promise(resolve => fse.remove(installFolder)
536
569
  .then(resolve)
537
570
  .catch(err => {
538
571
  logger.warn('failed to remove install npm packages folder', { err });
package/bluebirdConfig.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  /**
4
4
  * Configure bluebird promises
@@ -6,18 +6,19 @@
6
6
  const Promise = require('bluebird');
7
7
  const { isDebuggerConnected } = require('./commons/detectDebugger');
8
8
  const { OVERRIDE_TIMEOUTS } = require('./commons/config');
9
+
9
10
  Promise.config({
10
11
  // Disable warnings.
11
12
  warnings: false,
12
13
  // Enable long stack traces.
13
14
  longStackTraces: Boolean(isDebuggerConnected()),
14
15
  // Disable cancellation.
15
- cancellation: false
16
+ cancellation: false,
16
17
  });
17
18
 
18
19
  let warnedAboutDebugger = false;
19
20
  if (OVERRIDE_TIMEOUTS) {
20
- let old = Promise.prototype.timeout;
21
+ const old = Promise.prototype.timeout;
21
22
  const timeoutOverride = Number(OVERRIDE_TIMEOUTS || 6e5);
22
23
  if (!OVERRIDE_TIMEOUTS && !warnedAboutDebugger) {
23
24
  warnedAboutDebugger = true;
@@ -31,7 +32,7 @@ if (OVERRIDE_TIMEOUTS) {
31
32
  if (process.env.IS_BLUEBIRD_NATIVE_PROMISE_SCHEDULER) {
32
33
  // If the debugger is connected we skip the trampoline in order to schedule with native promise scheduling
33
34
  // which makes the V8 debugger aware of promise scheduling and makes async stack traces work without a lot of unnecessary bluebird-specific frames.
34
- const NativePromise = (async function () {})().constructor;
35
+ const NativePromise = (async function () {}()).constructor;
35
36
  const ResolvedNativePromise = NativePromise.resolve();
36
37
  Promise.setScheduler(fn => ResolvedNativePromise.then(fn));
37
38
  }
@@ -2,8 +2,8 @@
2
2
 
3
3
  const logger = require('./logger').getLogger('http-request');
4
4
  const superagent = require('superagent');
5
- const Promise = require('bluebird');
6
5
  const { makeCounters } = require('./httpRequestCounters');
6
+ const { promiseFromCallback } = require('../utils/promiseUtils');
7
7
 
8
8
  const wrapWithMonitoring = makeCounters();
9
9
 
@@ -63,7 +63,7 @@ function deleteFullRes(url, body = {}, headers = {}, timeout = DEFAULT_REQUEST_T
63
63
  request.proxy(getProxy());
64
64
  }
65
65
 
66
- return Promise.fromCallback((callback) => request.end(callback));
66
+ return promiseFromCallback((callback) => request.end(callback));
67
67
  }
68
68
 
69
69
  function post({
@@ -98,7 +98,7 @@ function postFullRes(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT,
98
98
  request.retry(retry);
99
99
  }
100
100
 
101
- return Promise.fromCallback((callback) => request.end(callback)).catch(e => e, e => {
101
+ return promiseFromCallback((callback) => request.end(callback)).catch(e => e, e => {
102
102
  e.url = url;
103
103
  e.originalRequestTimeout = timeout;
104
104
  e.additionalSetHeaders = headers;
@@ -127,7 +127,7 @@ function postForm(url, fields, files, headers = {}, timeout = DEFAULT_REQUEST_TI
127
127
  request.proxy(getProxy());
128
128
  }
129
129
 
130
- return Promise.fromCallback((callback) => request.end(callback))
130
+ return promiseFromCallback((callback) => request.end(callback))
131
131
  .then((res) => {
132
132
  if (res.type === 'text/plain') {
133
133
  return res.text;
@@ -156,7 +156,7 @@ function _get(url, query, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT, { isB
156
156
  request.proxy(getProxy());
157
157
  }
158
158
 
159
- return Promise.fromCallback((callback) => request.end(callback));
159
+ return promiseFromCallback((callback) => request.end(callback));
160
160
  }
161
161
 
162
162
  function getText(url, query, headers) {
@@ -191,7 +191,7 @@ function head(url) {
191
191
  request.proxy(getProxy());
192
192
  }
193
193
 
194
- return Promise.fromCallback((callback) => request.end(callback))
194
+ return promiseFromCallback((callback) => request.end(callback))
195
195
  .catch(logErrorAndRethrow('failed to head request', { url }));
196
196
  }
197
197
 
@@ -210,7 +210,7 @@ function put(url, body, headers = {}, timeout = DEFAULT_REQUEST_TIMEOUT) {
210
210
  request.proxy(getProxy());
211
211
  }
212
212
 
213
- return Promise.fromCallback((callback) => request.end(callback))
213
+ return promiseFromCallback((callback) => request.end(callback))
214
214
  .then((res) => res.body)
215
215
  .catch(logErrorAndRethrow('failed to put request', { url }));
216
216
  }
@@ -236,7 +236,7 @@ function download(url) {
236
236
  request.proxy(getProxy());
237
237
  }
238
238
 
239
- return Promise.fromCallback((callback) => request.end(callback))
239
+ return promiseFromCallback((callback) => request.end(callback))
240
240
  .then(response => {
241
241
  logger.info('finished to download', { url });
242
242
  return response;
@@ -1,13 +1,16 @@
1
+ // @ts-check
2
+
1
3
  'use strict';
2
4
 
3
5
  const path = require('path');
4
6
  const Promise = require('bluebird');
5
7
  const debounce = require('lodash/debounce');
6
- const fs = Promise.promisifyAll(require('fs'));
8
+ const fs = require('fs');
7
9
  const { getCliLocation } = require('../utils');
8
10
 
9
11
  const logger = require('./logger').getLogger('local cache');
10
12
  const crypto = require('crypto');
13
+ const utils = require('../utils');
11
14
 
12
15
  let cacheLocation = path.resolve(getCliLocation(), 'testim-cache');
13
16
 
@@ -25,10 +28,19 @@ const THREE_HOURS = 1000 * 60 * 60 * 3;
25
28
 
26
29
  const getCacheFileLocation = () => path.resolve(path.resolve(cacheLocation, 'testim.cache'));
27
30
 
28
- const getLocalRunnerCache = () => fs.readFileAsync(getCacheFileLocation()).then(async buffer => {
29
- const key = await _encryptKeyPromise;
30
- return decrypt(key, buffer);
31
- }).timeout(30000).catch(() => ({}));
31
+ async function getLocalRunnerCache() {
32
+ try {
33
+ return await utils.promiseTimeout(
34
+ fs.promises.readFile(getCacheFileLocation()).then(async buffer => {
35
+ const key = await _encryptKeyPromise;
36
+ return decrypt(key, buffer);
37
+ }),
38
+ 30_000,
39
+ );
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
32
44
 
33
45
  let localRunnerCache = getLocalRunnerCache();
34
46
 
@@ -59,7 +71,7 @@ const encryptAndSave = debounce(async (object) => {
59
71
  if (!pathExists) {
60
72
  await fs.promises.mkdir(cacheLocation, { recursive: true });
61
73
  }
62
- await fs.writeFileAsync(getCacheFileLocation(), result);
74
+ await fs.promises.writeFile(getCacheFileLocation(), result);
63
75
  } catch (err) {
64
76
  logger.error('failed saving cache', { err });
65
77
  error = err;
@@ -77,6 +89,7 @@ function decrypt(key, buffer) {
77
89
  const keyBuffer = Buffer.from(key);
78
90
  const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.concat([keyBuffer, Buffer.alloc(32)], 32), iv);
79
91
  const decrypted = decipher.update(encryptedText);
92
+ // @ts-ignore
80
93
  return JSON.parse(Buffer.concat([decrypted, decipher.final()]));
81
94
  }
82
95
  /**
@@ -4,6 +4,7 @@ const Promise = require('bluebird');
4
4
  const pRetry = require('p-retry');
5
5
  const io = require('socket.io-client');
6
6
  const config = require('../config');
7
+ const utils = require('../../utils');
7
8
 
8
9
  const MAX_SOCKET_RECONNECT_ATTEMPT = 50;
9
10
  const MAX_RECONNECT_ATTEMPT_BEFORE_SWITCH = 10;
@@ -15,7 +16,9 @@ const logger = require('../logger').getLogger('base socket service');
15
16
  class BaseSocketServiceSocketIO {
16
17
  constructor() {
17
18
  this.attempts = 0;
19
+ /** @type {{ [testResultId: string]: testId }} */
18
20
  this.rooms = {};
21
+ /** @type {undefined | Promise<void>} */
19
22
  this.emitPromiseQueue = undefined;
20
23
  }
21
24
 
@@ -28,10 +31,18 @@ class BaseSocketServiceSocketIO {
28
31
  });
29
32
  }
30
33
 
34
+ /**
35
+ * @param {string} resultId
36
+ * @param {string} testId
37
+ */
31
38
  joinRoom(resultId, testId) {
32
39
  this.rooms[resultId] = testId;
33
40
  }
34
41
 
42
+ /**
43
+ * @param {string} resultId
44
+ * @param {string} testId
45
+ */
35
46
  leaveRoom(resultId) {
36
47
  delete this.rooms[resultId];
37
48
  }
@@ -97,6 +108,10 @@ class BaseSocketServiceSocketIO {
97
108
  });
98
109
  }
99
110
 
111
+ /**
112
+ * @param {string} projectId
113
+ * @param {string} ns
114
+ */
100
115
  initNewSocket(projectId, ns) {
101
116
  const opts = {
102
117
  query: { projectId },
@@ -124,6 +139,10 @@ class BaseSocketServiceSocketIO {
124
139
  });
125
140
  }
126
141
 
142
+ /**
143
+ * @param {string} projectId
144
+ * @param {string} ns
145
+ */
127
146
  init(projectId, ns) {
128
147
  const opts = {
129
148
  query: { projectId },
@@ -146,6 +165,10 @@ class BaseSocketServiceSocketIO {
146
165
  this.addSocketHandlers();
147
166
  }
148
167
 
168
+ /**
169
+ * @param {string} eventName
170
+ * @param {*} eventData
171
+ */
149
172
  emitPromise(eventName, eventData) {
150
173
  const errorneousEvents = {};
151
174
 
@@ -158,10 +181,10 @@ class BaseSocketServiceSocketIO {
158
181
 
159
182
  return reject(new Error('bad ack'));
160
183
  });
161
- }).timeout(EMIT_PROMISE_TIMEOUT);
184
+ });
162
185
 
163
186
  this.emitPromiseQueue = (this.emitPromiseQueue || Promise.resolve())
164
- .then(() => pRetry(emitAndWait, { retries: 200, minTimeout: 3000 }))
187
+ .then(() => pRetry(() => utils.promiseTimeout(emitAndWait(), EMIT_PROMISE_TIMEOUT), { retries: 200, minTimeout: 3000, factor: 1 }))
165
188
  .finally(() => {
166
189
  if (Object.keys(errorneousEvents).length > 0) {
167
190
  logger.error('Bad acknowledge from socket emit', { errorneousEvents });
@@ -5,7 +5,6 @@ const { EventEmitter } = require('events');
5
5
  const featureFlags = require('../featureFlags');
6
6
 
7
7
  const { socketEventTypes } = require('../constants');
8
- const Promise = require('bluebird');
9
8
 
10
9
  class TestResultService extends EventEmitter {
11
10
  init(projectId) {
@@ -561,11 +561,11 @@ function buildSeleniumOptions(browserOptions, testName, testRunConfig, gridInfo,
561
561
  }
562
562
 
563
563
  //testRunConfig not in used for now
564
- function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, options }) {
564
+ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, options, appPath, androidActivityWait }) {
565
565
  const { deviceModel, osVersion, deviceUdid } = options;
566
566
  const headspinSelector = {};
567
567
 
568
- if (!nativeApp) {
568
+ if (!nativeApp && !appPath) {
569
569
  throw Error('missing mobile app!');
570
570
  }
571
571
  if (gridInfo.type !== gridTypes.TESTIM_HEADSPIN) {
@@ -576,23 +576,38 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
576
576
  hostname: gridInfo.host,
577
577
  port: gridInfo.port,
578
578
  path: `/v0/${gridInfo.accessToken}/wd/hub`,
579
+ // connectionRetryTimeout: 900000, -- not used for now
580
+ };
581
+ //TODO: check if more caps should be defined as default
582
+ let appCaps = {
583
+ 'headspin:capture': true,
584
+ 'appium:autoAcceptAlerts': true,
579
585
  };
580
-
581
- let appCaps = {};
582
586
  switch (projectType) {
583
587
  case 'ios':
584
588
  appCaps = {
585
- 'appium:bundleId': nativeApp.id,
589
+ ...appCaps,
586
590
  platformName: 'iOS',
587
591
  'appium:automationName': 'XCUITest',
592
+ ...(nativeApp && { 'appium:bundleId': nativeApp.id }),
593
+ ...(appPath && {
594
+ 'appium:app': appPath,
595
+ }),
588
596
  };
589
597
  break;
590
598
  case 'android':
591
599
  appCaps = {
600
+ ...appCaps,
592
601
  platformName: 'Android',
593
602
  'appium:automationName': 'UiAutomator2',
594
- 'appium:appPackage': nativeApp.packageName,
595
- 'appium:appActivity': nativeApp.activity,
603
+ 'appium:appWaitActivity': androidActivityWait,
604
+ ...(nativeApp && {
605
+ 'appium:appPackage': nativeApp.id || nativeApp.packageName,
606
+ 'appium:appActivity': nativeApp.activity,
607
+ }),
608
+ ...(appPath && {
609
+ 'appium:app': appPath,
610
+ }),
596
611
  };
597
612
  break;
598
613
  default:
@@ -609,7 +624,6 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
609
624
  delete headspinSelector.model;
610
625
  delete headspinSelector.os_version;
611
626
  }
612
-
613
627
  if (!_.isEmpty(headspinSelector)) {
614
628
  appCaps['headspin:selector'] = headspinSelector;
615
629
  }
@@ -237,6 +237,15 @@ function getSuiteTestList({
237
237
  }), { retries: DEFAULT_REQUEST_RETRY });
238
238
  }
239
239
 
240
+ async function getAppDetails({ appId, projectId }) {
241
+ try {
242
+ return await pRetry(() => getWithAuth(`/mobile-app/app/${appId}?projectId=${projectId}`), { retries: DEFAULT_REQUEST_RETRY, factor: 1 });
243
+ } catch (error) {
244
+ logger.error('failed getting application details', { appId, error });
245
+ return undefined;
246
+ }
247
+ }
248
+
240
249
  function getUsageForCurrentBillingPeriod(projectId) {
241
250
  return pRetry(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`), { retries: DEFAULT_REQUEST_RETRY })
242
251
  .catch((error) => {
@@ -395,10 +404,16 @@ function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
395
404
  }), { retries: DEFAULT_REQUEST_RETRY });
396
405
  }
397
406
 
407
+ /** @param {string} uri */
398
408
  function relativize(uri) {
399
409
  return uri.startsWith('/') ? uri : `/${uri}`;
400
410
  }
401
411
 
412
+ /**
413
+ * @param {string} filePath
414
+ * @param {string} bucket
415
+ * @param {string} projectId
416
+ */
402
417
  function getStorageRelativePath(filePath, bucket, projectId) {
403
418
  let fullPath = relativize(filePath);
404
419
  if (projectId) {
@@ -411,7 +426,15 @@ function getStorageRelativePath(filePath, bucket, projectId) {
411
426
  return fullPath;
412
427
  }
413
428
 
414
- function uploadArtifact(projectId, testId, testResultId, content, subType, mimeType = 'application/octet-stream') {
429
+ /**
430
+ * @param {string} projectId
431
+ * @param {string} testId
432
+ * @param {string} testResultId
433
+ * @param {*} content
434
+ * @param {string} subType
435
+ * @param {string} mimeType
436
+ */
437
+ async function uploadArtifact(projectId, testId, testResultId, content, subType, mimeType = 'application/octet-stream') {
415
438
  let fileSuffix = null;
416
439
  if (mimeType === 'application/json') {
417
440
  fileSuffix = '.json';
@@ -431,9 +454,11 @@ function uploadArtifact(projectId, testId, testResultId, content, subType, mimeT
431
454
  },
432
455
  };
433
456
 
434
- return pRetry(() => postAuthFormData(`/storage${storagePath}`, {}, files, {
435
- 'X-Asset-Encoding': 'gzip',
436
- }), { retries: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
457
+ await pRetry(
458
+ () => postAuthFormData(`/storage${storagePath}`, {}, files, { 'X-Asset-Encoding': 'gzip' }),
459
+ { retries: DEFAULT_REQUEST_RETRY, factor: 1 }
460
+ );
461
+ return storagePath;
437
462
  }
438
463
 
439
464
  const uploadRunDataArtifact = _.memoize(async (projectId, testId, testResultId, runData) => {
@@ -530,6 +555,7 @@ function updateRemoteRunFailure(body) {
530
555
  }
531
556
 
532
557
  module.exports = {
558
+ getAppDetails,
533
559
  getS3Artifact,
534
560
  getTestPlan,
535
561
  saveTestPlanResult,
@@ -553,7 +579,7 @@ module.exports = {
553
579
  saveRemoteStep,
554
580
  getEditorUrl,
555
581
  getLabFeaturesByProjectId,
556
- uploadRunDataArtifact: Promise.method(uploadRunDataArtifact),
582
+ uploadRunDataArtifact,
557
583
  updateTestDataArtifact: Promise.method(updateTestDataArtifact),
558
584
  initializeUserWithAuth,
559
585
  addTestRetry,
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const Promise = require('bluebird');
6
6
  const YAML = require('yaml');
7
7
  const os = require('os');
8
+ const utils = require('./utils');
8
9
  const { launchChrome } = require('./commons/chrome-launcher');
9
10
 
10
11
  async function getProjectId() {
@@ -17,7 +18,7 @@ async function getToken() {
17
18
 
18
19
  function timeout(promise, ms) {
19
20
  // we need this to time out even if we disabled timeouts system wide
20
- return Promise.race([promise, Promise.delay(ms).then(() => { throw new Promise.TimeoutError('timeout'); })]);
21
+ return Promise.race([promise, utils.delay(ms).then(() => { throw new utils.TimeoutError('timeout'); })]);
21
22
  }
22
23
 
23
24
  async function getCredentialsFromChrome() {
@@ -73,14 +74,14 @@ async function doLogin({ overwriteExisting = true, projects = null } = {}) {
73
74
  projects = await timeout(Promise.resolve(getCredentialsFromChrome()), 62000).catch(e => null);
74
75
  }
75
76
 
76
- if (projects && projects.token) { // V1(legacy) of the login extension API
77
+ if (projects?.token) { // V1(legacy) of the login extension API
77
78
  credentials.token = projects.token;
78
79
  credentials.projectId = projects.projectId;
79
80
  spinner.succeed();
80
81
 
81
82
  await writeCredentials(testimCredentialsFile, credentials);
82
83
  return;
83
- } if (projects && projects.length) { // V2(current) of the login extension API
84
+ } if (projects?.length) { // V2(current) of the login extension API
84
85
  spinner.succeed();
85
86
 
86
87
  const response = projects.length === 1 ?