@testim/testim-cli 3.197.0 → 3.201.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.
@@ -32,7 +32,7 @@ class OverrideTestDataBuilder {
32
32
  }
33
33
  }
34
34
  if (this.isObjectNotArray(params) && typeof params.overrideAllTestsData !== 'undefined') {
35
- if (this.isObjectNotArray(params.overrideAllTestsData) && !_.isEmpty(params.overrideAllTestsData)) {
35
+ if (_.isObject(params.overrideAllTestsData) && !_.isEmpty(params.overrideAllTestsData)) {
36
36
  const testNames = this.testInfoList.map(test => test.name);
37
37
  testNames.forEach(testName => this.overrideSingeTest(testName, params.overrideAllTestsData));
38
38
  delete params.overrideAllTestsData;
@@ -37,7 +37,6 @@ class FeatureFlagsService {
37
37
  useSafariWebdriverVisibilityChecks: new Rox.Flag(),
38
38
  useClickimVisibilityChecks: new Rox.Flag(),
39
39
  useIEWebdriverVisibilityChecks: new Rox.Flag(),
40
- enableTDKRun: new Rox.Flag(true),
41
40
  runGetElementCodeInAut: new Rox.Flag(),
42
41
  enableNpmPackageInstallUsingNpmCli: new Rox.Flag(),
43
42
  enableFrameSwitchOptimization: new Rox.Flag(),
@@ -47,8 +46,6 @@ class FeatureFlagsService {
47
46
  warnOnBadNetwork: new Rox.Flag(false),
48
47
  overrideAzureStorageUrl: new Rox.Flag(),
49
48
  useJsInputCodeInSafari: new Rox.Flag(),
50
- testNameTestDataInJunitReport: new Rox.Flag(),
51
- countRetries: new Rox.Flag(),
52
49
  autoSaveDownloadFileFireFox: new Rox.Flag(true),
53
50
  safariSelectOptionDispatchEventOnSelectElement: new Rox.Flag(true),
54
51
  experimentalPreCodeCompilation: new Rox.Flag(false),
@@ -9,7 +9,7 @@ const Promise = require('bluebird');
9
9
  const fse = require('fs-extra');
10
10
  const logger = require('./logger').getLogger('cli-service');
11
11
  const { requireWithFallback } = require('./requireWithFallback');
12
- const os = require('os');
12
+ const fs = require('fs');
13
13
 
14
14
  async function getLatestPackageVersion(packageName) {
15
15
  const result = await exec(`npm view ${packageName} version`);
@@ -40,6 +40,16 @@ function getLocallyInstalledPackageVersion(rootPath, packageName) {
40
40
  return require(path.join(rootPath, `./node_modules/${packageName}/package.json`)).version;
41
41
  }
42
42
 
43
+ // this is not exactly correct, but it's good enough.
44
+ async function fileExists(path) {
45
+ try {
46
+ await fs.promises.access(path);
47
+ return true;
48
+ } catch (err) {
49
+ return false;
50
+ }
51
+ }
52
+
43
53
  async function installPackageLocally(rootPath, packageName, execOptions) {
44
54
  function getPathWithMissingPermissions(error) {
45
55
  const pathRegex = /EACCES[^']+'(.+)'/;
@@ -50,26 +60,48 @@ async function installPackageLocally(rootPath, packageName, execOptions) {
50
60
  return regexResult[1];
51
61
  }
52
62
 
53
- return exec(`npm i ${packageName} --no-save --no-package-lock --no-prune --prefer-offline --no-audit --progress=false`, { ...execOptions, cwd: rootPath }).catch(err => {
54
- const pathWithMissingPermissions = getPathWithMissingPermissions(err);
55
- if (pathWithMissingPermissions) {
56
- logger.info('Failed to install package due to insufficient write access', {
57
- ...additionalLogDetails(),
58
- package: packageName,
59
- path: pathWithMissingPermissions,
60
- });
61
- // eslint-disable-next-line no-console
62
- console.error(`
63
+ // this is here because our shrinkwrap blocks our lazy deps for some reason
64
+ const oldShrinkwrap = path.join(rootPath, 'npm-shrinkwrap.json');
65
+ const newShrinkwrap = path.join(rootPath, 'npm-shrinkwrap-dummy.json');
66
+ let renamed = false;
67
+ try {
68
+ try {
69
+ if (await fileExists(oldShrinkwrap)) {
70
+ await fs.promises.rename(oldShrinkwrap, newShrinkwrap);
71
+ renamed = true;
72
+ }
73
+ } catch (err) {
74
+ // ignore error
75
+ }
76
+ return await exec(`npm i ${packageName} --no-save --no-package-lock --no-prune --prefer-offline --no-audit --progress=false`, { ...execOptions, cwd: rootPath }).catch(err => {
77
+ const pathWithMissingPermissions = getPathWithMissingPermissions(err);
78
+ if (pathWithMissingPermissions) {
79
+ logger.info('Failed to install package due to insufficient write access', {
80
+ ...additionalLogDetails(),
81
+ package: packageName,
82
+ path: pathWithMissingPermissions,
83
+ });
84
+ // eslint-disable-next-line no-console
85
+ console.error(`
63
86
 
64
87
  Testim failed installing the package ${packageName} due to insufficient permissions.
65
88
  This is probably due to an installation of @testim/testim-cli with sudo, and running it without sudo.
66
89
  Testim had missing write access to ${pathWithMissingPermissions}
67
90
 
68
91
  `);
69
- throw new NpmPermissionsError(pathWithMissingPermissions);
92
+ throw new NpmPermissionsError(pathWithMissingPermissions);
93
+ }
94
+ throw err;
95
+ });
96
+ } finally {
97
+ if (renamed) {
98
+ try {
99
+ await fs.promises.rename(newShrinkwrap, oldShrinkwrap);
100
+ } catch (err) {
101
+ // ignore error
102
+ }
70
103
  }
71
- throw err;
72
- });
104
+ }
73
105
  }
74
106
 
75
107
  const localNpmLocation = path.resolve(require.resolve('npm'), '../../bin/npm-cli.js');
@@ -5,8 +5,8 @@ const { sinon, expect } = require('../../test/utils/testUtils');
5
5
  const os = require('os');
6
6
  const { NpmPermissionsError } = require('../errors');
7
7
  const path = require('path');
8
+
8
9
  const fs = require('fs');
9
- const { getCliLocation } = require('../utils');
10
10
 
11
11
  describe('npmWrapper', () => {
12
12
  describe('installPackageLocally', () => {
@@ -22,17 +22,22 @@ describe('npmWrapper', () => {
22
22
 
23
23
  let fakeChildProcess;
24
24
  let fakeLogger;
25
-
25
+ let fakeFS;
26
26
  let originalConsole;
27
27
  beforeEach(() => {
28
28
  fakeChildProcess = { exec: sinon.stub() };
29
29
  fakeLogger = { warn: sinon.stub(), info: sinon.stub() };
30
-
30
+ fakeFS = {
31
+ promises: {
32
+ access: sinon.stub().rejects(new Error()),
33
+ },
34
+ };
31
35
  originalConsole = global.console;
32
36
  global.console = { log: sinon.stub(), error: sinon.stub() };
33
37
 
34
38
  npmWrapper = proxyquire('./npmWrapper', {
35
39
  child_process: fakeChildProcess,
40
+ fs: fakeFS,
36
41
  './logger': { getLogger: () => fakeLogger },
37
42
  });
38
43
  });
@@ -65,7 +70,7 @@ describe('npmWrapper', () => {
65
70
 
66
71
  stubExecRejection(execErr);
67
72
 
68
- expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
73
+ await expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
69
74
  });
70
75
 
71
76
  it('should throw an error if an error which isnt related to permissions occurred', async () => {
@@ -73,7 +78,7 @@ describe('npmWrapper', () => {
73
78
 
74
79
  stubExecRejection(execErr);
75
80
 
76
- expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
81
+ await expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
77
82
  });
78
83
 
79
84
  it('should throw an error if stderr includes "EACCES", but the path was not specified', async () => {
@@ -81,7 +86,7 @@ describe('npmWrapper', () => {
81
86
 
82
87
  stubExecRejection(execErr);
83
88
 
84
- expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
89
+ await expect(npmWrapper.installPackageLocally('/some/dir', 'some-package')).to.be.rejectedWith(execErr);
85
90
  });
86
91
 
87
92
  [
@@ -194,5 +199,176 @@ Testim had missing write access to ${expectedPath}
194
199
  expect(fs.existsSync(unexpectedDir), 'expected the package not to be installed - this could be a problem with the test itself, and not the tested class').to.be.false;
195
200
  }).timeout(20000);
196
201
  });
202
+
203
+ describe('shirnkwrap handling', () => {
204
+ let fakeChildProcess;
205
+ let fakeLogger;
206
+ let originalConsole;
207
+ const shrinkwrapPath = '/some/dir/npm-shrinkwrap.json';
208
+ const shrinkwrapDummyPath = '/some/dir/npm-shrinkwrap-dummy.json';
209
+ beforeEach(() => {
210
+ fakeChildProcess = { exec: sinon.stub() };
211
+ fakeLogger = { warn: sinon.stub(), info: sinon.stub() };
212
+ originalConsole = global.console;
213
+ global.console = { log: sinon.stub(), error: sinon.stub() };
214
+ });
215
+
216
+ afterEach(() => {
217
+ global.console = originalConsole;
218
+ });
219
+
220
+ it('does not call rename if access fails', async () => {
221
+ const fakeFS = {
222
+ promises: {
223
+ access: sinon.stub(),
224
+ rename: sinon.stub(),
225
+ },
226
+ };
227
+ fakeFS.promises.access.rejects();
228
+ const npmWrapper = proxyquire('./npmWrapper', {
229
+ child_process: fakeChildProcess,
230
+ fs: fakeFS,
231
+ './logger': { getLogger: () => fakeLogger },
232
+ });
233
+
234
+ fakeChildProcess.exec.yields(undefined, []); //resolve without errors
235
+ const cwd = '/some/dir';
236
+ const pkg = 'some-package';
237
+ await npmWrapper.installPackageLocally(cwd, pkg);
238
+ sinon.assert.calledOnce(fakeFS.promises.access);
239
+ sinon.assert.notCalled(fakeFS.promises.rename);
240
+ expect(fakeFS.promises.access.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
241
+ });
242
+
243
+ it('calls rename once if rename fails on the first time', async () => {
244
+ const fakeFS = {
245
+ promises: {
246
+ access: sinon.stub().resolves(),
247
+ rename: sinon.stub().rejects(),
248
+ },
249
+ };
250
+
251
+ const npmWrapper = proxyquire('./npmWrapper', {
252
+ child_process: fakeChildProcess,
253
+ fs: fakeFS,
254
+ './logger': { getLogger: () => fakeLogger },
255
+ });
256
+
257
+ fakeChildProcess.exec.yields(undefined, []); //resolve without errors
258
+ const cwd = '/some/dir';
259
+ const pkg = 'some-package';
260
+ await npmWrapper.installPackageLocally(cwd, pkg);
261
+ sinon.assert.calledOnce(fakeFS.promises.access);
262
+ sinon.assert.calledOnce(fakeFS.promises.rename);
263
+ });
264
+
265
+ it('calls rename twice if first is success', async () => {
266
+ const fakeFS = {
267
+ promises: {
268
+ access: sinon.stub().resolves(),
269
+ rename: sinon.stub().resolves(),
270
+ },
271
+ };
272
+ const npmWrapper = proxyquire('./npmWrapper', {
273
+ child_process: fakeChildProcess,
274
+ fs: fakeFS,
275
+ './logger': { getLogger: () => fakeLogger },
276
+ });
277
+
278
+ fakeChildProcess.exec.yields(undefined, []); //resolve without errors
279
+ const cwd = '/some/dir';
280
+ const pkg = 'some-package';
281
+
282
+ await npmWrapper.installPackageLocally(cwd, pkg);
283
+ sinon.assert.calledOnce(fakeFS.promises.access);
284
+ sinon.assert.calledTwice(fakeFS.promises.rename);
285
+ expect(fakeFS.promises.access.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
286
+ expect(fakeFS.promises.rename.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
287
+ expect(fakeFS.promises.rename.getCall(0).args[1]).to.be.equal(shrinkwrapDummyPath);
288
+ expect(fakeFS.promises.rename.getCall(1).args[0]).to.be.equal(shrinkwrapDummyPath);
289
+ expect(fakeFS.promises.rename.getCall(1).args[1]).to.be.equal(shrinkwrapPath);
290
+ });
291
+
292
+ it('doesn\'t throw if first rename fails', async () => {
293
+ const fakeFS = {
294
+ promises: {
295
+ access: sinon.stub().resolves(true),
296
+ rename: sinon.stub().rejects(),
297
+ },
298
+ };
299
+ const npmWrapper = proxyquire('./npmWrapper', {
300
+ child_process: fakeChildProcess,
301
+ fs: fakeFS,
302
+ './logger': { getLogger: () => fakeLogger },
303
+ });
304
+
305
+ fakeChildProcess.exec.yields(undefined, []); //resolve without errors
306
+ const cwd = '/some/dir';
307
+ const pkg = 'some-package';
308
+ await npmWrapper.installPackageLocally(cwd, pkg);
309
+ sinon.assert.calledOnce(fakeFS.promises.access);
310
+ sinon.assert.calledOnce(fakeFS.promises.rename);
311
+ expect(fakeFS.promises.access.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
312
+ expect(fakeFS.promises.rename.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
313
+ expect(fakeFS.promises.rename.getCall(0).args[1]).to.be.equal(shrinkwrapDummyPath);
314
+ });
315
+
316
+ it('doesn\'t throw is second rename fails', async () => {
317
+ const fakeFS = {
318
+ promises: {
319
+ access: sinon.stub().resolves(),
320
+ rename: sinon.stub().onFirstCall().resolves().onSecondCall()
321
+ .rejects(),
322
+ },
323
+ };
324
+
325
+ const npmWrapper = proxyquire('./npmWrapper', {
326
+ child_process: fakeChildProcess,
327
+ fs: fakeFS,
328
+ './logger': { getLogger: () => fakeLogger },
329
+ });
330
+
331
+ fakeChildProcess.exec.yields(undefined, []); //resolve without errors
332
+ const cwd = '/some/dir';
333
+ const pkg = 'some-package';
334
+ await npmWrapper.installPackageLocally(cwd, pkg);
335
+ sinon.assert.calledOnce(fakeFS.promises.access);
336
+ sinon.assert.calledTwice(fakeFS.promises.rename);
337
+ expect(fakeFS.promises.access.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
338
+ expect(fakeFS.promises.rename.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
339
+ expect(fakeFS.promises.rename.getCall(0).args[1]).to.be.equal(shrinkwrapDummyPath);
340
+ expect(fakeFS.promises.rename.getCall(1).args[0]).to.be.equal(shrinkwrapDummyPath);
341
+ expect(fakeFS.promises.rename.getCall(1).args[1]).to.be.equal(shrinkwrapPath);
342
+ });
343
+
344
+ it('calls rename even if exec fails', async () => {
345
+ const fakeFS = {
346
+ promises: {
347
+ access: sinon.stub().resolves(),
348
+ rename: sinon.stub().onFirstCall().resolves().onSecondCall()
349
+ .rejects(),
350
+ },
351
+ };
352
+
353
+ fakeChildProcess.exec.throws();
354
+
355
+ const npmWrapper = proxyquire('./npmWrapper', {
356
+ child_process: fakeChildProcess,
357
+ fs: fakeFS,
358
+ './logger': { getLogger: () => fakeLogger },
359
+ });
360
+
361
+ const cwd = '/some/dir';
362
+ const pkg = 'some-package';
363
+ await expect(npmWrapper.installPackageLocally(cwd, pkg)).to.be.rejected;
364
+ sinon.assert.calledOnce(fakeFS.promises.access);
365
+ sinon.assert.calledTwice(fakeFS.promises.rename);
366
+ expect(fakeFS.promises.access.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
367
+ expect(fakeFS.promises.rename.getCall(0).args[0]).to.be.equal(shrinkwrapPath);
368
+ expect(fakeFS.promises.rename.getCall(0).args[1]).to.be.equal(shrinkwrapDummyPath);
369
+ expect(fakeFS.promises.rename.getCall(1).args[0]).to.be.equal(shrinkwrapDummyPath);
370
+ expect(fakeFS.promises.rename.getCall(1).args[1]).to.be.equal(shrinkwrapPath);
371
+ });
372
+ });
197
373
  });
198
374
  });
package/executionQueue.js CHANGED
@@ -3,8 +3,8 @@
3
3
  const TestRun = require('./testRunHandler.js');
4
4
 
5
5
  class ExecutionQueue {
6
- constructor(executionId, testList, options, branchToUse, testStatus) {
7
- this._waitingTests = testList.map(testInfo => new TestRun(executionId, testInfo, options, branchToUse, testStatus));
6
+ constructor(executionId, executionName, testList, options, branchToUse, testStatus) {
7
+ this._waitingTests = testList.map(testInfo => new TestRun(executionId, executionName, testInfo, options, branchToUse, testStatus));
8
8
  }
9
9
 
10
10
  getNext() {