@testim/testim-cli 3.253.0 → 3.255.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/OverrideTestDataBuilder.js +1 -1
- package/agent/routers/cliJsCode/index.js +4 -4
- package/agent/routers/cliJsCode/router.js +46 -42
- package/agent/routers/cliJsCode/service.js +18 -13
- package/agent/routers/codim/router.js +14 -17
- package/agent/routers/codim/router.test.js +19 -21
- package/agent/routers/codim/service.js +16 -16
- package/agent/routers/general/index.js +4 -8
- package/agent/routers/hybrid/registerRoutes.js +18 -18
- package/agent/routers/index.js +7 -7
- package/agent/routers/playground/router.js +11 -10
- package/agent/routers/playground/service.js +22 -23
- package/agent/routers/standalone-browser/registerRoutes.js +10 -10
- package/cdpTestRunner.js +4 -3
- package/chromiumInstaller.js +4 -5
- package/cli/onExit.js +2 -2
- package/cli.js +11 -10
- package/cliAgentMode.js +8 -8
- package/codim/codim-cli.js +20 -17
- package/codim/hybrid-utils.js +1 -1
- package/codim/measure-perf.js +9 -6
- package/codim/template.js/tests/examples/01-simple-text-validation.test.js +6 -6
- package/codim/template.js/tests/examples/02-using-locators.test.js +13 -15
- package/codim/template.js/tests/examples/03-using-hooks.test.js +17 -19
- package/codim/template.js/tests/examples/04-skip-and-only.test.js +16 -17
- package/codim/template.js/tests/examples/05-multiple-windows.test.js +16 -17
- package/codim/template.js/webpack.config.js +1 -1
- package/codim/template.ts/webpack.config.js +3 -3
- package/commons/AbortError.js +4 -4
- package/commons/detectDebugger.js +4 -2
- package/commons/featureFlags.js +8 -0
- package/commons/httpRequest.js +5 -1
- package/commons/httpRequestCounters.js +21 -10
- package/commons/lazyRequire.js +14 -12
- package/commons/logger.js +4 -4
- package/commons/performance-logger.js +14 -8
- package/commons/preloadTests.js +2 -2
- package/commons/prepareRunner.js +4 -2
- package/commons/prepareRunnerAndTestimStartUtils.js +40 -42
- package/commons/runnerFileCache.js +1 -1
- package/commons/socket/baseSocketServiceSocketIO.js +32 -34
- package/commons/socket/realDataService.js +6 -5
- package/commons/socket/realDataServiceSocketIO.js +4 -4
- package/commons/socket/remoteStepService.js +4 -3
- package/commons/socket/remoteStepServiceSocketIO.js +11 -12
- package/commons/socket/socketService.js +50 -52
- package/commons/socket/testResultServiceSocketIO.js +11 -11
- package/commons/testimDesiredCapabilitiesBuilder.js +3 -2
- package/commons/testimNgrok.js +2 -2
- package/commons/testimNgrok.test.js +1 -1
- package/commons/testimServicesApi.js +27 -20
- package/commons/testimTunnel.test.js +2 -1
- package/commons/xhr2.js +97 -100
- package/coverage/SummaryToObjectReport.js +0 -1
- package/coverage/jsCoverage.js +12 -10
- package/errors.js +5 -0
- package/fixLocalBuild.js +2 -0
- package/inputFileUtils.js +11 -9
- package/npm-shrinkwrap.json +2286 -1284
- package/package.json +9 -8
- package/player/appiumTestPlayer.js +1 -1
- package/player/chromeLauncherTestPlayer.js +0 -1
- package/player/services/tabService.js +15 -1
- package/player/services/tabServiceMock.js +166 -0
- package/player/stepActions/locateStepAction.js +2 -0
- package/player/stepActions/navigationStepAction.js +11 -10
- package/player/stepActions/sleepStepAction.js +4 -5
- package/player/stepActions/textStepAction.js +4 -11
- package/player/utils/imageCaptureUtils.js +81 -120
- package/player/utils/windowUtils.js +4 -3
- package/player/webdriver.js +26 -23
- package/processHandler.js +3 -3
- package/processHandler.test.js +1 -1
- package/reports/consoleReporter.js +3 -2
- package/reports/junitReporter.js +7 -9
- package/reports/reporter.js +34 -39
- package/runOptions.d.ts +260 -0
- package/runOptions.js +59 -44
- package/runner.js +14 -0
- package/runners/ParallelWorkerManager.js +9 -10
- package/runners/TestPlanRunner.js +142 -78
- package/runners/buildCodeTests.js +38 -37
- package/runners/runnerUtils.js +3 -3
- package/services/gridService.js +36 -40
- package/services/lambdatestService.js +3 -5
- package/stepPlayers/cliJsStepPlayback.js +22 -17
- package/testRunHandler.js +8 -0
- package/testRunStatus.js +9 -6
- package/utils/argsUtils.js +86 -0
- package/utils/argsUtils.test.js +32 -0
- package/utils/fsUtils.js +154 -0
- package/{utils.js → utils/index.js} +19 -262
- package/utils/promiseUtils.js +89 -0
- package/utils/stringUtils.js +98 -0
- package/utils/stringUtils.test.js +22 -0
- package/utils/timeUtils.js +25 -0
- package/utils/utils.test.js +27 -0
- package/workers/BaseWorker.js +16 -14
- package/workers/WorkerAppium.js +1 -1
- package/workers/WorkerExtension.js +6 -7
- package/workers/WorkerExtensionSingleBrowser.js +4 -4
- package/workers/WorkerSelenium.js +5 -2
- package/utils.test.js +0 -68
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const router = require('./router');
|
|
4
4
|
const service = require('./service');
|
|
5
|
-
const logger = require('../../../commons/logger').getLogger(
|
|
5
|
+
const logger = require('../../../commons/logger').getLogger('cli-service');
|
|
6
6
|
|
|
7
7
|
// clean local
|
|
8
8
|
service.cleanLocalPackageInstallFolder()
|
|
9
|
-
.catch(err => logger.warn(
|
|
9
|
+
.catch(err => logger.warn('failed to clean local package folder', { err }));
|
|
10
10
|
|
|
11
11
|
module.exports = {
|
|
12
|
-
router
|
|
12
|
+
router,
|
|
13
13
|
};
|
|
@@ -1,60 +1,64 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { TimeoutError } = require('bluebird');
|
|
4
6
|
const express = require('express');
|
|
5
7
|
const service = require('./service');
|
|
6
|
-
const {NpmPackageError} = require('../../../errors');
|
|
7
|
-
const logger = require('../../../commons/logger').getLogger(
|
|
8
|
+
const { NpmPackageError } = require('../../../errors');
|
|
9
|
+
const logger = require('../../../commons/logger').getLogger('cli-router');
|
|
8
10
|
const chalk = require('chalk');
|
|
9
11
|
|
|
10
12
|
const router = express.Router();
|
|
11
13
|
|
|
12
|
-
router.post('/run', (req, res) => {
|
|
13
|
-
const {code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, timeout, fileDataUrl} = req.body;
|
|
14
|
+
router.post('/run', async (req, res) => {
|
|
15
|
+
const { code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, timeout, fileDataUrl } = req.body;
|
|
14
16
|
|
|
15
|
-
if (typeof code !==
|
|
16
|
-
|
|
17
|
+
if (typeof code !== 'string' || !stepId || !incomingParams || !context || !testResultId || typeof retryIndex !== 'number' || !stepResultId || typeof timeout !== 'number') {
|
|
18
|
+
res.status(400).json({ success: false, code: 'invalid-params' });
|
|
19
|
+
return;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
22
|
+
try {
|
|
23
|
+
const data = await service.runCodeWithPackages(code, stepId, incomingParams, context, testResultId, retryIndex, stepResultId, timeout, fileDataUrl);
|
|
24
|
+
if (!data.success) {
|
|
25
|
+
console.log(chalk.red(data.result.resultValue));
|
|
26
|
+
logger.error('CLI Action Failure', { message: data.result.resultValue });
|
|
27
|
+
}
|
|
28
|
+
res.status(200).json({ success: true, data });
|
|
29
|
+
} catch (err) {
|
|
30
|
+
logger.error('failed to run cli code', { err });
|
|
31
|
+
console.log(chalk.red('failed to run cli code', err));
|
|
32
|
+
res.status(500).json({ success: false, code: 'internal-error' });
|
|
33
|
+
}
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
router.post('/install', (req, res) => {
|
|
35
|
-
const {stepId, testResultId, retryIndex, packageData, stepResultId, timeout} = req.body;
|
|
36
|
+
router.post('/install', async (req, res) => {
|
|
37
|
+
const { stepId, testResultId, retryIndex, packageData, stepResultId, timeout } = req.body;
|
|
36
38
|
|
|
37
|
-
if (!stepId || typeof packageData !==
|
|
38
|
-
|
|
39
|
+
if (!stepId || typeof packageData !== 'object' || !testResultId || typeof retryIndex !== 'number' || !stepResultId || typeof timeout !== 'number') {
|
|
40
|
+
res.status(400).json({ success: false, code: 'invalid-params' });
|
|
41
|
+
return;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
logger.error(
|
|
48
|
-
res.status(200).json({success: false, code:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
});
|
|
44
|
+
try {
|
|
45
|
+
const data = await service.installPackage(stepId, testResultId, retryIndex, packageData, stepResultId, timeout);
|
|
46
|
+
logger.info('installed packages successfully');
|
|
47
|
+
res.status(200).json({ success: true, data });
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (err instanceof NpmPackageError) {
|
|
50
|
+
logger.error('failed to install node packages', { err });
|
|
51
|
+
res.status(200).json({ success: false, code: 'invalid-node-package', message: err.message });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (err instanceof TimeoutError) {
|
|
55
|
+
logger.error('timeout installing node package');
|
|
56
|
+
res.status(200).json({ success: false, code: 'timeout' });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
logger.error('failed to install node packages', { err });
|
|
60
|
+
res.status(500).json({ success: false, code: 'internal-error' });
|
|
61
|
+
}
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
module.exports = router;
|
|
@@ -11,6 +11,7 @@ const logger = require('../../../commons/logger').getLogger('cli-service');
|
|
|
11
11
|
const { getS3Artifact } = require('../../../commons/testimServicesApi');
|
|
12
12
|
const npmWrapper = require('../../../commons/npmWrapper');
|
|
13
13
|
const featureFlags = require('../../../commons/featureFlags');
|
|
14
|
+
const { TimeoutError } = require('../../../errors');
|
|
14
15
|
|
|
15
16
|
let workerThreads;
|
|
16
17
|
|
|
@@ -587,22 +588,22 @@ function runCodeWithPackages(code, stepId, incomingParams, context, testResultId
|
|
|
587
588
|
}).then(res => Object.assign({}, res, { nodeVersion: process.version }));
|
|
588
589
|
}
|
|
589
590
|
|
|
590
|
-
function runNpmInstall(transactionId, packageData, timeout) {
|
|
591
|
+
async function runNpmInstall(transactionId, packageData, timeout) {
|
|
591
592
|
const packages = packageData.map(data => `${data.packageName}@${data.packageVersion}`);
|
|
592
593
|
const localPackageInstallFolder = getLocalPackageInstallFolder();
|
|
593
594
|
const installFolder = path.join(localPackageInstallFolder, `/${transactionId}`);
|
|
594
595
|
const proxyUri = global.proxyUri;
|
|
595
596
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
return new Promise(async (resolve, reject) => {
|
|
597
|
+
|
|
598
|
+
async function npmInstallation() {
|
|
599
599
|
let output = '';
|
|
600
600
|
try {
|
|
601
601
|
output = await npmWrapper.installPackages(installFolder, packages, proxyUri, timeout);
|
|
602
602
|
logger.info('npm package install finished', { transactionId, output, timeout });
|
|
603
603
|
if (Number(output.trim().split(' ')[1]) < packages.length) {
|
|
604
|
-
|
|
605
|
-
|
|
604
|
+
// TODO: I am not sure changing this to an error would be safe.
|
|
605
|
+
// eslint-disable-next-line no-throw-literal
|
|
606
|
+
throw 'npm package install failed, couldn\'t install all packages';
|
|
606
607
|
}
|
|
607
608
|
const packageDataWithVersions = packageData.map(pData => {
|
|
608
609
|
const version = npmWrapper.getLocallyInstalledPackageVersion(installFolder, pData.packageName);
|
|
@@ -614,17 +615,21 @@ function runNpmInstall(transactionId, packageData, timeout) {
|
|
|
614
615
|
});
|
|
615
616
|
});
|
|
616
617
|
|
|
617
|
-
|
|
618
|
+
return { data: packageDataWithVersions, installFolder };
|
|
618
619
|
} catch (err) {
|
|
619
620
|
logger.warn('npm package install failed', { transactionId, err });
|
|
620
|
-
|
|
621
|
+
throw err;
|
|
621
622
|
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
try {
|
|
626
|
+
return await utils.promiseTimeout(npmInstallation(), timeout);
|
|
627
|
+
} catch (err) {
|
|
628
|
+
if (err instanceof TimeoutError) {
|
|
625
629
|
logger.warn('timeout to install package', { packages, transactionId, err, timeout });
|
|
626
|
-
|
|
627
|
-
|
|
630
|
+
}
|
|
631
|
+
throw err;
|
|
632
|
+
}
|
|
628
633
|
}
|
|
629
634
|
|
|
630
635
|
function getLocalPackageInstallFolder() {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const express = require('express');
|
|
4
|
+
|
|
4
5
|
const router = express.Router();
|
|
5
|
-
const logger = require('../../../commons/logger').getLogger(
|
|
6
|
+
const logger = require('../../../commons/logger').getLogger('codim-router');
|
|
6
7
|
|
|
7
8
|
const {
|
|
8
9
|
findTests,
|
|
@@ -10,40 +11,39 @@ const {
|
|
|
10
11
|
getLocalLocatorContents,
|
|
11
12
|
saveTest,
|
|
12
13
|
saveLocators,
|
|
13
|
-
compileFunctionsLibrary
|
|
14
|
+
compileFunctionsLibrary,
|
|
14
15
|
} = require('./service');
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
router.get('/tests', async (req, res) => {
|
|
18
19
|
const tests = await findTests();
|
|
19
|
-
res.json({tests, success: true });
|
|
20
|
+
res.json({ tests, success: true });
|
|
20
21
|
});
|
|
21
22
|
router.get('/locators', async (req, res) => {
|
|
22
23
|
const locators = await getLocalLocators();
|
|
23
24
|
const contents = await getLocalLocatorContents(locators, req.query.full);
|
|
24
|
-
res.json({locators, contents, success: true });
|
|
25
|
+
res.json({ locators, contents, success: true });
|
|
25
26
|
});
|
|
26
27
|
router.post('/locators', async (req, res) => {
|
|
27
|
-
|
|
28
28
|
if (!req.body) {
|
|
29
|
-
res.status(400).send({success: false, reason: 'missing body' });
|
|
29
|
+
res.status(400).send({ success: false, reason: 'missing body' });
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
if (!req.body.locators) {
|
|
33
|
-
res.status(400).send({success: false, reason: 'missing locators' });
|
|
33
|
+
res.status(400).send({ success: false, reason: 'missing locators' });
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const { locators, mergeIntoExisting } = req.body;
|
|
38
38
|
|
|
39
39
|
await saveLocators(locators, { mergeIntoExisting: mergeIntoExisting || false });
|
|
40
|
-
res.status(200).send({ success: true })
|
|
40
|
+
res.status(200).send({ success: true });
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
router.get('/compile', async (req, res) => {
|
|
44
44
|
try {
|
|
45
45
|
const code = await compileFunctionsLibrary(req.body.name);
|
|
46
|
-
res.send({ success: true, code })
|
|
46
|
+
res.send({ success: true, code });
|
|
47
47
|
} catch (e) {
|
|
48
48
|
logger.error(e);
|
|
49
49
|
res.json({ success: false, reason: e.message });
|
|
@@ -51,20 +51,17 @@ router.get('/compile', async (req, res) => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
router.post('/saveTest', async (req, res) => {
|
|
54
|
-
|
|
55
54
|
if (!req.body) {
|
|
56
|
-
res.status(400).send({success: false, reason: 'missing body' });
|
|
55
|
+
res.status(400).send({ success: false, reason: 'missing body' });
|
|
57
56
|
return;
|
|
58
57
|
}
|
|
59
58
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
await saveTest(req.body);
|
|
60
|
+
res.send({ success: true });
|
|
62
61
|
} catch (e) {
|
|
63
|
-
res.json({success: false, reason: e.message });
|
|
62
|
+
res.json({ success: false, reason: e.message });
|
|
64
63
|
logger.error(e);
|
|
65
|
-
return;
|
|
66
64
|
}
|
|
67
|
-
|
|
68
65
|
});
|
|
69
66
|
|
|
70
67
|
|
|
@@ -1,62 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const router = require('./router');
|
|
4
|
-
|
|
5
4
|
const path = require('path');
|
|
6
5
|
const os = require('os');
|
|
7
6
|
const compression = require('compression');
|
|
8
7
|
const express = require('express');
|
|
9
|
-
const app = express();
|
|
10
8
|
const bodyParser = require('body-parser');
|
|
11
|
-
const Promise = require('bluebird');
|
|
12
9
|
const superagent = require('superagent');
|
|
13
|
-
const
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const { expect } = require('chai'); // eslint-disable-line import/no-extraneous-dependencies
|
|
14
12
|
|
|
15
|
-
const
|
|
13
|
+
const app = express();
|
|
16
14
|
|
|
17
|
-
app.use(bodyParser.urlencoded({extended: false, limit: '50mb'}));
|
|
15
|
+
app.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));
|
|
18
16
|
app.use(compression());
|
|
19
|
-
app.use(bodyParser.json({limit: '50mb'}));
|
|
17
|
+
app.use(bodyParser.json({ limit: '50mb' }));
|
|
20
18
|
|
|
21
19
|
app.use('/files', router.router);
|
|
22
20
|
|
|
23
21
|
describe('codim router', () => {
|
|
24
22
|
let listener;
|
|
25
23
|
async function saveLocators(locatorsObject) {
|
|
26
|
-
const request = superagent.post(`http://localhost:${listener.address().port}/files/locators`)
|
|
27
|
-
|
|
28
|
-
await Promise.fromCallback((callback) => request.end(callback));
|
|
24
|
+
const request = superagent.post(`http://localhost:${listener.address().port}/files/locators`).send(locatorsObject);
|
|
25
|
+
await request;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
async function loadLocators() {
|
|
32
29
|
const request = superagent.get(`http://localhost:${listener.address().port}/files/locators`);
|
|
33
|
-
|
|
30
|
+
const response = await request;
|
|
31
|
+
return JSON.parse(response.text);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
let tmpDir;
|
|
35
|
+
|
|
37
36
|
before((done) => {
|
|
38
37
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tdk-test-'));
|
|
39
38
|
process.chdir(tmpDir);
|
|
40
|
-
listener = app.listen(0, done);
|
|
39
|
+
listener = app.listen(0, () => done());
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
after(async () => {
|
|
44
|
-
await fs.
|
|
43
|
+
await fs.promises.unlink(tmpDir).catch(() => {});
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
it('saves locators', async () => {
|
|
48
47
|
await saveLocators({
|
|
49
|
-
locators: [{ id: 'foo', name: 'foo', body: {internal: 'bar' }}],
|
|
50
|
-
mergeIntoExisting: false
|
|
48
|
+
locators: [{ id: 'foo', name: 'foo', body: { internal: 'bar' } }],
|
|
49
|
+
mergeIntoExisting: false,
|
|
51
50
|
});
|
|
52
51
|
const locators = await loadLocators();
|
|
53
52
|
expect(locators).to.deep.eq({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
contents: {},
|
|
54
|
+
locators: {
|
|
55
|
+
foo: 'foo',
|
|
57
56
|
},
|
|
58
|
-
|
|
57
|
+
success: true,
|
|
59
58
|
});
|
|
60
59
|
});
|
|
61
|
-
|
|
62
60
|
});
|
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const
|
|
6
|
-
const fs = Promise.promisifyAll(require('fs'));
|
|
5
|
+
const fsPromises = require('fs/promises');
|
|
7
6
|
const { fromPairs } = require('lodash');
|
|
8
7
|
const { buildCodeTests } = require('../../../runners/buildCodeTests');
|
|
9
8
|
const { AbortError } = require('../../../commons/AbortError');
|
|
10
9
|
|
|
11
10
|
const findTestFolder = _.memoize(async (fromFolder) => {
|
|
12
|
-
const files = await
|
|
11
|
+
const files = await fsPromises.readdir(fromFolder);
|
|
13
12
|
// this is either invoked by running the Testim CLI from inside the tests folder or from inside the `init` folder
|
|
14
13
|
// so deal with the case we're inside tests.
|
|
15
|
-
const isInProjectFolder = files.
|
|
14
|
+
const isInProjectFolder = files.includes('tests') && (await fsPromises.stat(path.join(fromFolder, 'tests'))).isDirectory();
|
|
16
15
|
if (isInProjectFolder) {
|
|
17
16
|
return path.join(fromFolder, 'tests');
|
|
18
17
|
}
|
|
@@ -27,7 +26,7 @@ async function getLocalLocators() {
|
|
|
27
26
|
// eslint-disable-next-line no-eval
|
|
28
27
|
return eval(buffer.toString().replace(/require/g, '(x => /locator\.(.*)\.json/.exec(x)[1])'));
|
|
29
28
|
}
|
|
30
|
-
const locators = await
|
|
29
|
+
const locators = await fsPromises.readFile(locatorsFilePath).then(parseLocators, () => ({}));
|
|
31
30
|
return _(Object.keys(locators)).map((id) => {
|
|
32
31
|
const escapedId = id.replace(/"/g, '\\"');
|
|
33
32
|
return [escapedId, locators[id]];
|
|
@@ -36,7 +35,7 @@ async function getLocalLocators() {
|
|
|
36
35
|
|
|
37
36
|
async function findTests(folder = process.cwd()) {
|
|
38
37
|
const testFolder = await findTestFolder(folder);
|
|
39
|
-
const filesWithStat = await
|
|
38
|
+
const filesWithStat = await fsPromises.readdir(testFolder, { withFileTypes: true });
|
|
40
39
|
|
|
41
40
|
// things we know are not tests but end in js
|
|
42
41
|
const excluded = ['webpack.config.js', 'tsconfig.js', '.DS_Store', 'functions.js'];
|
|
@@ -70,13 +69,14 @@ async function getLocalLocatorContents(locators, full = false, originFolder = pr
|
|
|
70
69
|
if (full) {
|
|
71
70
|
const folder = await findTestFolder(originFolder);
|
|
72
71
|
for (const key of Object.values(locators)) {
|
|
73
|
-
props[key] =
|
|
72
|
+
props[key] = fsPromises.readFile(path.join(folder, 'locators', `locator.${key}.json`)).then(JSON.parse);
|
|
74
73
|
}
|
|
75
74
|
}
|
|
76
75
|
try {
|
|
77
76
|
const contents = await promiseFromProps(props);
|
|
78
77
|
return contents;
|
|
79
78
|
} catch (e) {
|
|
79
|
+
// eslint-disable-next-line no-console
|
|
80
80
|
console.error(e);
|
|
81
81
|
return {};
|
|
82
82
|
}
|
|
@@ -104,10 +104,10 @@ async function saveTest({
|
|
|
104
104
|
if (filename.endsWith('locators/locators.js')) {
|
|
105
105
|
throw new Error('Cannot override locators file from the internet as it is evaluated by the runner');
|
|
106
106
|
}
|
|
107
|
-
await
|
|
108
|
-
await
|
|
107
|
+
await fsPromises.writeFile(filename, body);
|
|
108
|
+
await fsPromises.mkdir(path.join(folder, 'locators')).catch(() => {});
|
|
109
109
|
for (const { id, body } of locators) {
|
|
110
|
-
await
|
|
110
|
+
await fsPromises.writeFile(path.join(folder, 'locators', `locator.${id}.json`), JSON.stringify(body));
|
|
111
111
|
}
|
|
112
112
|
const locatorMap = fromPairs(locators.map(({ name, id }) => [name, id]));
|
|
113
113
|
const localLocatorMap = await getLocalLocators();
|
|
@@ -120,15 +120,15 @@ async function writeLocators(locatorsFilePath, locatorMap) {
|
|
|
120
120
|
content += ` "${key}": require('./locator.${value}.json'),\n`;
|
|
121
121
|
}
|
|
122
122
|
content += '};';
|
|
123
|
-
await
|
|
123
|
+
await fsPromises.writeFile(locatorsFilePath, content);
|
|
124
124
|
}
|
|
125
125
|
async function saveLocators(locators, { mergeIntoExisting } = { mergeIntoExisting: false }) {
|
|
126
126
|
const folder = await findTestFolder(process.cwd());
|
|
127
127
|
const locatorsFilePath = path.join(folder, 'locators', 'locators.js');
|
|
128
|
-
await
|
|
128
|
+
await fsPromises.mkdir(path.join(folder, 'locators')).catch(() => {});
|
|
129
129
|
|
|
130
130
|
for (const { name, id, elementLocator } of locators) {
|
|
131
|
-
await
|
|
131
|
+
await fsPromises.writeFile(path.join(folder, 'locators', `locator.${id}.json`), JSON.stringify({ name, id, elementLocator }));
|
|
132
132
|
}
|
|
133
133
|
const locatorMap = fromPairs(locators.map(({ name, id }) => [name, id]));
|
|
134
134
|
if (mergeIntoExisting) {
|
|
@@ -139,14 +139,14 @@ async function saveLocators(locators, { mergeIntoExisting } = { mergeIntoExistin
|
|
|
139
139
|
await writeLocators(locatorsFilePath, locatorMap);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
async function compileFunctionsLibrary({ fileSystem, bypassWebpack } = {}, optionalAbortSignal) {
|
|
142
|
+
async function compileFunctionsLibrary({ fileSystem, bypassWebpack } = {}, optionalAbortSignal = undefined) {
|
|
143
143
|
const folder = await findTestFolder(process.cwd());
|
|
144
|
-
if (optionalAbortSignal
|
|
144
|
+
if (optionalAbortSignal?.aborted) {
|
|
145
145
|
throw new AbortError();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
const functionsFile = path.join(folder, 'functions.js');
|
|
149
|
-
if (bypassWebpack
|
|
149
|
+
if (bypassWebpack?.testim) {
|
|
150
150
|
const Module = require('module');
|
|
151
151
|
// attempt to require without webpack compile - useful for puppeteer/selenium hybrid
|
|
152
152
|
const originalRequire = Module.prototype.require;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const { getPackageVersion } = require('../../../testimNpmDriver');
|
|
4
4
|
const { doLogin } = require('../../../credentialsManager');
|
|
@@ -9,11 +9,9 @@ module.exports = (app) => {
|
|
|
9
9
|
* root endpoint
|
|
10
10
|
*/
|
|
11
11
|
app.get('/', (req, res) => {
|
|
12
|
-
|
|
13
12
|
const isStartMode = getStartedWithStart();
|
|
14
13
|
|
|
15
|
-
return res.status(200).json({success: true, isTestimAgent: true, startMode: isStartMode});
|
|
16
|
-
|
|
14
|
+
return res.status(200).json({ success: true, isTestimAgent: true, startMode: isStartMode });
|
|
17
15
|
});
|
|
18
16
|
|
|
19
17
|
/**
|
|
@@ -22,19 +20,17 @@ module.exports = (app) => {
|
|
|
22
20
|
app.get('/version', (req, res) => {
|
|
23
21
|
res.status(200).json({
|
|
24
22
|
node: process.version,
|
|
25
|
-
app: getPackageVersion()
|
|
23
|
+
app: getPackageVersion(),
|
|
26
24
|
});
|
|
27
25
|
});
|
|
28
26
|
|
|
29
27
|
app.get('/loginInfo', (req, res) => {
|
|
30
28
|
try {
|
|
31
29
|
const projects = JSON.parse(Buffer.from(req.query.info, 'base64').toString());
|
|
32
|
-
doLogin({overwriteExisting: false, projects });
|
|
30
|
+
doLogin({ overwriteExisting: false, projects });
|
|
33
31
|
res.status(200).end();
|
|
34
32
|
} catch (err) {
|
|
35
33
|
res.status(400).end();
|
|
36
34
|
}
|
|
37
35
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const service = require('../../../stepPlayers/hybridStepPlayback');
|
|
4
4
|
const express = require('express');
|
|
5
5
|
const lazyRequire = require('../../../commons/lazyRequire');
|
|
6
|
-
const logger = require('../../../commons/logger').getLogger(
|
|
6
|
+
const logger = require('../../../commons/logger').getLogger('hybrid-router');
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {{
|
|
@@ -16,7 +16,7 @@ module.exports.hybridRoutes = function hybridRoutes(testimStandaloneBrowser) {
|
|
|
16
16
|
router.post('/run', (req, res) => {
|
|
17
17
|
if (!req.body || !req.body.step) {
|
|
18
18
|
res.status(400).send({
|
|
19
|
-
error:
|
|
19
|
+
error: 'Missing step',
|
|
20
20
|
});
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
@@ -24,15 +24,15 @@ module.exports.hybridRoutes = function hybridRoutes(testimStandaloneBrowser) {
|
|
|
24
24
|
const {
|
|
25
25
|
step,
|
|
26
26
|
context,
|
|
27
|
-
loginData // is this safe to pass here?
|
|
27
|
+
loginData, // is this safe to pass here?
|
|
28
28
|
} = req.body;
|
|
29
29
|
if (!testimStandaloneBrowser.webdriverApi) {
|
|
30
|
-
res.status(503).send({success: false, reason: 'Testim Agent was not started with Testim Start.' });
|
|
30
|
+
res.status(503).send({ success: false, reason: 'Testim Agent was not started with Testim Start.' });
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// The step run might take very long time, and it will still be valid
|
|
34
34
|
// so we set here unlimited timeout
|
|
35
|
-
req.setTimeout(0)
|
|
35
|
+
req.setTimeout(0);
|
|
36
36
|
|
|
37
37
|
service.execute(
|
|
38
38
|
step,
|
|
@@ -41,18 +41,18 @@ module.exports.hybridRoutes = function hybridRoutes(testimStandaloneBrowser) {
|
|
|
41
41
|
loginData,
|
|
42
42
|
undefined, // don't pass frameManager,
|
|
43
43
|
'agent'
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
).then((result) => {
|
|
45
|
+
res.status(200).send(result);
|
|
46
|
+
}).catch(e => {
|
|
47
|
+
logger.error('failed to run hybrid code', { e });
|
|
48
|
+
res.status(500).send(Object.assign({ success: false, error: e }));
|
|
49
|
+
});
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
router.post('/abort', (req, res) => {
|
|
53
53
|
if (!req.body || !req.body.stepResultId) {
|
|
54
54
|
res.status(400).send({
|
|
55
|
-
error:
|
|
55
|
+
error: 'missing stepResultId',
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
return;
|
|
@@ -62,20 +62,20 @@ module.exports.hybridRoutes = function hybridRoutes(testimStandaloneBrowser) {
|
|
|
62
62
|
service.abort(req.body.stepResultId);
|
|
63
63
|
res.status(204).end();
|
|
64
64
|
} catch (e) {
|
|
65
|
-
if (e && e.message ===
|
|
65
|
+
if (e && e.message === 'No such stepResultId') {
|
|
66
66
|
res.status(400).send({
|
|
67
|
-
error:
|
|
67
|
+
error: 'No such stepResultId',
|
|
68
68
|
});
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
logger.error(
|
|
72
|
+
logger.error('hybrid code abort unexpected error', { e });
|
|
73
73
|
res.status(500).send({
|
|
74
|
-
error:
|
|
75
|
-
info: `${e ? e.message :
|
|
74
|
+
error: 'unexpected error',
|
|
75
|
+
info: `${e ? e.message : 'N/A'}`,
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
return router;
|
|
81
|
-
}
|
|
81
|
+
};
|
package/agent/routers/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const compression = require('compression');
|
|
4
4
|
const express = require('express');
|
|
@@ -7,14 +7,14 @@ const cors = require('cors');
|
|
|
7
7
|
const { IS_ON_PREM, DISABLE_AGENT_ORIGIN_CHECK } = require('../../commons/config');
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
module.exports = function(beforeMiddleware, standaloneBrowserInfo) {
|
|
10
|
+
module.exports = function (beforeMiddleware, standaloneBrowserInfo) {
|
|
11
11
|
const app = express();
|
|
12
12
|
beforeMiddleware(app);
|
|
13
13
|
|
|
14
14
|
// view engine setup
|
|
15
|
-
app.use(bodyParser.urlencoded({extended: false, limit: '50mb'}));
|
|
15
|
+
app.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));
|
|
16
16
|
app.use(compression());
|
|
17
|
-
app.use(bodyParser.json({limit: '50mb'}));
|
|
17
|
+
app.use(bodyParser.json({ limit: '50mb' }));
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* set cors options
|
|
@@ -27,8 +27,8 @@ module.exports = function(beforeMiddleware, standaloneBrowserInfo) {
|
|
|
27
27
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
28
28
|
credentials: true,
|
|
29
29
|
maxAge: 86400,
|
|
30
|
-
origin: (IS_ON_PREM || DISABLE_AGENT_ORIGIN_CHECK) ? '*' : whitelist
|
|
31
|
-
}
|
|
30
|
+
origin: (IS_ON_PREM || DISABLE_AGENT_ORIGIN_CHECK) ? '*' : whitelist,
|
|
31
|
+
};
|
|
32
32
|
app.use('*', cors(corsOptions));
|
|
33
33
|
|
|
34
34
|
// Routes
|
|
@@ -42,7 +42,7 @@ module.exports = function(beforeMiddleware, standaloneBrowserInfo) {
|
|
|
42
42
|
app.use('/cliJs', cliJsCode.router);
|
|
43
43
|
|
|
44
44
|
app.use('/standalone-browser',
|
|
45
|
-
require(
|
|
45
|
+
require('./standalone-browser/registerRoutes').standaloneBrowserRoutes(standaloneBrowserInfo)
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
app.use('/hybrid', require('./hybrid/registerRoutes').hybridRoutes(standaloneBrowserInfo));
|