@testim/testim-cli 3.285.0 → 3.287.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/agent/routers/cliJsCode/service.js +32 -9
- package/agent/routers/codim/service.js +10 -7
- package/cli/writeStackTrace.js +14 -13
- package/cli.js +12 -15
- package/commons/featureFlags.js +1 -0
- package/commons/getSessionPlayerRequire.js +23 -8
- package/commons/httpRequestCounters.js +2 -2
- package/commons/initializeUserWithAuth.js +1 -1
- package/commons/testimDesiredCapabilitiesBuilder.js +6 -1
- package/npm-shrinkwrap.json +2128 -964
- package/package.json +2 -2
- package/player/appiumTestPlayer.js +8 -20
- package/player/seleniumTestPlayer.js +10 -21
- package/player/services/frameLocator.js +4 -2
- package/player/services/tabService.js +13 -14
- package/player/stepActions/apiStepAction.js +6 -8
- package/player/stepActions/baseCliJsStepAction.js +3 -6
- package/player/stepActions/baseJsStepAction.js +10 -8
- package/player/stepActions/dropFileStepAction.js +5 -3
- package/player/stepActions/evaluateExpressionStepAction.js +6 -7
- package/player/stepActions/hoverStepAction.js +1 -3
- package/player/stepActions/inputFileStepAction.js +7 -6
- package/player/stepActions/locateStepAction.js +5 -6
- package/player/stepActions/mouseStepAction.js +9 -10
- package/player/stepActions/scrollStepAction.js +5 -7
- package/player/stepActions/selectOptionStepAction.js +3 -4
- package/player/stepActions/sfdcRecordedStepAction.js +1 -1
- package/player/stepActions/sfdcStepAction.js +1 -1
- package/player/stepActions/stepAction.js +7 -2
- package/player/stepActions/textStepAction.js +4 -7
- package/player/stepActions/textValidationStepAction.js +3 -10
- package/player/stepActions/wheelStepAction.js +1 -2
- package/player/utils/eyeSdkService.js +4 -3
- package/player/utils/stepActionUtils.js +9 -4
- package/player/webdriver.js +3 -3
- package/processHandler.js +3 -2
- package/processHandler.test.js +3 -4
- package/reports/debugReporter.js +1 -1
- package/runOptions.d.ts +2 -0
- package/runOptions.js +17 -8
- package/runners/TestPlanRunner.js +1 -1
- package/stepPlayers/hybridStepPlayback.js +23 -21
- package/stepPlayers/remoteStepPlayback.js +8 -6
- package/stepPlayers/tdkHybridStepPlayback.js +20 -17
- package/workers/BaseWorker.js +7 -6
- package/workers/WorkerAppium.js +8 -6
- package/workers/WorkerSelenium.js +16 -12
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const fs = require('fs');
|
|
6
6
|
const os = require('os');
|
|
7
|
-
const
|
|
8
|
-
const { spawn: threadSpawn, config } = require('threads');
|
|
7
|
+
const path = require('path');
|
|
9
8
|
const fse = require('fs-extra');
|
|
10
|
-
const
|
|
9
|
+
const dataUriToBuffer = require('data-uri-to-buffer');
|
|
11
10
|
const utils = require('../../../utils');
|
|
12
|
-
const logger = require('../../../commons/logger').getLogger('cli-service');
|
|
13
|
-
const { getS3Artifact } = require('../../../commons/testimServicesApi');
|
|
14
11
|
const npmWrapper = require('../../../commons/npmWrapper');
|
|
15
12
|
const featureFlags = require('../../../commons/featureFlags');
|
|
13
|
+
const { spawn: threadSpawn, config } = require('threads');
|
|
16
14
|
const { TimeoutError } = require('../../../errors');
|
|
15
|
+
const { getLogger } = require('../../../commons/logger');
|
|
16
|
+
const { getS3Artifact } = require('../../../commons/testimServicesApi');
|
|
17
|
+
|
|
18
|
+
const logger = getLogger('cli-service');
|
|
17
19
|
|
|
18
20
|
/** @type {import('worker_threads') | false} */
|
|
19
21
|
let workerThreads;
|
|
@@ -270,16 +272,17 @@ function runCode(transactionId, incomingParams, context, code, packageLocalLocat
|
|
|
270
272
|
.finally(() => thread?.kill());
|
|
271
273
|
}
|
|
272
274
|
|
|
273
|
-
|
|
275
|
+
/** @param {string} _path */
|
|
276
|
+
function requireOrImportMethod(_path) {
|
|
274
277
|
try {
|
|
275
|
-
return { sync: true, lib: require(
|
|
278
|
+
return { sync: true, lib: require(_path) };
|
|
276
279
|
} catch (err) {
|
|
277
280
|
if (err.code === 'ERR_REQUIRE_ESM') {
|
|
278
281
|
const pathModule = require('path');
|
|
279
282
|
|
|
280
283
|
const lib = fs.promises.readFile(`${path}${pathModule.sep}package.json`).then(file => {
|
|
281
284
|
const packageJson = JSON.parse(file);
|
|
282
|
-
const fullPath = pathModule.join(
|
|
285
|
+
const fullPath = pathModule.join(_path, packageJson.main || `${pathModule.sep}index.js`);
|
|
283
286
|
return import(fullPath);
|
|
284
287
|
});
|
|
285
288
|
|
|
@@ -563,6 +566,7 @@ function runCodeWithWorkerThread(
|
|
|
563
566
|
.finally(() => thread?.terminate());
|
|
564
567
|
}
|
|
565
568
|
|
|
569
|
+
/** @param {string} installFolder */
|
|
566
570
|
async function removeFolder(installFolder) {
|
|
567
571
|
try {
|
|
568
572
|
await fse.remove(installFolder);
|
|
@@ -571,10 +575,24 @@ async function removeFolder(installFolder) {
|
|
|
571
575
|
}
|
|
572
576
|
}
|
|
573
577
|
|
|
578
|
+
/**
|
|
579
|
+
* @param {string} stepResultId
|
|
580
|
+
* @param {string} testResultId
|
|
581
|
+
* @param {string} stepId
|
|
582
|
+
* @param {number} retryIndex
|
|
583
|
+
*/
|
|
574
584
|
function getTransactionId(stepResultId, testResultId, stepId, retryIndex) {
|
|
575
585
|
return `${testResultId}_${stepId}_${stepResultId}_${retryIndex}`;
|
|
576
586
|
}
|
|
577
587
|
|
|
588
|
+
/**
|
|
589
|
+
* @param {string} stepId
|
|
590
|
+
* @param {string} testResultId
|
|
591
|
+
* @param {number} retryIndex
|
|
592
|
+
* @param {{ packageName: string; packageVersion: string }[]} packageData
|
|
593
|
+
* @param {string} stepResultId
|
|
594
|
+
* @param {number} timeout
|
|
595
|
+
*/
|
|
578
596
|
function installPackage(stepId, testResultId, retryIndex, packageData, stepResultId, timeout) {
|
|
579
597
|
const transactionId = getTransactionId(stepResultId, testResultId, stepId, retryIndex);
|
|
580
598
|
return runNpmInstall(transactionId, packageData, timeout).then(({ data }) => data);
|
|
@@ -622,6 +640,11 @@ function runCodeWithPackages(code, stepId, incomingParams, context, testResultId
|
|
|
622
640
|
}).then(res => Object.assign({}, res, { nodeVersion: process.version }));
|
|
623
641
|
}
|
|
624
642
|
|
|
643
|
+
/**
|
|
644
|
+
* @param {string} transactionId
|
|
645
|
+
* @param {{ packageName: string; packageVersion: string }[]} packageData
|
|
646
|
+
* @param {number} timeout
|
|
647
|
+
*/
|
|
625
648
|
async function runNpmInstall(transactionId, packageData, timeout) {
|
|
626
649
|
const packages = packageData.map(data => `${data.packageName}@${data.packageVersion}`);
|
|
627
650
|
const localPackageInstallFolder = getLocalPackageInstallFolder();
|
|
@@ -150,19 +150,22 @@ async function compileFunctionsLibrary({ fileSystem, bypassWebpack } = {}, optio
|
|
|
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;
|
|
153
|
-
Module.prototype.require = function
|
|
153
|
+
Module.prototype.require = function requireThatOverridesTestimTDK(id) {
|
|
154
154
|
if (id === 'testim') {
|
|
155
155
|
return bypassWebpack.testim;
|
|
156
156
|
}
|
|
157
157
|
// eslint-disable-next-line prefer-rest-params
|
|
158
158
|
return originalRequire.apply(this, arguments);
|
|
159
159
|
};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
160
|
+
try {
|
|
161
|
+
// delete references to the old __testim from previous invocations
|
|
162
|
+
delete require.cache[require.resolve(functionsFile)];
|
|
163
|
+
const functions = require(functionsFile); // eslint-disable-line import/no-dynamic-require
|
|
164
|
+
// asynchronous require not supported - is this fine?
|
|
165
|
+
return functions;
|
|
166
|
+
} finally {
|
|
167
|
+
Module.prototype.require = originalRequire;
|
|
168
|
+
}
|
|
166
169
|
}
|
|
167
170
|
const functionsAsAWebpackModule = await buildCodeTests([functionsFile], {
|
|
168
171
|
output: {
|
package/cli/writeStackTrace.js
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const fse = require('fs-extra');
|
|
2
7
|
|
|
3
8
|
module.exports.writeStackTrace = function writeStackTrace(err) {
|
|
4
|
-
if(err
|
|
9
|
+
if (err?.message?.includes('SIGINT')) {
|
|
5
10
|
return; // no need to generate a log file for a sigint.
|
|
6
11
|
}
|
|
7
12
|
try {
|
|
8
|
-
const homedir =
|
|
9
|
-
const fse = require('fs-extra');
|
|
10
|
-
const path = require('path');
|
|
13
|
+
const homedir = os.homedir();
|
|
11
14
|
|
|
12
15
|
fse.ensureDirSync(path.resolve(homedir, '.testim_logs'));
|
|
13
|
-
const
|
|
16
|
+
const logFileName = path.resolve(homedir, '.testim_logs', `${new Date().toISOString().replace(/:|\./g, '_')}.log`);
|
|
14
17
|
console.log('Oops :( The test runner has encountered an unexpected error. A complete log of this run can be found in:');
|
|
15
|
-
console.log(`\t${
|
|
18
|
+
console.log(`\t${logFileName}`);
|
|
16
19
|
|
|
17
|
-
if (err
|
|
18
|
-
&& process.argv.some(x => x.includes('player-require-path'))) {
|
|
19
|
-
const chalk = require('chalk');
|
|
20
|
+
if (err?.message?.includes('Unable to compile TypeScript') && err.stack.includes('runner/src') && process.argv.some(x => x.includes('player-require-path'))) {
|
|
20
21
|
console.log(chalk.red('Looks like you got a TypeScript compile error champ - but it\'s not a very good one because we use TypeScript in transpile-only mode'));
|
|
21
|
-
console.log(chalk.red(
|
|
22
|
+
console.log(chalk.red('change require(\'ts-node/register/transpile-only\'); to require(\'ts-node/register\'); for better errors'));
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
fse.writeFileSync(
|
|
25
|
-
} catch
|
|
26
|
-
}
|
|
25
|
+
fse.writeFileSync(logFileName, `${err}\n${err.stack}\n\n${JSON.stringify(err, Object.getOwnPropertyNames(err), 2)}`);
|
|
26
|
+
} catch { /* noop */ }
|
|
27
|
+
};
|
package/cli.js
CHANGED
|
@@ -4,26 +4,23 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
require('./polyfills');
|
|
7
|
-
const
|
|
7
|
+
const semver = require('semver');
|
|
8
8
|
const EventEmitter = require('events');
|
|
9
|
-
const
|
|
10
|
-
const { onExit, ignoreFailingTestsInExitCode } = require('./cli/onExit');
|
|
9
|
+
const utils = require('./utils');
|
|
11
10
|
const testRunner = require('./runner');
|
|
11
|
+
const options = require('./runOptions');
|
|
12
|
+
const agentMode = require('./cliAgentMode');
|
|
13
|
+
const perf = require('./commons/performance-logger');
|
|
12
14
|
const prepareRunner = require('./commons/prepareRunner');
|
|
15
|
+
const prepareRunnerAndTestimStartUtils = require('./commons/prepareRunnerAndTestimStartUtils');
|
|
16
|
+
const { getLogger } = require('./commons/logger');
|
|
13
17
|
const { CLI_MODE } = require('./commons/constants');
|
|
18
|
+
const { registerProcessForCleanup } = require('./processHandler');
|
|
19
|
+
const { NoArgsError, SeleniumError, ArgError } = require('./errors');
|
|
20
|
+
const { onExit, ignoreFailingTestsInExitCode } = require('./cli/onExit');
|
|
14
21
|
const { updateRemoteRunFailure } = require('./commons/testimServicesApi');
|
|
15
|
-
const prepareRunnerAndTestimStartUtils = require('./commons/prepareRunnerAndTestimStartUtils');
|
|
16
22
|
|
|
17
|
-
const
|
|
18
|
-
NoArgsError,
|
|
19
|
-
SeleniumError,
|
|
20
|
-
ArgError,
|
|
21
|
-
} = require('./errors');
|
|
22
|
-
|
|
23
|
-
const utils = require('./utils');
|
|
24
|
-
const semver = require('semver');
|
|
25
|
-
const perf = require('./commons/performance-logger');
|
|
26
|
-
const agentMode = require('./cliAgentMode');
|
|
23
|
+
const logger = getLogger('cli-entry');
|
|
27
24
|
|
|
28
25
|
try {
|
|
29
26
|
require('./fixLocalBuild');
|
|
@@ -56,7 +53,7 @@ async function checkNodeVersion() {
|
|
|
56
53
|
async function main() {
|
|
57
54
|
console.log('Starting Testim.io CLI');
|
|
58
55
|
perf.log('Starting Testim.io CLI');
|
|
59
|
-
|
|
56
|
+
registerProcessForCleanup(onExit);
|
|
60
57
|
|
|
61
58
|
checkNodeVersion().catch(err => {
|
|
62
59
|
console.log('Argument Error:', err.message);
|
package/commons/featureFlags.js
CHANGED
|
@@ -62,6 +62,7 @@ class FeatureFlagsService {
|
|
|
62
62
|
LTNetworkCapabilities: new Rox.Flag(),
|
|
63
63
|
downloadToBase64: new Rox.Flag(),
|
|
64
64
|
dec2022eolBrowsers: new Rox.Flag(),
|
|
65
|
+
publicGridURL: new Rox.Configuration('public-grid.testim.io'),
|
|
65
66
|
};
|
|
66
67
|
Rox.register('default', this.flags);
|
|
67
68
|
}
|
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { join, resolve } = require('path');
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const { getSessionPlayerFolder } = require('./prepareRunnerAndTestimStartUtils');
|
|
5
|
+
/** @type {{ playerPath: string | undefined }} */ module.exports.options = { playerPath: undefined };
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
/** @type {import('clickim/src/background/sessionPlayerInit').SessionPlayerInit} */
|
|
10
|
-
const sessionPlayer = require(require('path').join(testimAppDataFolder, 'sessionPlayer.js')); // eslint-disable-line import/no-dynamic-require
|
|
7
|
+
/** @type {import('clickim/src/background/sessionPlayerInit').SessionPlayerInit | undefined} */ let sessionPlayerInit;
|
|
11
8
|
|
|
12
|
-
module.exports =
|
|
13
|
-
|
|
9
|
+
module.exports.getSessionPlayer = () => {
|
|
10
|
+
if (sessionPlayerInit) {
|
|
11
|
+
return sessionPlayerInit;
|
|
12
|
+
}
|
|
13
|
+
const perf = require('./performance-logger');
|
|
14
|
+
|
|
15
|
+
perf.log('getSessionPlayerRequire start');
|
|
16
|
+
const { getSessionPlayerFolder } = require('./prepareRunnerAndTestimStartUtils');
|
|
17
|
+
|
|
18
|
+
const testimAppDataFolder = getSessionPlayerFolder();
|
|
19
|
+
const { options } = module.exports;
|
|
20
|
+
const path = options.playerPath ? resolve(options.playerPath, 'src/background/sessionPlayerInit.ts') : join(testimAppDataFolder, 'sessionPlayer.js');
|
|
21
|
+
|
|
22
|
+
/** @type {import('clickim/src/background/sessionPlayerInit').SessionPlayerInit} */
|
|
23
|
+
const sessionPlayer = require(path); // eslint-disable-line import/no-dynamic-require
|
|
24
|
+
|
|
25
|
+
perf.log('getSessionPlayerRequire end');
|
|
26
|
+
sessionPlayerInit = sessionPlayer;
|
|
27
|
+
return sessionPlayer;
|
|
28
|
+
};
|
|
@@ -62,13 +62,13 @@ module.exports.makeCounters = () => {
|
|
|
62
62
|
* @template T, TArgs
|
|
63
63
|
* @param {(...args: TArgs[]) => T} fn
|
|
64
64
|
* @param {string=} name
|
|
65
|
-
* @return {(...args: TArgs[]) => Promise<
|
|
65
|
+
* @return {(...args: TArgs[]) => Promise<T>}
|
|
66
66
|
*/
|
|
67
67
|
function wrapWithMonitoring(fn, name = fn.name) {
|
|
68
68
|
return async function (...args) {
|
|
69
69
|
update(counters.call, name);
|
|
70
70
|
try {
|
|
71
|
-
const result = await fn.call(
|
|
71
|
+
const result = await fn.call(null, ...args);
|
|
72
72
|
update(counters.success, name);
|
|
73
73
|
return result;
|
|
74
74
|
} catch (e) {
|
|
@@ -15,7 +15,7 @@ function preloadSlowRequires(mode) {
|
|
|
15
15
|
}
|
|
16
16
|
// heuristic to pay the cost of loading the sessionPlayer here while we are waiting for the backend
|
|
17
17
|
try {
|
|
18
|
-
require('./getSessionPlayerRequire');
|
|
18
|
+
require('./getSessionPlayerRequire').getSessionPlayer();
|
|
19
19
|
// jsdom for the same reason, we don't require workerSelenium here since it actually takes longer to load
|
|
20
20
|
// then it takes for the backend to return 🤯
|
|
21
21
|
require('jsdom');
|
|
@@ -529,7 +529,11 @@ function buildSeleniumOptions(browserOptions, testName, testRunConfig, gridInfo,
|
|
|
529
529
|
* One level targeting (either grid provider, host, browser name or browser version): { "devicefarm": { selenium_version: '3.141.59' } }
|
|
530
530
|
* Two level targeting: { "internet explorer": { "11": { selenium_version: '3.141.59' } } }
|
|
531
531
|
*/
|
|
532
|
-
const hostToProvider = {
|
|
532
|
+
const hostToProvider = {
|
|
533
|
+
'hub.lambdatest.com': 'lambdatest',
|
|
534
|
+
[featureFlags.flags.publicGridURL.getValue()]: 'testim',
|
|
535
|
+
'testgrid-devicefarm.us-west-2.amazonaws.com': 'devicefarm',
|
|
536
|
+
};
|
|
533
537
|
const byGrid = (capabilities) => capabilities[gridInfo.provider] || capabilities[opts.host] || capabilities[hostToProvider[opts.host]];
|
|
534
538
|
const getTargetingGroup = capabilities =>
|
|
535
539
|
byGrid(capabilities) ||
|
|
@@ -576,6 +580,7 @@ function buildAppiumOptions({ projectType, gridInfo, testRunConfig, nativeApp, o
|
|
|
576
580
|
hostname: gridInfo.host,
|
|
577
581
|
port: gridInfo.port,
|
|
578
582
|
path: `/v0/${gridInfo.accessToken}/wd/hub`,
|
|
583
|
+
logLevel: options.appiumLogLevel,
|
|
579
584
|
// connectionRetryTimeout: 900000, -- not used for now
|
|
580
585
|
};
|
|
581
586
|
//TODO: check if more caps should be defined as default
|