@testim/testim-cli 3.244.0 → 3.245.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,10 +1,11 @@
1
1
  /* eslint-disable no-console */
2
2
 
3
3
  const fkill = require('fkill');
4
+ const pRetry = require('p-retry');
4
5
 
5
6
  const httpRequest = require('./httpRequest');
6
7
  const npmWrapper = require('./npmWrapper');
7
- const { getCliLocation, runWithRetries } = require('../utils');
8
+ const { getCliLocation } = require('../utils');
8
9
  const { requireWithFallback } = require('./requireWithFallback');
9
10
 
10
11
  const PACKAGE_NAME = 'chromedriver';
@@ -40,7 +41,7 @@ const start = async () => {
40
41
 
41
42
  const isReady = async ({ chromeBinaryLocation }) => {
42
43
  // 100 tries, every 30ms
43
- await runWithRetries(async () => {
44
+ await pRetry(async () => {
44
45
  const statusResponse = await httpRequest.get(`${DRIVER_BASE_URL}/status`);
45
46
  if (!statusResponse || !statusResponse.value || !statusResponse.value.ready) {
46
47
  throw new Error('status failed');
@@ -59,7 +60,7 @@ const isReady = async ({ chromeBinaryLocation }) => {
59
60
  throw new Error('create session failed');
60
61
  }
61
62
  await httpRequest.delete(`${DRIVER_BASE_URL}/session/${sessionResponse.sessionId}`);
62
- }, 100, 30);
63
+ }, { retries: 100, minTimeout: 30 });
63
64
  };
64
65
 
65
66
  module.exports = {
@@ -45,6 +45,7 @@ class FeatureFlagsService {
45
45
  warnOnBadNetwork: new Rox.Flag(false),
46
46
  overrideAzureStorageUrl: new Rox.Flag(),
47
47
  useJsInputCodeInSafari: new Rox.Flag(),
48
+ useJsInputCodeInFirefox: new Rox.Flag(),
48
49
  autoSaveDownloadFileFireFox: new Rox.Flag(true),
49
50
  safariSelectOptionDispatchEventOnSelectElement: new Rox.Flag(true),
50
51
  experimentalPreCodeCompilation: new Rox.Flag(true),
@@ -1,5 +1,5 @@
1
+ const pRetry = require('p-retry');
1
2
  const { makeCounters } = require('./httpRequestCounters');
2
- const { runWithRetries } = require('../utils');
3
3
  const { rejects, doesNotReject, strictEqual } = require('assert');
4
4
 
5
5
  describe('the http request counters', () => {
@@ -8,29 +8,29 @@ describe('the http request counters', () => {
8
8
  wrapWithMonitoring = makeCounters();
9
9
  });
10
10
 
11
- it('Marks an always failing network as unhealthy', async () => {
12
- const fn = runWithRetries(wrapWithMonitoring(() => { throw new Error('bad network'); }), 30, 1);
11
+ it('marks an always failing network as unhealthy', async () => {
12
+ const fn = pRetry(wrapWithMonitoring(() => { throw new Error('bad network'); }), { retries: 30, minTimeout: 0, maxTimeout: 0 });
13
13
  await rejects(fn);
14
14
  strictEqual(await wrapWithMonitoring.isNetworkHealthy(), false);
15
15
  });
16
16
 
17
- it('Marks an unstable network as unhealthy', async () => {
18
- const fn = runWithRetries(wrapWithMonitoring(() => { throw new Error('bad network'); }), 30, 1);
19
- const fn2 = runWithRetries(wrapWithMonitoring(() => 'hello'), 20, 1);
17
+ it('marks an unstable network as unhealthy', async () => {
18
+ const fn = pRetry(wrapWithMonitoring(() => { throw new Error('bad network'); }), { retries: 30, minTimeout: 0, maxTimeout: 0 });
19
+ const fn2 = pRetry(wrapWithMonitoring(() => 'hello'), { retries: 20, minTimeout: 0, maxTimeout: 0 });
20
20
  await rejects(fn);
21
21
  await doesNotReject(fn2);
22
22
  strictEqual(await wrapWithMonitoring.isNetworkHealthy(), false);
23
23
  });
24
24
 
25
- it('Marks a trivial amount of failed requests as healthy', async () => {
26
- const fn = runWithRetries(wrapWithMonitoring(() => { throw new Error('bad network'); }), 30, 1);
25
+ it('marks a trivial amount of failed requests as healthy', async () => {
26
+ const fn = pRetry(wrapWithMonitoring(() => { throw new Error('bad network'); }), { retries: 30, minTimeout: 0, maxTimeout: 0 });
27
27
  await rejects(fn);
28
28
  const fn2 = wrapWithMonitoring(() => 'hello');
29
29
  await Promise.all(Array(290).fill().map(fn2));
30
30
  strictEqual(await wrapWithMonitoring.isNetworkHealthy(), true);
31
31
  });
32
32
 
33
- it('Marks a healthy network as healthy', async () => {
33
+ it('marks a healthy network as healthy', async () => {
34
34
  const fn2 = wrapWithMonitoring(() => 'hello');
35
35
  await Promise.all(Array(200).fill().map(fn2));
36
36
  strictEqual(await wrapWithMonitoring.isNetworkHealthy(), true);
@@ -78,7 +78,7 @@ async function installPackageLocally(rootPath, packageName, execOptions) {
78
78
  } catch (err) {
79
79
  // ignore error
80
80
  }
81
- return await exec(`npm i ${packageName} --no-save --no-package-lock --no-prune --prefer-offline --no-audit --legacy-peer-deps --progress=false`, { ...execOptions, cwd: rootPath }).catch(err => {
81
+ return await exec(`npm i ${packageName} --no-save --no-prune --prefer-offline --no-audit --progress=false`, { ...execOptions, cwd: rootPath }).catch(err => {
82
82
  const pathWithMissingPermissions = getPathWithMissingPermissions(err);
83
83
  const npmEightMissingPermissions = npmSevenAndEightMissingPermissions(err);
84
84
  if (pathWithMissingPermissions || npmEightMissingPermissions) {
@@ -110,7 +110,7 @@ Testim had missing write access to ${pathWithMissingPermissions || rootPath}
110
110
  }
111
111
  }
112
112
 
113
- const localNpmLocation = path.resolve(require.resolve('npm').replace('index.js',''), 'bin','npm-cli.js');
113
+ const localNpmLocation = path.resolve(require.resolve('npm').replace('index.js', ''), 'bin', 'npm-cli.js');
114
114
 
115
115
  function installPackages(prefix, packageNames, proxyUri, timeoutMs) {
116
116
  return new Promise((resolve, reject) => {
@@ -121,7 +121,7 @@ function installPackages(prefix, packageNames, proxyUri, timeoutMs) {
121
121
  let stdout = '';
122
122
  let stderr = '';
123
123
 
124
- const ops = '--no-save --no-package-lock --no-prune --prefer-offline --no-audit --legacy-peer-deps --progress=false'.split(' ');
124
+ const ops = '--no-save --no-package-lock --no-prune --prefer-offline --no-audit --progress=false'.split(' ');
125
125
  const npmInstall = spawn('node', [localNpmLocation, 'i', '--prefix', prefix, ...ops, ...packageNames, ...proxyFlag], envVars);
126
126
  npmInstall.stderr.pipe(process.stderr);
127
127
  npmInstall.stdout.pipe(process.stdout);
@@ -54,7 +54,7 @@ describe('npmWrapper', () => {
54
54
  fakeChildProcess.exec.yields(undefined, []); //resolve without errors
55
55
  const cwd = '/some/dir';
56
56
  const pkg = 'some-package';
57
- const expectedCmd = 'npm i some-package --no-save --no-package-lock --no-prune --prefer-offline --no-audit --legacy-peer-deps --progress=false';
57
+ const expectedCmd = 'npm i some-package --no-save --no-prune --prefer-offline --no-audit --progress=false';
58
58
  const expectedExecParams = { cwd };
59
59
 
60
60
  await npmWrapper.installPackageLocally(cwd, pkg);
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
3
  const Promise = require('bluebird');
4
+ const pRetry = require('p-retry');
4
5
  const io = require('socket.io-client');
5
6
  const config = require('../config');
6
- const utils = require('../../utils');
7
7
 
8
8
  const MAX_SOCKET_RECONNECT_ATTEMPT = 50;
9
9
  const MAX_RECONNECT_ATTEMPT_BEFORE_SWITCH = 10;
@@ -163,7 +163,7 @@ class BaseSocketServiceSocketIO {
163
163
  };
164
164
 
165
165
  this.emitPromisQueue = (this.emitPromisQueue || Promise.resolve())
166
- .then(() => utils.runWithRetries(emitAndWait, 200, 3000))
166
+ .then(() => pRetry(emitAndWait, { retries: 200, minTimeout: 3000 }))
167
167
  .finally(() => {
168
168
  if (Object.keys(errorneousEvents).length > 0) {
169
169
  logger.error('Bad acknowledge from socket emit', { errorneousEvents });
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const pako = require('pako');
4
+ const pRetry = require('p-retry');
4
5
  const _ = require('lodash');
5
6
  const testimCustomToken = require('./testimCustomToken');
6
7
  const constants = require('./constants');
@@ -66,13 +67,13 @@ function getWithAuth(url, query, options, timeout) {
66
67
  }
67
68
 
68
69
  function getS3Artifact(url, timeout) {
69
- return utils.runWithRetries(() => getWithAuth(`/storage${url}`, null, { isBinary: true }, timeout));
70
+ return pRetry(() => getWithAuth(`/storage${url}`, null, { isBinary: true }, timeout), { retries: DEFAULT_REQUEST_RETRY });
70
71
  }
71
72
 
72
73
  function getTestPlan(projectId, testPlanNames) {
73
74
  //TODO: need to be checked after 3 months to prevent users from using old version
74
75
  const parseProperty = (dataValue) => (dataValue == null ? [] : (typeof (dataValue) === 'string' && JSON.parse(dataValue)) || dataValue);
75
- return utils.runWithRetries(() => getWithAuth('/testPlan', { projectId, name: testPlanNames.join(',') }))
76
+ return pRetry((() => getWithAuth('/testPlan', { projectId, name: testPlanNames.join(',') }), { retries: DEFAULT_REQUEST_RETRY }))
76
77
  .then(body => body.map(testPlan => {
77
78
  testPlan.testConfigIds = parseProperty(testPlan.testConfigIds);
78
79
  testPlan.beforeAllLabels = parseProperty(testPlan.beforeAllLabels);
@@ -84,20 +85,20 @@ function getTestPlan(projectId, testPlanNames) {
84
85
 
85
86
 
86
87
  function loadTest({ testId, branch, projectId, skipSharedSteps = false, useBranchMap = true }) {
87
- return utils.runWithRetries(() => getWithAuth(`/test/${testId}`, {
88
+ return pRetry(() => getWithAuth(`/test/${testId}`, {
88
89
  projectId,
89
90
  branch,
90
91
  skipSharedSteps,
91
92
  useBranchMap,
92
- }));
93
+ }), { retries: DEFAULT_REQUEST_RETRY });
93
94
  }
94
95
 
95
96
  function saveTestPlanResult(projectId, testPlanId, result) {
96
- return utils.runWithRetries(() => postAuth({ url: '/testPlan/result', body: { projectId, testPlanId, result } }));
97
+ return pRetry(() => postAuth({ url: '/testPlan/result', body: { projectId, testPlanId, result } }), { retries: DEFAULT_REQUEST_RETRY });
97
98
  }
98
99
 
99
- function updateTestStatus(projectId, executionId, testId, resultId, status, data, apiRetries = DEFAULT_REQUEST_RETRY) {
100
- return utils.runWithRetries(() => putAuth('/result/run/test', {
100
+ function updateTestStatus(projectId, executionId, testId, resultId, status, data, retries = DEFAULT_REQUEST_RETRY) {
101
+ return pRetry(() => putAuth('/result/run/test', {
101
102
  runId: executionId,
102
103
  testId,
103
104
  resultId,
@@ -105,11 +106,11 @@ function updateTestStatus(projectId, executionId, testId, resultId, status, data
105
106
  projectId,
106
107
  runnerVersion,
107
108
  ...data,
108
- }), apiRetries);
109
+ }), { retries });
109
110
  }
110
111
 
111
112
  function updateExecutionTests(executionId, runnerStatuses, status, reason, success, startTime, endTime, projectId) {
112
- return utils.runWithRetries(() => putAuth('/result/run/tests', {
113
+ return pRetry(() => putAuth('/result/run/tests', {
113
114
  runId: executionId,
114
115
  runnerStatuses,
115
116
  status,
@@ -118,7 +119,7 @@ function updateExecutionTests(executionId, runnerStatuses, status, reason, succe
118
119
  startTime,
119
120
  endTime,
120
121
  projectId,
121
- }), DEFAULT_REQUEST_RETRY);
122
+ }), { retries: DEFAULT_REQUEST_RETRY });
122
123
  }
123
124
 
124
125
  function reportExecutionStarted({
@@ -162,7 +163,7 @@ function reportExecutionStarted({
162
163
  function reportExecutionFinished(status, executionId, projectId, success, tmsOptions = {}, remoteRunId, resultExtraData) {
163
164
  const endTime = Date.now();
164
165
 
165
- return utils.runWithRetries(() => putAuth('/result/run', {
166
+ return pRetry(() => putAuth('/result/run', {
166
167
  runId: executionId,
167
168
  projectId,
168
169
  endTime,
@@ -171,22 +172,22 @@ function reportExecutionFinished(status, executionId, projectId, success, tmsOpt
171
172
  tmsOptions,
172
173
  remoteRunId,
173
174
  resultExtraData,
174
- }), DEFAULT_REQUEST_RETRY);
175
+ }), { reties: DEFAULT_REQUEST_RETRY });
175
176
  }
176
177
 
177
178
  async function getTestPlanTestList(projectId, names, planIds, branch, intersections) {
178
- return utils.runWithRetries(() => postAuth({
179
+ return pRetry(() => postAuth({
179
180
  url: '/testPlan/list',
180
181
  body: { projectId, names, planIds, branch, intersections },
181
182
  // people who send insane lists get a timeout :(
182
183
  timeout: 120000,
183
- }));
184
+ }), { reties: DEFAULT_REQUEST_RETRY });
184
185
  }
185
186
 
186
187
  function getSuiteTestList({
187
188
  projectId, labels, testIds, testNames, testConfigNames, suiteNames, suiteIds, branch, rerunFailedByRunId, testConfigIds, intersections,
188
189
  }) {
189
- return utils.runWithRetries(() => postAuth({
190
+ return pRetry(() => postAuth({
190
191
  url: '/suite/v2/list',
191
192
  body: {
192
193
  projectId,
@@ -201,11 +202,11 @@ function getSuiteTestList({
201
202
  testConfigIds,
202
203
  intersections,
203
204
  },
204
- }));
205
+ }), { reties: DEFAULT_REQUEST_RETRY });
205
206
  }
206
207
 
207
208
  function getUsageForCurrentBillingPeriod(projectId) {
208
- return utils.runWithRetries(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`))
209
+ return pRetry(() => getWithAuth(`/plan/project/${projectId}/usage-current-billing-period`), { reties: DEFAULT_REQUEST_RETRY })
209
210
  .catch((error) => {
210
211
  logger.error('failed getting usage for current billing period', { projectId, error });
211
212
  return undefined;
@@ -213,11 +214,11 @@ function getUsageForCurrentBillingPeriod(projectId) {
213
214
  }
214
215
 
215
216
  function isTestResultCompleted(resultId, projectId, testRetryKey) {
216
- return utils.runWithRetries(() => getWithAuth(`/result/${resultId}/isComplete`, { projectId, testRetryKey }));
217
+ return pRetry(() => getWithAuth(`/result/${resultId}/isComplete`, { projectId, testRetryKey }), { reties: DEFAULT_REQUEST_RETRY });
217
218
  }
218
219
 
219
220
  function getTestResults(testId, resultId, projectId, branch) {
220
- return utils.runWithRetries(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }));
221
+ return pRetry(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }), { reties: DEFAULT_REQUEST_RETRY });
221
222
  }
222
223
 
223
224
  function keepAliveGrid(projectId, slots) {
@@ -245,19 +246,19 @@ function getHybridGridProvider(body) {
245
246
  }
246
247
 
247
248
  function getGridByName(companyId, projectId, gridName, browser, executionId) {
248
- return utils.runWithRetries(() => getWithAuth('/grid/name', {
249
+ return pRetry(() => getWithAuth('/grid/name', {
249
250
  companyId, projectId, name: gridName, browser, executionId, reqId: utils.guid(),
250
- }));
251
+ }), { reties: DEFAULT_REQUEST_RETRY });
251
252
  }
252
253
 
253
254
  function getGridById(companyId, projectId, gridId, browser, executionId) {
254
- return utils.runWithRetries(() => getWithAuth(`/grid/${gridId}`, { companyId, projectId, browser, executionId, reqId: utils.guid() }));
255
+ return pRetry(() => getWithAuth(`/grid/${gridId}`, { companyId, projectId, browser, executionId, reqId: utils.guid() }), { reties: DEFAULT_REQUEST_RETRY });
255
256
  }
256
257
 
257
258
 
258
259
  async function initializeUserWithAuth({ projectId, token, branchName, lightweightMode, localGrid }) {
259
260
  try {
260
- return await utils.runWithRetries(() => httpRequest.post({
261
+ return await pRetry(() => httpRequest.post({
261
262
  url: `${config.SERVICES_HOST}/executions/initialize`,
262
263
  body: {
263
264
  projectId,
@@ -266,7 +267,7 @@ async function initializeUserWithAuth({ projectId, token, branchName, lightweigh
266
267
  lightweightMode,
267
268
  localGrid,
268
269
  },
269
- }));
270
+ }), { reties: DEFAULT_REQUEST_RETRY });
270
271
  } catch (e) {
271
272
  logger.error('error initializing info from server', e);
272
273
  if (e && e.message && e.message.includes('Bad Request')) {
@@ -288,7 +289,7 @@ async function getEditorUrl() {
288
289
  return config.EDITOR_URL;
289
290
  }
290
291
  try {
291
- return await utils.runWithRetries(() => getWithAuth('/system-info/editor-url'));
292
+ return await pRetry(() => getWithAuth('/system-info/editor-url'), { reties: DEFAULT_REQUEST_RETRY });
292
293
  } catch (err) {
293
294
  logger.error('cannot retrieve editor-url from server');
294
295
  return 'https://app.testim.io';
@@ -296,20 +297,20 @@ async function getEditorUrl() {
296
297
  }
297
298
 
298
299
  function getAllGrids(companyId) {
299
- return utils.runWithRetries(() => getWithAuth('/grid', { companyId }));
300
+ return pRetry(() => getWithAuth('/grid', { companyId }), { reties: DEFAULT_REQUEST_RETRY });
300
301
  }
301
302
 
302
- const fetchLambdatestConfig = async () => utils.runWithRetries(() => getWithAuth('/grid/lt/config'));
303
+ const fetchLambdatestConfig = async () => pRetry(() => getWithAuth('/grid/lt/config'), { reties: DEFAULT_REQUEST_RETRY });
303
304
 
304
- const getLabFeaturesByProjectId = async (projectId) => utils.runWithRetries(() => getWithAuth(`/labFeature/v2/project/${projectId}`));
305
+ const getLabFeaturesByProjectId = async (projectId) => pRetry(() => getWithAuth(`/labFeature/v2/project/${projectId}`), { reties: DEFAULT_REQUEST_RETRY });
305
306
 
306
307
 
307
308
  function getRealData(projectId, channel, query) {
308
- return utils.runWithRetries(() => getWithAuth(`/real-data/${channel}?${query}&projectId=${projectId}`));
309
+ return pRetry(() => getWithAuth(`/real-data/${channel}?${query}&projectId=${projectId}`), { reties: DEFAULT_REQUEST_RETRY });
309
310
  }
310
311
 
311
312
  function updateTestResult(projectId, resultId, testId, testResult, remoteRunId) {
312
- return utils.runWithRetries(() => postAuth({
313
+ return pRetry(() => postAuth({
313
314
  url: '/result/test',
314
315
  body: {
315
316
  projectId,
@@ -318,11 +319,11 @@ function updateTestResult(projectId, resultId, testId, testResult, remoteRunId)
318
319
  testResult,
319
320
  remoteRunId,
320
321
  },
321
- }));
322
+ }), { reties: DEFAULT_REQUEST_RETRY });
322
323
  }
323
324
 
324
325
  function clearTestResult(projectId, resultId, testId, testResult) {
325
- return utils.runWithRetries(() => postAuth({
326
+ return pRetry(() => postAuth({
326
327
  url: '/result/test/clear',
327
328
  body: {
328
329
  projectId,
@@ -330,11 +331,11 @@ function clearTestResult(projectId, resultId, testId, testResult) {
330
331
  testId,
331
332
  testResult,
332
333
  },
333
- }));
334
+ }), { reties: DEFAULT_REQUEST_RETRY });
334
335
  }
335
336
 
336
337
  function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
337
- return utils.runWithRetries(() => postAuth({
338
+ return pRetry(() => postAuth({
338
339
  url: '/remoteStep',
339
340
  body: {
340
341
  projectId,
@@ -342,7 +343,7 @@ function saveRemoteStep(projectId, resultId, stepId, remoteStep) {
342
343
  stepId,
343
344
  remoteStep,
344
345
  },
345
- }));
346
+ }), { reties: DEFAULT_REQUEST_RETRY });
346
347
  }
347
348
 
348
349
  function relativize(uri) {
@@ -381,9 +382,9 @@ function uploadArtifact(projectId, testId, testResultId, content, subType, mimeT
381
382
  },
382
383
  };
383
384
 
384
- return utils.runWithRetries(() => postAuthFormData(`/storage${storagePath}`, {}, files, {
385
+ return pRetry(() => postAuthFormData(`/storage${storagePath}`, {}, files, {
385
386
  'X-Asset-Encoding': 'gzip',
386
- })).then(() => storagePath);
387
+ }), { reties: DEFAULT_REQUEST_RETRY }).then(() => storagePath);
387
388
  }
388
389
 
389
390
  const uploadRunDataArtifact = _.memoize(async (projectId, testId, testResultId, runData) => {
@@ -422,7 +423,7 @@ function addTestRetry({
422
423
  previousTestResultId,
423
424
  testResult,
424
425
  }) {
425
- return utils.runWithRetries(() => postAuth({
426
+ return pRetry(() => postAuth({
426
427
  url: '/result/test/retry',
427
428
  body: {
428
429
  projectId,
@@ -433,7 +434,7 @@ function addTestRetry({
433
434
  runId,
434
435
  testResult,
435
436
  },
436
- }), DEFAULT_REQUEST_RETRY);
437
+ }), { reties: DEFAULT_REQUEST_RETRY });
437
438
  }
438
439
 
439
440
  /**
package/errors.js CHANGED
@@ -1,3 +1,4 @@
1
+ const { AbortError } = require('p-retry');
1
2
  /**
2
3
  * NoArgsError - throws when arguments not passed to cli
3
4
  *
@@ -57,7 +58,7 @@ class GetBrowserError extends Error {
57
58
  }
58
59
  }
59
60
 
60
- class PageNotAvailableError extends Error {
61
+ class PageNotAvailableError extends AbortError {
61
62
  }
62
63
 
63
64
  class QuotaDepletedError extends Error { }