@testim/testim-cli 3.245.0 → 3.246.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/chromiumInstaller.js +92 -0
- package/cli.js +89 -87
- package/cliAgentMode.js +39 -114
- package/commons/getSessionPlayerRequire.js +2 -1
- package/commons/prepareRunner.js +2 -0
- package/commons/testimServicesApi.js +5 -0
- package/npm-shrinkwrap.json +135 -98
- package/package.json +1 -1
- package/player/WebDriverHttpRequest.js +45 -37
- package/player/chromeLauncherTestPlayer.js +2 -2
- package/player/services/playbackTimeoutCalculator.js +5 -1
- package/player/stepActions/sfdcStepAction.js +27 -0
- package/player/stepActions/stepActionRegistrar.js +12 -0
- package/player/webdriver.js +51 -52
- package/runOptions.js +3 -1
- package/runner.js +44 -41
- package/testRunHandler.js +4 -1
- package/utils.js +42 -2
- package/utils.test.js +26 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const { ArgError } = require('./errors');
|
|
5
|
+
const { unzipFile } = require('./utils');
|
|
6
|
+
const { downloadAndSave, TESTIM_BROWSER_DIR } = require('./utils');
|
|
7
|
+
const ora = require('ora');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const CHROMIUM_VERSION = '1000968'; // '973306' = 101.0.4899.0 '1000968' = 103.0.5046.0;
|
|
11
|
+
const DOWNLOAD_CHROME_FOLDER = path.join(TESTIM_BROWSER_DIR, `chrome-${CHROMIUM_VERSION}`);
|
|
12
|
+
|
|
13
|
+
function getCurrentPlatform() {
|
|
14
|
+
const osType = os.type().toLowerCase();
|
|
15
|
+
if (osType === 'darwin') {
|
|
16
|
+
return os.arch() === 'arm' ? 'mac_arm' : 'mac';
|
|
17
|
+
}
|
|
18
|
+
if (osType === 'windows_nt') {
|
|
19
|
+
return os.arch() === 'x64' ? 'win64' : 'win32';
|
|
20
|
+
}
|
|
21
|
+
return 'linux';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function downloadAndInstallChromium() {
|
|
25
|
+
/** Inspired by puppeteer's implementation https://github.com/puppeteer/puppeteer/blob/main/src/node/BrowserFetcher.ts#L45 */
|
|
26
|
+
const platform = getCurrentPlatform();
|
|
27
|
+
|
|
28
|
+
// example download url: https://storage.googleapis.com/chromium-browser-snapshots/Mac/1000968/chrome-mac.zip
|
|
29
|
+
const storageBaseUrl = 'https://storage.googleapis.com/chromium-browser-snapshots';
|
|
30
|
+
const platformFolder = {
|
|
31
|
+
linux: 'Linux_x64',
|
|
32
|
+
mac: 'Mac',
|
|
33
|
+
mac_arm: 'Mac_Arm',
|
|
34
|
+
win32: 'Win',
|
|
35
|
+
win64: 'Win_x64',
|
|
36
|
+
};
|
|
37
|
+
if (!(platform in platformFolder)) {
|
|
38
|
+
throw new ArgError(`Unsupported platform: ${platform}`);
|
|
39
|
+
}
|
|
40
|
+
// Windows archive name changed at r591479.
|
|
41
|
+
const winArchiveName = parseInt(CHROMIUM_VERSION, 10) > 591479 ? 'chrome-win' : 'chrome-win32';
|
|
42
|
+
const platformArchiveName = {
|
|
43
|
+
linux: 'chrome-linux',
|
|
44
|
+
mac: 'chrome-mac',
|
|
45
|
+
mac_arm: 'chrome-mac',
|
|
46
|
+
win32: winArchiveName,
|
|
47
|
+
win64: winArchiveName,
|
|
48
|
+
};
|
|
49
|
+
const binaryPaths = {
|
|
50
|
+
linux: 'chrome',
|
|
51
|
+
mac: 'Chromium.app/Contents/MacOS/Chromium',
|
|
52
|
+
mac_arm: 'Chromium.app/Contents/MacOS/Chromium',
|
|
53
|
+
win32: 'chrome.exe',
|
|
54
|
+
win64: 'chrome.exe',
|
|
55
|
+
};
|
|
56
|
+
const downloadUrl = `${storageBaseUrl}/${platformFolder[platform]}/${CHROMIUM_VERSION}/${platformArchiveName[platform]}.zip`;
|
|
57
|
+
const downloadArchivePath = path.join(DOWNLOAD_CHROME_FOLDER, platformArchiveName[platform]);
|
|
58
|
+
const downloadedZipFile = `${downloadArchivePath}.zip`;
|
|
59
|
+
const binaryPath = path.join(downloadArchivePath, binaryPaths[platform]);
|
|
60
|
+
|
|
61
|
+
if (await fs.pathExists(binaryPath)) {
|
|
62
|
+
return binaryPath;
|
|
63
|
+
}
|
|
64
|
+
if (!(await fs.pathExists(downloadedZipFile))) {
|
|
65
|
+
const downloadSpinner = ora('Downloading Chromium').start();
|
|
66
|
+
try {
|
|
67
|
+
await fs.mkdirp(DOWNLOAD_CHROME_FOLDER);
|
|
68
|
+
await downloadAndSave(downloadUrl, downloadedZipFile);
|
|
69
|
+
// todo - We can add a failover here if the download fails if we host the file too
|
|
70
|
+
} catch (e) {
|
|
71
|
+
const errorMessage = `Failed to download Chromium: ${e.message}`;
|
|
72
|
+
downloadSpinner.fail(errorMessage);
|
|
73
|
+
throw new Error(errorMessage);
|
|
74
|
+
}
|
|
75
|
+
downloadSpinner.succeed();
|
|
76
|
+
}
|
|
77
|
+
const extractSpinner = ora('Extracting Chromium').start();
|
|
78
|
+
try {
|
|
79
|
+
await unzipFile(downloadedZipFile, DOWNLOAD_CHROME_FOLDER);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
const errorMessage = `Failed to extract Chromium: ${e.message}`;
|
|
82
|
+
extractSpinner.fail(errorMessage);
|
|
83
|
+
throw new Error(errorMessage);
|
|
84
|
+
}
|
|
85
|
+
extractSpinner.succeed();
|
|
86
|
+
return binaryPath;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
CHROMIUM_VERSION,
|
|
91
|
+
downloadAndInstallChromium,
|
|
92
|
+
};
|
package/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ const { onExit, ignoreFailingTestsInExitCode } = require('./cli/onExit');
|
|
|
11
11
|
const testRunner = require('./runner');
|
|
12
12
|
const prepareRunner = require('./commons/prepareRunner');
|
|
13
13
|
const { CLI_MODE } = require('./commons/constants');
|
|
14
|
+
const { updateRemoteRunFailure } = require('./commons/testimServicesApi');
|
|
14
15
|
const prepareRunnerAndTestimStartUtils = require('./commons/prepareRunnerAndTestimStartUtils');
|
|
15
16
|
|
|
16
17
|
const {
|
|
@@ -21,7 +22,6 @@ const {
|
|
|
21
22
|
|
|
22
23
|
const utils = require('./utils');
|
|
23
24
|
const semver = require('semver');
|
|
24
|
-
const Promise = require('bluebird');
|
|
25
25
|
const perf = require('./commons/performance-logger');
|
|
26
26
|
const agentMode = require('./cliAgentMode');
|
|
27
27
|
|
|
@@ -35,19 +35,19 @@ async function checkNodeVersion() {
|
|
|
35
35
|
throw new ArgError(`Required node version ${version} not satisfied with current version ${process.version}`);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const majorVersion = Number(process.version.replace('v', '').split('.')[0]);
|
|
39
|
+
const dateHasPassed = new Date('2022-08-01T00:00:00.000Z') <= new Date();
|
|
40
|
+
|
|
41
|
+
if (majorVersion < 14 && dateHasPassed) {
|
|
42
|
+
throw new ArgError('Testim.io CLI supports Node.js 14 and above, please upgrade to a newer Node.js version');
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log('\x1b[33m%s\x1b[0m', 'Testim.io CLI will stop supporting Node.js < 12.20 on March 1st 2022, please upgrade to a newer Node.js version');
|
|
45
|
+
if (majorVersion < 14) {
|
|
46
|
+
console.log('\x1b[33m%s\x1b[0m', 'Testim.io CLI will stop supporting Node.js < 14 on August 1st 2022, please upgrade to a newer Node.js version');
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function main() {
|
|
50
|
+
async function main() {
|
|
51
51
|
console.log('Starting Testim.io CLI');
|
|
52
52
|
perf.log('Starting Testim.io CLI');
|
|
53
53
|
require('./processHandler')(onExit);
|
|
@@ -57,91 +57,93 @@ function main() {
|
|
|
57
57
|
process.exit(1);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await prepareRunnerAndTestimStartUtils.preparePlayer(options.playerLocation, options.canary);
|
|
85
|
-
}
|
|
86
|
-
const res = await runnerFileCache.waitForSave();
|
|
87
|
-
if (res.success) {
|
|
88
|
-
console.log(`created prefeched data at ${runnerFileCache.getCacheFileLocation()}`);
|
|
89
|
-
} else {
|
|
90
|
-
console.error('failed to create prefech data', res.error);
|
|
91
|
-
}
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (options.tunnelOnlyMode) {
|
|
96
|
-
await testRunner.init(options);
|
|
97
|
-
await require('./commons/testimTunnel').serveTunneling(options);
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (agentMode.shouldStartAgentMode(options)) {
|
|
102
|
-
return agentMode.runAgentMode(options);
|
|
60
|
+
try {
|
|
61
|
+
const processedOptions = await options.process();
|
|
62
|
+
perf.log('in main, after options.process');
|
|
63
|
+
require('./commons/logger').setProxyUri(global.proxyUri);
|
|
64
|
+
if (processedOptions.parallel && processedOptions.parallel > 5) {
|
|
65
|
+
EventEmitter.defaultMaxListeners = processedOptions.parallel * 2;
|
|
66
|
+
}
|
|
67
|
+
require('./commons/logger').setProjectId(processedOptions.project);
|
|
68
|
+
require('./commons/runnerFileCache').setEncryptKey(typeof processedOptions.token === 'string' ? processedOptions.token : 'anonymous_encrypt_key');
|
|
69
|
+
|
|
70
|
+
if (processedOptions.initCodimMode) {
|
|
71
|
+
const codimCli = require('./codim/codim-cli');
|
|
72
|
+
return codimCli.init(processedOptions.initTestProject);
|
|
73
|
+
}
|
|
74
|
+
if (processedOptions.loginMode) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
if (processedOptions.createPrefechedData) {
|
|
78
|
+
const runnerFileCache = require('./commons/runnerFileCache');
|
|
79
|
+
await runnerFileCache.clear();
|
|
80
|
+
await prepareRunner.initializeUserWithAuth(processedOptions);
|
|
81
|
+
await require('./commons/preloadTests').preloadTests(processedOptions);
|
|
82
|
+
if (!processedOptions.playerRequirePath && processedOptions.mode !== CLI_MODE.EXTENSION) {
|
|
83
|
+
await prepareRunnerAndTestimStartUtils.preparePlayer(processedOptions.playerLocation, processedOptions.canary);
|
|
103
84
|
}
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (options.exitCodeIgnoreFailingTests) {
|
|
111
|
-
ignoreFailingTestsInExitCode();
|
|
85
|
+
const res = await runnerFileCache.waitForSave();
|
|
86
|
+
if (res.success) {
|
|
87
|
+
console.log(`created prefeched data at ${runnerFileCache.getCacheFileLocation()}`);
|
|
88
|
+
} else {
|
|
89
|
+
console.error('failed to create prefech data', res.error);
|
|
112
90
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (processedOptions.tunnelOnlyMode) {
|
|
95
|
+
await testRunner.init(processedOptions);
|
|
96
|
+
await require('./commons/testimTunnel').serveTunneling(processedOptions);
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (agentMode.shouldStartAgentMode(processedOptions)) {
|
|
101
|
+
return agentMode.runAgentMode(processedOptions);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (processedOptions.saveRCALocally) {
|
|
105
|
+
const { port } = await require('./services/localRCASaver').initServer(processedOptions);
|
|
106
|
+
processedOptions.localRCASaver = `http://localhost:${port}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (processedOptions.exitCodeIgnoreFailingTests) {
|
|
110
|
+
ignoreFailingTestsInExitCode();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
perf.log('right before testRunner.init/prepareRunner.prepare');
|
|
114
|
+
const [customExtensionLocalLocation] = await Promise.all([
|
|
115
|
+
prepareRunner.prepare(processedOptions),
|
|
116
|
+
testRunner.init(processedOptions),
|
|
117
|
+
]);
|
|
118
|
+
perf.log('right after testRunner.init/prepareRunner.prepare');
|
|
119
|
+
return await testRunner.run(processedOptions, customExtensionLocalLocation);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err instanceof NoArgsError) {
|
|
123
122
|
// display help by default
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
const argsForRemoteRunFailure = utils.getArgsOnRemoteRunFailure();
|
|
126
|
+
if (argsForRemoteRunFailure) {
|
|
127
|
+
await updateRemoteRunFailure({ ...argsForRemoteRunFailure, error: err.message }).catch(() => { /* */ });
|
|
128
|
+
}
|
|
129
|
+
if (err instanceof ArgError) {
|
|
126
130
|
console.log('Argument Error:', err.message);
|
|
127
131
|
return err;
|
|
128
|
-
}
|
|
129
|
-
|
|
132
|
+
}
|
|
133
|
+
if (err instanceof SeleniumError) {
|
|
130
134
|
console.log('Selenium Error:', err.message);
|
|
131
135
|
return err;
|
|
132
|
-
}
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
})
|
|
138
|
-
.then(result => {
|
|
139
|
-
if (Array.isArray(result) && result.length === 0) {
|
|
140
|
-
console.log('No tests ran');
|
|
141
|
-
}
|
|
142
|
-
onExit(result);
|
|
143
|
-
});
|
|
136
|
+
}
|
|
137
|
+
console.log('Error:', err.message);
|
|
138
|
+
logger.error('runner ended with unexpected error', { err });
|
|
139
|
+
return err;
|
|
140
|
+
}
|
|
144
141
|
}
|
|
145
142
|
|
|
146
|
-
main()
|
|
143
|
+
main().then(result => {
|
|
144
|
+
if (Array.isArray(result) && result.length === 0) {
|
|
145
|
+
console.log('No tests ran');
|
|
146
|
+
}
|
|
147
|
+
onExit(result);
|
|
148
|
+
});
|
|
147
149
|
|
package/cliAgentMode.js
CHANGED
|
@@ -4,26 +4,23 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const os = require('os');
|
|
8
7
|
const fs = require('fs-extra');
|
|
9
8
|
const ms = require('ms');
|
|
10
9
|
const WebSocket = require('ws');
|
|
11
10
|
const Bluebird = require('bluebird');
|
|
12
11
|
const ChromeLauncher = require('chrome-launcher');
|
|
13
|
-
const httpRequest = require('./commons/httpRequest');
|
|
14
12
|
const config = require('./commons/config');
|
|
15
13
|
const { ArgError } = require('./errors');
|
|
16
14
|
const lazyRequire = require('./commons/lazyRequire');
|
|
17
15
|
const prepareUtils = require('./commons/prepareRunnerAndTestimStartUtils');
|
|
18
|
-
const { unzipFile } = require('./utils');
|
|
19
|
-
const { downloadAndSave } = require('./utils');
|
|
16
|
+
const { downloadAndSave, unzipFile, getCdpAddressForHost, TESTIM_BROWSER_DIR } = require('./utils');
|
|
20
17
|
const ora = require('ora');
|
|
18
|
+
const { downloadAndInstallChromium, CHROMIUM_VERSION } = require('./chromiumInstaller');
|
|
19
|
+
|
|
21
20
|
|
|
22
21
|
const LOG_LEVEL = config.WEBDRIVER_DEBUG ? 'verbose' : 'silent';
|
|
23
22
|
const EXTENSION_CACHE_TIME = ms('1h');
|
|
24
|
-
const
|
|
25
|
-
const TESTIM_BROWSER_PROFILES_CONTAINER = path.join(HOMEDIR, '.testim-browser-profile');
|
|
26
|
-
const USER_DATA_DIR = path.join(TESTIM_BROWSER_PROFILES_CONTAINER, 'profile');
|
|
23
|
+
const USER_DATA_DIR = path.join(TESTIM_BROWSER_DIR, 'profile');
|
|
27
24
|
|
|
28
25
|
// https://github.com/bayandin/chromedriver/blob/5013f2124888c50fff15dc2ff8287288f780b046/chrome_launcher.cc#L105
|
|
29
26
|
const CHOMEDRIVER_DEVTOOLS_ACTIVE_PORT_FILENAME = 'DevToolsActivePort';
|
|
@@ -111,84 +108,37 @@ function getStartedWithStart() {
|
|
|
111
108
|
return startedWithStart;
|
|
112
109
|
}
|
|
113
110
|
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (osType === 'windows_nt') {
|
|
120
|
-
return os.arch() === 'x64' ? 'win64' : 'win32';
|
|
111
|
+
function isPidRunning(pid) {
|
|
112
|
+
try {
|
|
113
|
+
return process.kill(pid, 0);
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
121
116
|
}
|
|
122
|
-
return 'linux';
|
|
123
117
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
135
|
-
if (!(platform in platformFolder)) {
|
|
136
|
-
throw new ArgError(`Unsupported platform: ${platform}`);
|
|
137
|
-
}
|
|
138
|
-
// Windows archive name changed at r591479.
|
|
139
|
-
const winArchiveName = parseInt(revision, 10) > 591479 ? 'chrome-win' : 'chrome-win32';
|
|
140
|
-
const platformArchiveName = {
|
|
141
|
-
linux: 'chrome-linux',
|
|
142
|
-
mac: 'chrome-mac',
|
|
143
|
-
mac_arm: 'chrome-mac',
|
|
144
|
-
win32: winArchiveName,
|
|
145
|
-
win64: winArchiveName,
|
|
146
|
-
};
|
|
147
|
-
const binaryPaths = {
|
|
148
|
-
linux: 'chrome',
|
|
149
|
-
mac: 'Chromium.app/Contents/MacOS/Chromium',
|
|
150
|
-
mac_arm: 'Chromium.app/Contents/MacOS/Chromium',
|
|
151
|
-
win32: 'chrome.exe',
|
|
152
|
-
win64: 'chrome.exe',
|
|
118
|
+
|
|
119
|
+
async function startFixedVersionChromium(options, extensionBase64, downloadedExtensionPathUnzipped) {
|
|
120
|
+
const CHROMIUM_PROCESS_INFO_FILE = path.join(TESTIM_BROWSER_DIR, `chrome-${CHROMIUM_VERSION}-process`);
|
|
121
|
+
const CHECK_CHROMIUM_RUNNING_INTERVAL = 3000;
|
|
122
|
+
|
|
123
|
+
const onBrowserClosed = () => {
|
|
124
|
+
fs.removeSync(CHROMIUM_PROCESS_INFO_FILE);
|
|
125
|
+
// eslint-disable-next-line no-console
|
|
126
|
+
console.log('\n\nBrowser session ended');
|
|
127
|
+
process.exit(0);
|
|
153
128
|
};
|
|
154
|
-
const downloadUrl = `${storageBaseUrl}/${platformFolder[platform]}/${revision}/${platformArchiveName[platform]}.zip`;
|
|
155
|
-
const downloadArchivePath = path.join(saveLocation, platformArchiveName[platform]);
|
|
156
|
-
const downloadedZipFile = `${downloadArchivePath}.zip`;
|
|
157
|
-
const binaryPath = path.join(downloadArchivePath, binaryPaths[platform]);
|
|
158
129
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} catch (e) {
|
|
169
|
-
const errorMessage = `Failed to download Chromium: ${e.message}`;
|
|
170
|
-
downloadSpinner.fail(errorMessage);
|
|
171
|
-
throw new Error(errorMessage);
|
|
130
|
+
|
|
131
|
+
if (fs.existsSync(CHROMIUM_PROCESS_INFO_FILE)) {
|
|
132
|
+
const processInfo = fs.readJSONSync(CHROMIUM_PROCESS_INFO_FILE);
|
|
133
|
+
if (isPidRunning(processInfo.pid)) { // if a previous instance of our browser is still running, use it and exit if it does
|
|
134
|
+
const monitorPidForExit = () => (isPidRunning(processInfo.pid) ? setTimeout(monitorPidForExit, CHECK_CHROMIUM_RUNNING_INTERVAL) : onBrowserClosed());
|
|
135
|
+
monitorPidForExit();
|
|
136
|
+
return {
|
|
137
|
+
webdriverApi: processInfo,
|
|
138
|
+
};
|
|
172
139
|
}
|
|
173
|
-
downloadSpinner.succeed();
|
|
174
140
|
}
|
|
175
|
-
const
|
|
176
|
-
try {
|
|
177
|
-
await unzipFile(downloadedZipFile, saveLocation);
|
|
178
|
-
} catch (e) {
|
|
179
|
-
const errorMessage = `Failed to extract Chromium: ${e.message}`;
|
|
180
|
-
extractSpinner.fail(errorMessage);
|
|
181
|
-
throw new Error(errorMessage);
|
|
182
|
-
}
|
|
183
|
-
extractSpinner.succeed();
|
|
184
|
-
return binaryPath;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async function startFixedVersionBrowser(options, extensionBase64, downloadedExtensionPathUnzipped) {
|
|
188
|
-
const CHROME_VERSION = '1000968';
|
|
189
|
-
const DOWNLOAD_CHROME_FOLDER = path.join(TESTIM_BROWSER_PROFILES_CONTAINER, `chrome-${CHROME_VERSION}`);
|
|
190
|
-
|
|
191
|
-
const chromeBinary = await downloadAndInstallChrome(getCurrentPlatform(), CHROME_VERSION, DOWNLOAD_CHROME_FOLDER);
|
|
141
|
+
const chromeBinary = await downloadAndInstallChromium();
|
|
192
142
|
|
|
193
143
|
if (!(await fs.pathExists(USER_DATA_DIR))) {
|
|
194
144
|
await fs.mkdirp(USER_DATA_DIR);
|
|
@@ -210,12 +160,12 @@ async function startFixedVersionBrowser(options, extensionBase64, downloadedExte
|
|
|
210
160
|
};
|
|
211
161
|
const appUrl = `${options.extensionPath ? 'http://localhost:3000/app/' : 'https://app.testim.io'}?startMode=true`;
|
|
212
162
|
const chrome = await ChromeLauncher.launch({ chromeFlags, startingUrl: appUrl, ignoreDefaultFlags: true, userDataDir: USER_DATA_DIR, chromePath: chromeBinary, envVars });
|
|
213
|
-
const
|
|
214
|
-
|
|
163
|
+
const processInfo = { port: chrome.port, pid: chrome.pid, cdpUrl: await getCdpAddressForHost(`localhost:${chrome.port}`) };
|
|
164
|
+
fs.writeJSONSync(CHROMIUM_PROCESS_INFO_FILE, processInfo);
|
|
215
165
|
chrome.process.once('exit', onBrowserClosed);
|
|
216
166
|
chrome.process.once('close', onBrowserClosed);
|
|
217
167
|
return {
|
|
218
|
-
webdriverApi:
|
|
168
|
+
webdriverApi: processInfo,
|
|
219
169
|
};
|
|
220
170
|
}
|
|
221
171
|
|
|
@@ -226,8 +176,8 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
226
176
|
const fullExtensionUrl = `${config.EDGE_URL}/extension/testim-full-master.zip`;
|
|
227
177
|
const extensionFilename = path.basename(fullExtensionUrl);
|
|
228
178
|
|
|
229
|
-
const downloadedExtensionPath = path.join(
|
|
230
|
-
const downloadedExtensionPathUnzipped = path.join(
|
|
179
|
+
const downloadedExtensionPath = path.join(TESTIM_BROWSER_DIR, extensionFilename);
|
|
180
|
+
const downloadedExtensionPathUnzipped = path.join(TESTIM_BROWSER_DIR, `${extensionFilename}__unzipped__`);
|
|
231
181
|
|
|
232
182
|
let shouldDownloadExtension = !(options.ext || options.extensionPath);
|
|
233
183
|
|
|
@@ -236,7 +186,7 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
236
186
|
const stat = await fs.stat(downloadedExtensionPath);
|
|
237
187
|
shouldDownloadExtension = (Date.now() - EXTENSION_CACHE_TIME > stat.mtimeMs);
|
|
238
188
|
}
|
|
239
|
-
await fs.mkdirp(
|
|
189
|
+
await fs.mkdirp(TESTIM_BROWSER_DIR);
|
|
240
190
|
|
|
241
191
|
if (shouldDownloadExtension) {
|
|
242
192
|
const spinner = ora('Downloading Testim Editor').start();
|
|
@@ -268,7 +218,7 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
268
218
|
|
|
269
219
|
const extensionBase64 = options.extensionPath ? null : (await fs.readFile(options.ext || downloadedExtensionPath)).toString('base64');
|
|
270
220
|
if (options.downloadBrowser) {
|
|
271
|
-
return await
|
|
221
|
+
return await startFixedVersionChromium(options, extensionBase64, downloadedExtensionPathUnzipped);
|
|
272
222
|
}
|
|
273
223
|
await prepareUtils.prepareChromeDriver(
|
|
274
224
|
{ projectId: options.project },
|
|
@@ -301,9 +251,8 @@ async function startTestimStandaloneBrowser(options) {
|
|
|
301
251
|
// save the initial URL we navigated to so we don't consider it the AuT
|
|
302
252
|
webdriverApi.initialUrl = appUrl;
|
|
303
253
|
try {
|
|
304
|
-
//TODO(Benji) do we want this to be exactly
|
|
305
|
-
|
|
306
|
-
webdriverApi.cdpUrl = debuggerAddress.webSocketDebuggerUrl;
|
|
254
|
+
//TODO(Benji) do we want this to be exactly getCdpAddressForHost or should this fail less gracefully indicating the agent did not start correctly?
|
|
255
|
+
webdriverApi.cdpUrl = await getCdpAddressForHost(webdriverInitResponse.value['goog:chromeOptions'].debuggerAddress);
|
|
307
256
|
} catch (e) {
|
|
308
257
|
// ignore error
|
|
309
258
|
}
|
|
@@ -392,31 +341,7 @@ async function readAndValidateChromedriverDevToolsActivePortFile() {
|
|
|
392
341
|
throw new Error('invalid devtools browser url');
|
|
393
342
|
}
|
|
394
343
|
|
|
395
|
-
|
|
396
|
-
try {
|
|
397
|
-
/**
|
|
398
|
-
example response
|
|
399
|
-
|
|
400
|
-
{
|
|
401
|
-
"Browser": "Chrome/81.0.4044.138",
|
|
402
|
-
"Protocol-Version": "1.3",
|
|
403
|
-
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
|
|
404
|
-
"V8-Version": "8.1.307.32",
|
|
405
|
-
"WebKit-Version": "537.36 (@8c6c7ba89cc9453625af54f11fd83179e23450fa)",
|
|
406
|
-
"webSocketDebuggerUrl": "ws://localhost:58938/devtools/browser/d4290379-ec08-4d03-a41a-ab9d9d4c36ac"
|
|
407
|
-
}
|
|
408
|
-
*/
|
|
409
|
-
({ webSocketDebuggerUrl } = await httpRequest.get(
|
|
410
|
-
`http://localhost:${port}/json/version`,
|
|
411
|
-
undefined,
|
|
412
|
-
undefined,
|
|
413
|
-
// short timeout, as we try to connect to localhost
|
|
414
|
-
100
|
|
415
|
-
));
|
|
416
|
-
} catch (e) {
|
|
417
|
-
throw new Error('unable to connect to devtools http server');
|
|
418
|
-
}
|
|
419
|
-
|
|
344
|
+
const webSocketDebuggerUrl = await getCdpAddressForHost(`localhost:${port}`, 500);
|
|
420
345
|
// invariant check
|
|
421
346
|
if (!webSocketDebuggerUrl.endsWith(browserCDPURLLine)) {
|
|
422
347
|
throw new Error('invariant webSocketDebuggerUrl miss match');
|
|
@@ -21,7 +21,8 @@ const testimAppDataFolder = getSessionPlayerFolder();
|
|
|
21
21
|
stepParamBuilder: typeof import('../../../clickim/src/common/stepParamsBuilder').StepParamsBuilder;
|
|
22
22
|
stepParamExpressionEvaluator: import('../../../clickim/src/common/stepParamExpressionEvaluator');
|
|
23
23
|
manifestVersion: string | undefined;
|
|
24
|
-
EyeSdkBuilder: typeof import('../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder
|
|
24
|
+
EyeSdkBuilder: typeof import('../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder;
|
|
25
|
+
sfdc: typeof import('sfdc-engine');
|
|
25
26
|
}}
|
|
26
27
|
*/
|
|
27
28
|
const sessionPlayer = require(require('path').join(testimAppDataFolder, 'sessionPlayer.js')); // eslint-disable-line import/no-dynamic-require
|
package/commons/prepareRunner.js
CHANGED
|
@@ -10,6 +10,7 @@ const Ajv = require('ajv');
|
|
|
10
10
|
const prepareRunnerAndTestimStartUtils = require('./prepareRunnerAndTestimStartUtils');
|
|
11
11
|
const mockNetworkRuleFileSchema = require('./mockNetworkRuleFileSchema.json');
|
|
12
12
|
const { initializeUserWithAuth } = require('./initializeUserWithAuth');
|
|
13
|
+
const { downloadAndInstallChromium } = require('../chromiumInstaller');
|
|
13
14
|
|
|
14
15
|
const MAX_RULE_FILE_SIZE_IN_MB = 1;
|
|
15
16
|
const PREPARE_MOCK_NETWORK_ERROR_PREFIX = 'JSON file supplied to --mock-network-pattern';
|
|
@@ -30,6 +31,7 @@ async function prepare(options) {
|
|
|
30
31
|
const hasNoGrid = !options.host && !options.gridId && !options.grid && (!options.testPlan || options.testPlan.length === 0);
|
|
31
32
|
const isTdkRun = options.files.length !== 0;
|
|
32
33
|
if ((hasNoGrid && isTdkRun) || options.useLocalChromeDriver) {
|
|
34
|
+
options.chromeBinaryLocation = options.downloadBrowser ? await downloadAndInstallChromium() : options.chromeBinaryLocation;
|
|
33
35
|
chromedriverPromise = prepareRunnerAndTestimStartUtils.prepareChromeDriver(
|
|
34
36
|
{ projectId: options.project, userId: options.user },
|
|
35
37
|
{ chromeBinaryLocation: options.chromeBinaryLocation },
|
|
@@ -476,6 +476,10 @@ function deleteCloudflareTunnel(companyId, tunnelId) {
|
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
+
function updateRemoteRunFailure(body) {
|
|
480
|
+
return httpRequest.post({ url: `${config.SERVICES_HOST}/result/remoteRunFailure`, body });
|
|
481
|
+
}
|
|
482
|
+
|
|
479
483
|
module.exports = {
|
|
480
484
|
getS3Artifact,
|
|
481
485
|
getTestPlan,
|
|
@@ -511,4 +515,5 @@ module.exports = {
|
|
|
511
515
|
getCloudflareTunnel,
|
|
512
516
|
forceUpdateCloudflareTunnelRoutes,
|
|
513
517
|
deleteCloudflareTunnel,
|
|
518
|
+
updateRemoteRunFailure,
|
|
514
519
|
};
|