@testim/testim-cli 3.197.0 → 3.198.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.
- package/commons/npmWrapper.js +46 -14
- package/commons/npmWrapper.test.js +182 -6
- package/npm-shrinkwrap.json +14 -14
- package/package.json +1 -1
- package/player/stepActions/salesforceApexActionStepAction.js +9 -0
- package/player/stepActions/salesforceAutoLoginStepAction.js +1 -1
- package/player/stepActions/stepActionRegistrar.js +4 -1
- package/testRunHandler.js +15 -1
- package/testRunStatus.js +4 -4
- package/workers/BaseWorker.js +1 -0
package/commons/npmWrapper.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/npm-shrinkwrap.json
CHANGED
|
@@ -1514,9 +1514,9 @@
|
|
|
1514
1514
|
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
|
|
1515
1515
|
},
|
|
1516
1516
|
"asn1": {
|
|
1517
|
-
"version": "0.2.
|
|
1518
|
-
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.
|
|
1519
|
-
"integrity": "sha512-
|
|
1517
|
+
"version": "0.2.6",
|
|
1518
|
+
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
|
1519
|
+
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
|
1520
1520
|
"requires": {
|
|
1521
1521
|
"safer-buffer": "~2.1.0"
|
|
1522
1522
|
}
|
|
@@ -1873,13 +1873,13 @@
|
|
|
1873
1873
|
"dev": true
|
|
1874
1874
|
},
|
|
1875
1875
|
"browserslist": {
|
|
1876
|
-
"version": "4.17.
|
|
1877
|
-
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.
|
|
1878
|
-
"integrity": "sha512-
|
|
1876
|
+
"version": "4.17.6",
|
|
1877
|
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz",
|
|
1878
|
+
"integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==",
|
|
1879
1879
|
"dev": true,
|
|
1880
1880
|
"requires": {
|
|
1881
|
-
"caniuse-lite": "^1.0.
|
|
1882
|
-
"electron-to-chromium": "^1.3.
|
|
1881
|
+
"caniuse-lite": "^1.0.30001274",
|
|
1882
|
+
"electron-to-chromium": "^1.3.886",
|
|
1883
1883
|
"escalade": "^3.1.1",
|
|
1884
1884
|
"node-releases": "^2.0.1",
|
|
1885
1885
|
"picocolors": "^1.0.0"
|
|
@@ -2033,9 +2033,9 @@
|
|
|
2033
2033
|
"dev": true
|
|
2034
2034
|
},
|
|
2035
2035
|
"caniuse-lite": {
|
|
2036
|
-
"version": "1.0.
|
|
2037
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
|
2038
|
-
"integrity": "sha512
|
|
2036
|
+
"version": "1.0.30001278",
|
|
2037
|
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001278.tgz",
|
|
2038
|
+
"integrity": "sha512-mpF9KeH8u5cMoEmIic/cr7PNS+F5LWBk0t2ekGT60lFf0Wq+n9LspAj0g3P+o7DQhD3sUdlMln4YFAWhFYn9jg==",
|
|
2039
2039
|
"dev": true
|
|
2040
2040
|
},
|
|
2041
2041
|
"caseless": {
|
|
@@ -3172,9 +3172,9 @@
|
|
|
3172
3172
|
"integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ=="
|
|
3173
3173
|
},
|
|
3174
3174
|
"electron-to-chromium": {
|
|
3175
|
-
"version": "1.3.
|
|
3176
|
-
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.
|
|
3177
|
-
"integrity": "sha512
|
|
3175
|
+
"version": "1.3.890",
|
|
3176
|
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.890.tgz",
|
|
3177
|
+
"integrity": "sha512-VWlVXSkv0cA/OOehrEyqjUTHwV8YXCPTfPvbtoeU2aHR21vI4Ejh5aC4AxUwOmbLbBgb6Gd3URZahoCxtBqCYQ==",
|
|
3178
3178
|
"dev": true
|
|
3179
3179
|
},
|
|
3180
3180
|
"emoji-regex": {
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@ class SalesforceAutoLoginStepAction extends NavigationStepAction {
|
|
|
19
19
|
var done = arguments[1];
|
|
20
20
|
done();
|
|
21
21
|
`, timeout);
|
|
22
|
-
await Promise.delay(
|
|
22
|
+
await Promise.delay(5000);
|
|
23
23
|
newUrl = await this.driver.getUrl(); // If we managed to continue correctly we want to get the new redirected url
|
|
24
24
|
}
|
|
25
25
|
await Promise.delay(700);
|
|
@@ -21,9 +21,11 @@ const RefreshStepAction = require('./RefreshStepAction');
|
|
|
21
21
|
const ApiStepAction = require('./apiStepAction');
|
|
22
22
|
const ExtractTextStepAction = require('./extractTextStepAction');
|
|
23
23
|
const TdkHybridStepAction = require('./tdkHybridStepAction');
|
|
24
|
-
const SalesforceAutoLoginStepAction = require('./salesforceAutoLoginStepAction');
|
|
25
24
|
const PixelValidationStepAction = require('./pixelValidationStepAction');
|
|
26
25
|
|
|
26
|
+
const SalesforceAutoLoginStepAction = require('./salesforceAutoLoginStepAction');
|
|
27
|
+
const SalesforceApexActionStepAction = require('./salesforceApexActionStepAction');
|
|
28
|
+
|
|
27
29
|
const CliJsStepAction = require('./cliJsStepAction');
|
|
28
30
|
const CliConditionStepAction = require('./cliConditionStepAction');
|
|
29
31
|
const NodePackageStepAction = require('./nodePackageStepAction');
|
|
@@ -85,6 +87,7 @@ module.exports = function (driver, stepActionFactory, runMode) {
|
|
|
85
87
|
'tdk-hybrid': TdkHybridStepAction,
|
|
86
88
|
|
|
87
89
|
'salesforce-autologin': SalesforceAutoLoginStepAction,
|
|
90
|
+
'salesforce-apex-action': SalesforceApexActionStepAction,
|
|
88
91
|
};
|
|
89
92
|
|
|
90
93
|
register(STEP_ACTION_MAPPING, stepActionFactory);
|
package/testRunHandler.js
CHANGED
|
@@ -7,6 +7,7 @@ const testimServicesApi = require('./commons/testimServicesApi');
|
|
|
7
7
|
const { timeoutMessages, CLI_MODE } = require('./commons/constants');
|
|
8
8
|
const logger = require('./commons/logger').getLogger('test-run-handler');
|
|
9
9
|
const perf = require('./commons/performance-logger');
|
|
10
|
+
const { URL } = require('url');
|
|
10
11
|
const Promise = require('bluebird');
|
|
11
12
|
const _ = require('lodash');
|
|
12
13
|
const remoteStepPlayback = require('./stepPlayers/remoteStepPlayback');
|
|
@@ -316,6 +317,19 @@ TestRun.prototype.isRetryKeyMismatch = function (testResult) {
|
|
|
316
317
|
return testResult.testRetryKey && (testResult.testRetryKey !== this.getRetryKey());
|
|
317
318
|
};
|
|
318
319
|
|
|
320
|
+
TestRun.prototype.validateRunConfig = function () {
|
|
321
|
+
const baseUrl = this.getBaseUrl();
|
|
322
|
+
const { browserValue } = this.getRunConfig();
|
|
323
|
+
|
|
324
|
+
if (baseUrl) {
|
|
325
|
+
const { username, password } = new URL(baseUrl);
|
|
326
|
+
|
|
327
|
+
if (browserValue === 'safari' && (username || password)) {
|
|
328
|
+
throw new Error('Basic authentication in URL is not supported in Safari');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
319
333
|
TestRun.prototype.onStarted = function (startTimeout) {
|
|
320
334
|
return new Promise(resolve => {
|
|
321
335
|
// We can't leave the test result as it may remove other listeners as well
|
|
@@ -467,7 +481,7 @@ TestRun.prototype.onCompleted = function () {
|
|
|
467
481
|
waitForTestEnd();
|
|
468
482
|
}
|
|
469
483
|
} catch (err) {
|
|
470
|
-
logger.error('failed to check is complete', {err});
|
|
484
|
+
logger.error('failed to check is complete', { err });
|
|
471
485
|
waitForTestEnd();
|
|
472
486
|
}
|
|
473
487
|
}, 3000);
|
package/testRunStatus.js
CHANGED
|
@@ -23,11 +23,11 @@ const gitRepoUrl = process.env.GIT_URL || process.env.CIRCLE_REPOSITORY_URL;
|
|
|
23
23
|
const runnerVersion = utils.getRunnerVersion();
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
function runHook(fn,
|
|
26
|
+
function runHook(fn, ...args) {
|
|
27
27
|
if (!fn || typeof fn !== 'function') {
|
|
28
28
|
return Promise.resolve();
|
|
29
29
|
}
|
|
30
|
-
return Promise.try(() => fn(
|
|
30
|
+
return Promise.try(() => fn(...args) || {}).catch(err => {
|
|
31
31
|
logger.warn('failed to run hook', { err });
|
|
32
32
|
throw new ArgError(`failed to run hook promise ${err.message}`);
|
|
33
33
|
});
|
|
@@ -181,7 +181,7 @@ RunStatus.prototype.testStartReport = function (test, executionId, testRetryKey)
|
|
|
181
181
|
if (utils.isQuarantineAndNotRemoteRun(test, this.options)) {
|
|
182
182
|
return Promise.resolve();
|
|
183
183
|
}
|
|
184
|
-
return runHook(this.options.beforeTest, Object.assign({}, test, { exportsGlobal: this.exportsGlobal }))
|
|
184
|
+
return runHook(this.options.beforeTest, Object.assign({}, test, { exportsGlobal: this.exportsGlobal }), this.options.userData.loginData.token)
|
|
185
185
|
.then(params => {
|
|
186
186
|
this.options.runParams[test.resultId] = test.config.testData = Object.assign({}, test.config.testData, this.exportsGlobal, this.fileUserParamsData, this.beforeSuiteParams, params);
|
|
187
187
|
test.startTime = Date.now();
|
|
@@ -278,7 +278,7 @@ RunStatus.prototype.testEndReport = async function (test, executionId, result, t
|
|
|
278
278
|
const globalParameters = result.exportsGlobal;
|
|
279
279
|
try {
|
|
280
280
|
try {
|
|
281
|
-
await runHook(this.options.afterTest, Object.assign({}, test, { globalParameters }));
|
|
281
|
+
await runHook(this.options.afterTest, Object.assign({}, test, { globalParameters }), this.options.userData.loginData.token);
|
|
282
282
|
} catch (err) {
|
|
283
283
|
logger.error('HOOK threw an error', { test: test.testId, err });
|
|
284
284
|
// eslint-disable-next-line no-console
|
package/workers/BaseWorker.js
CHANGED
|
@@ -387,6 +387,7 @@ class BaseWorker {
|
|
|
387
387
|
!disableRemoteStep && remoteStepService.joinToRemoteStep(this.testResultId),
|
|
388
388
|
!disableResults && testResultService.joinToTestResult(this.testResultId, this.testId),
|
|
389
389
|
])
|
|
390
|
+
.then(() => testRunHandler.validateRunConfig())
|
|
390
391
|
.then(() => this.runTest(testRunHandler, this.customExtensionLocalLocation, shouldRerun))
|
|
391
392
|
.then(testResult => onRunComplete(testResult, testRunHandler))
|
|
392
393
|
.then(result => {
|