appium 2.5.4 → 2.6.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/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +10 -0
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/parser.d.ts +5 -0
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +38 -1
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/setup-command.d.ts +37 -0
- package/build/lib/cli/setup-command.d.ts.map +1 -0
- package/build/lib/cli/setup-command.js +173 -0
- package/build/lib/cli/setup-command.js.map +1 -0
- package/build/lib/config.d.ts +38 -18
- package/build/lib/config.d.ts.map +1 -1
- package/build/lib/config.js +75 -3
- package/build/lib/config.js.map +1 -1
- package/build/lib/constants.d.ts +21 -2
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +24 -7
- package/build/lib/constants.js.map +1 -1
- package/build/lib/grid-register.js +2 -2
- package/build/lib/grid-register.js.map +1 -1
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +23 -5
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/main.d.ts +1 -0
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +15 -1
- package/build/lib/main.js.map +1 -1
- package/build/lib/utils.d.ts +12 -2
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +15 -3
- package/build/lib/utils.js.map +1 -1
- package/build/types/cli.d.ts +23 -6
- package/build/types/cli.d.ts.map +1 -1
- package/lib/cli/args.js +10 -0
- package/lib/cli/parser.js +52 -2
- package/lib/cli/setup-command.js +185 -0
- package/lib/config.js +81 -20
- package/lib/constants.js +31 -6
- package/lib/grid-register.js +2 -2
- package/lib/logsink.js +24 -5
- package/lib/main.js +17 -1
- package/lib/utils.js +15 -3
- package/package.json +14 -14
- package/types/cli.ts +33 -8
package/lib/cli/args.js
CHANGED
|
@@ -290,6 +290,16 @@ const serverArgsDisallowedInConfig = new Map([
|
|
|
290
290
|
help: 'Show info about the Appium build and exit',
|
|
291
291
|
},
|
|
292
292
|
],
|
|
293
|
+
[
|
|
294
|
+
['--show-debug-info'],
|
|
295
|
+
{
|
|
296
|
+
dest: 'showDebugInfo',
|
|
297
|
+
action: 'store_const',
|
|
298
|
+
const: true,
|
|
299
|
+
required: false,
|
|
300
|
+
help: 'Show debug info about the current Appium deployment and exit',
|
|
301
|
+
},
|
|
302
|
+
],
|
|
293
303
|
[
|
|
294
304
|
['--show-config'],
|
|
295
305
|
{
|
package/lib/cli/parser.js
CHANGED
|
@@ -11,11 +11,19 @@ import {
|
|
|
11
11
|
EXT_SUBCOMMAND_UNINSTALL,
|
|
12
12
|
EXT_SUBCOMMAND_UPDATE,
|
|
13
13
|
PLUGIN_TYPE,
|
|
14
|
-
SERVER_SUBCOMMAND
|
|
14
|
+
SERVER_SUBCOMMAND,
|
|
15
|
+
SETUP_SUBCOMMAND
|
|
15
16
|
} from '../constants';
|
|
16
17
|
import {finalizeSchema, getArgSpec, hasArgSpec} from '../schema';
|
|
17
18
|
import {rootDir} from '../config';
|
|
18
19
|
import {getExtensionArgs, getServerArgs} from './args';
|
|
20
|
+
import {
|
|
21
|
+
SUBCOMMAND_MOBILE,
|
|
22
|
+
SUBCOMMAND_DESKTOP,
|
|
23
|
+
SUBCOMMAND_BROWSER,
|
|
24
|
+
getPresetDrivers,
|
|
25
|
+
determinePlatformName
|
|
26
|
+
} from './setup-command';
|
|
19
27
|
|
|
20
28
|
export const EXTRA_ARGS = 'extraArgs';
|
|
21
29
|
|
|
@@ -24,7 +32,7 @@ export const EXTRA_ARGS = 'extraArgs';
|
|
|
24
32
|
* will automatially inject the `server` subcommand.
|
|
25
33
|
*/
|
|
26
34
|
const NON_SERVER_ARGS = Object.freeze(
|
|
27
|
-
new Set([DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND, '-h', '--help', '-v', '--version'])
|
|
35
|
+
new Set([SETUP_SUBCOMMAND, DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND, '-h', '--help', '-v', '--version'])
|
|
28
36
|
);
|
|
29
37
|
|
|
30
38
|
const version = fs.readPackageJsonFrom(rootDir).version;
|
|
@@ -76,6 +84,9 @@ class ArgParser {
|
|
|
76
84
|
|
|
77
85
|
const subParsers = parser.add_subparsers({dest: 'subcommand'});
|
|
78
86
|
|
|
87
|
+
// add the 'setup' command
|
|
88
|
+
ArgParser._addSetupToParser(subParsers);
|
|
89
|
+
|
|
79
90
|
// add the 'server' subcommand, and store the raw arguments on the parser
|
|
80
91
|
// object as a way for other parts of the code to work with the arguments
|
|
81
92
|
// conceptually rather than just through argparse
|
|
@@ -280,6 +291,45 @@ class ArgParser {
|
|
|
280
291
|
}
|
|
281
292
|
}
|
|
282
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Add subcommand and sub-sub commands for 'setup' subcommand.
|
|
297
|
+
* @param {import('argparse').SubParser} subParser
|
|
298
|
+
*/
|
|
299
|
+
static _addSetupToParser(subParser) {
|
|
300
|
+
const setupParser = subParser.add_parser('setup', {
|
|
301
|
+
add_help: true,
|
|
302
|
+
help: `Select a preset of official drivers/plugins to install ` +
|
|
303
|
+
`compatible with '${determinePlatformName()}' host platform. ` +
|
|
304
|
+
`Existing drivers/plugins will remain. The default preset is 'mobile'.`,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
ArgParser._patchExit(setupParser);
|
|
309
|
+
const extSubParsers = setupParser.add_subparsers({
|
|
310
|
+
dest: `setupCommand`,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const parserSpecs = [
|
|
314
|
+
{
|
|
315
|
+
command: SUBCOMMAND_MOBILE,
|
|
316
|
+
help: `The preset for mobile devices: ${_.join(getPresetDrivers(SUBCOMMAND_MOBILE), ',')}`
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
command: SUBCOMMAND_BROWSER,
|
|
320
|
+
help: `The preset for desktop browser drivers: ${_.join(getPresetDrivers(SUBCOMMAND_BROWSER), ',')}`
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
command: SUBCOMMAND_DESKTOP,
|
|
324
|
+
help: `The preset for desktop application drivers: ${_.join(getPresetDrivers(SUBCOMMAND_DESKTOP), ',')}`
|
|
325
|
+
},
|
|
326
|
+
];
|
|
327
|
+
|
|
328
|
+
for (const {command, help} of parserSpecs) {
|
|
329
|
+
const parser = extSubParsers.add_parser(command, {help});
|
|
330
|
+
ArgParser._patchExit(parser);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
283
333
|
}
|
|
284
334
|
|
|
285
335
|
/**
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {
|
|
3
|
+
DESKTOP_BROWSERS,
|
|
4
|
+
DESKTOP_DRIVERS,
|
|
5
|
+
MOBILE_DRIVERS
|
|
6
|
+
} from '../constants';
|
|
7
|
+
import {runExtensionCommand} from './extension';
|
|
8
|
+
import { system } from '@appium/support';
|
|
9
|
+
import log from '../logger';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Subcommands of preset for setup
|
|
13
|
+
*/
|
|
14
|
+
export const SUBCOMMAND_MOBILE = 'mobile';
|
|
15
|
+
export const SUBCOMMAND_DESKTOP = 'desktop';
|
|
16
|
+
export const SUBCOMMAND_BROWSER = 'browser';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pairs of preset subcommand and driver candidates.
|
|
20
|
+
* Driver names listed in KNOWN_DRIVERS to install by default
|
|
21
|
+
*/
|
|
22
|
+
const PRESET_PAIRS = Object.freeze(
|
|
23
|
+
/** @type {const} */ ({
|
|
24
|
+
mobile: _.keys(MOBILE_DRIVERS),
|
|
25
|
+
desktop: _.keys(DESKTOP_DRIVERS),
|
|
26
|
+
browser: _.keys(DESKTOP_BROWSERS)
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
const DRIVERS_ONLY_MACOS = ['xcuitest', 'safari', 'mac2'];
|
|
30
|
+
|
|
31
|
+
const DRIVERS_ONLY_WINDOWS = ['windows'];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Plugin names listed in KNOWN_PLUGINS to install by default.
|
|
35
|
+
*/
|
|
36
|
+
export const DEFAULT_PLUGINS = ['images'];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Return a list of drivers available for current host platform.
|
|
40
|
+
* @param {import('appium/types').CliCommandSetupSubcommand} presetName
|
|
41
|
+
* @returns {Array<string>}
|
|
42
|
+
*/
|
|
43
|
+
export function getPresetDrivers(presetName) {
|
|
44
|
+
return _.filter(PRESET_PAIRS[presetName], (driver) => {
|
|
45
|
+
if (_.includes(DRIVERS_ONLY_MACOS, driver)) {
|
|
46
|
+
return system.isMac();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (_.includes(DRIVERS_ONLY_WINDOWS, driver)) {
|
|
50
|
+
return system.isWindows();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Return desktop platform name for setup command description.
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
export function determinePlatformName() {
|
|
63
|
+
if (system.isMac()) {
|
|
64
|
+
return 'macOS';
|
|
65
|
+
} else if (system.isWindows()) {
|
|
66
|
+
return 'Windows';
|
|
67
|
+
}
|
|
68
|
+
return 'Linux';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Run 'setup' command to install drivers/plugins into the given appium home.
|
|
73
|
+
* @template {import('appium/types').CliCommandSetup} SetupCmd
|
|
74
|
+
* @param {import('appium/types').Args<SetupCmd>} preConfigArgs
|
|
75
|
+
* @param {string} appiumHome
|
|
76
|
+
* @param {DriverConfig} driverConfig
|
|
77
|
+
* @param {PluginConfig} pluginConfig
|
|
78
|
+
* @returns {Promise<void>}
|
|
79
|
+
*/
|
|
80
|
+
export async function runSetupCommand(appiumHome, preConfigArgs, driverConfig, pluginConfig) {
|
|
81
|
+
switch (preConfigArgs.setupCommand) {
|
|
82
|
+
case SUBCOMMAND_DESKTOP:
|
|
83
|
+
await setupDesktopAppDrivers(driverConfig);
|
|
84
|
+
await setupDefaultPlugins(pluginConfig);
|
|
85
|
+
break;
|
|
86
|
+
case SUBCOMMAND_BROWSER:
|
|
87
|
+
await setupBrowserDrivers(driverConfig);
|
|
88
|
+
await setupDefaultPlugins(pluginConfig);
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
await setupMobileDrivers(driverConfig);
|
|
92
|
+
await setupDefaultPlugins(pluginConfig);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Install drivers listed in DEFAULT_DRIVERS.
|
|
99
|
+
* @param {DriverConfig} driverConfig
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
async function setupMobileDrivers(driverConfig) {
|
|
103
|
+
await installDrivers(SUBCOMMAND_MOBILE, driverConfig);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Install all of known drivers listed in BROWSER_DRIVERS.
|
|
108
|
+
* @param {DriverConfig} driverConfig
|
|
109
|
+
* @returns {Promise<void>}
|
|
110
|
+
*/
|
|
111
|
+
async function setupBrowserDrivers(driverConfig) {
|
|
112
|
+
await installDrivers(SUBCOMMAND_BROWSER, driverConfig);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Install all of known drivers listed in DESKTOP_APP_DRIVERS.
|
|
117
|
+
* @param {DriverConfig} driverConfig
|
|
118
|
+
* @returns {Promise<void>}
|
|
119
|
+
*/
|
|
120
|
+
async function setupDesktopAppDrivers(driverConfig) {
|
|
121
|
+
await installDrivers(SUBCOMMAND_DESKTOP, driverConfig);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Install the given driver name. It skips the installation if the given driver name was already installed.
|
|
126
|
+
* @param {import('appium/types').CliCommandSetupSubcommand} subcommand
|
|
127
|
+
* @param {DriverConfig} driverConfig
|
|
128
|
+
* @returns {Promise<void>}
|
|
129
|
+
*/
|
|
130
|
+
async function installDrivers(subcommand, driverConfig) {
|
|
131
|
+
for (const driverName of getPresetDrivers(subcommand)) {
|
|
132
|
+
await installExtension(driverName, extensionCommandArgs('driver', driverName, 'install'), driverConfig);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Install plugins listed in DEFAULT_PLUGINS.
|
|
138
|
+
* @param {PluginConfig} pluginConfig
|
|
139
|
+
* @returns {Promise<void>}
|
|
140
|
+
*/
|
|
141
|
+
async function setupDefaultPlugins(pluginConfig) {
|
|
142
|
+
for (const pluginName of DEFAULT_PLUGINS) {
|
|
143
|
+
await installExtension(pluginName, extensionCommandArgs('plugin', pluginName, 'install'), pluginConfig);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Run the given extensionConfigArgs command after checking if the given extensionName was already installed.
|
|
149
|
+
* @param {string} extensionName
|
|
150
|
+
* @param {Args} extensionConfigArgs
|
|
151
|
+
* @param {DriverConfig|PluginConfig} extensionConfig
|
|
152
|
+
* @returns
|
|
153
|
+
*/
|
|
154
|
+
async function installExtension(extensionName, extensionConfigArgs, extensionConfig) {
|
|
155
|
+
if (_.keys(extensionConfig.installedExtensions).includes(extensionName)) {
|
|
156
|
+
log.info(`${extensionName} (${extensionConfig.installedExtensions[extensionName].version}) is already installed. ` +
|
|
157
|
+
`Skipping the installation.`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
await runExtensionCommand(extensionConfigArgs, extensionConfig);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Return the command config for driver or plugin.
|
|
165
|
+
* @param {CliExtensionCommand} extensionCommand
|
|
166
|
+
* @param {string} extensionName
|
|
167
|
+
* @param {CliExtensionSubcommand} command
|
|
168
|
+
* @returns {Args}
|
|
169
|
+
*/
|
|
170
|
+
function extensionCommandArgs(extensionCommand, extensionName, command) {
|
|
171
|
+
return (extensionCommand === 'plugin')
|
|
172
|
+
? {'subcommand': 'plugin', 'pluginCommand': command, 'plugin': extensionName}
|
|
173
|
+
: {'subcommand': 'driver', 'driverCommand': command, 'driver': extensionName};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @typedef {import('appium/types').CliExtensionCommand} CliExtensionCommand
|
|
178
|
+
* @typedef {import('appium/types').CliExtensionSubcommand} CliExtensionSubcommand
|
|
179
|
+
* @typedef {import('../extension/extension-config').ExtensionConfig<CliExtensionCommand>} PluginConfig
|
|
180
|
+
* @typedef {import('../extension/extension-config').ExtensionConfig<CliExtensionCommand>} DriverConfig
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @typedef {import('appium/types').Args<CliExtensionCommand, CliExtensionSubcommand>} Args
|
|
185
|
+
*/
|
package/lib/config.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {system, fs} from '@appium/support';
|
|
3
|
+
import {system, fs, npm} from '@appium/support';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import {exec} from 'teen_process';
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import {npmPackage} from './utils';
|
|
9
|
+
import B from 'bluebird';
|
|
9
10
|
import {getDefaultsForSchema, getAllArgSpecs} from './schema/schema';
|
|
10
11
|
|
|
11
12
|
export const APPIUM_VER = npmPackage.version;
|
|
12
13
|
const ENGINES = /** @type {Record<string,string>} */ (npmPackage.engines);
|
|
13
14
|
const MIN_NODE_VERSION = ENGINES.node;
|
|
15
|
+
export const rootDir = fs.findRoot(__dirname);
|
|
14
16
|
|
|
15
17
|
const GIT_BINARY = `git${system.isWindows() ? '.exe' : ''}`;
|
|
16
18
|
const GITHUB_API = 'https://api.github.com/repos/appium/appium';
|
|
@@ -28,8 +30,9 @@ function getNodeVersion() {
|
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* @param {boolean} [useGithubApiFallback]
|
|
33
|
+
* @returns {Promise<void>}
|
|
31
34
|
*/
|
|
32
|
-
async function updateBuildInfo(useGithubApiFallback = false) {
|
|
35
|
+
export async function updateBuildInfo(useGithubApiFallback = false) {
|
|
33
36
|
const sha = await getGitRev(useGithubApiFallback);
|
|
34
37
|
if (!sha) {
|
|
35
38
|
return;
|
|
@@ -50,11 +53,61 @@ const getFullGitPath = _.memoize(async function getFullGitPath() {
|
|
|
50
53
|
}
|
|
51
54
|
});
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Prints server debug into into the console.
|
|
58
|
+
*
|
|
59
|
+
* @param {{
|
|
60
|
+
* driverConfig: import('./extension/driver-config').DriverConfig,
|
|
61
|
+
* pluginConfig: import('./extension/plugin-config').PluginConfig,
|
|
62
|
+
* appiumHome: string
|
|
63
|
+
* }} info
|
|
64
|
+
* @returns {Promise<void>}
|
|
65
|
+
*/
|
|
66
|
+
export async function showDebugInfo({driverConfig, pluginConfig, appiumHome}) {
|
|
67
|
+
const getNpmVersion = async () => {
|
|
68
|
+
const {stdout} = await npm.exec('--version', [], {cwd: process.cwd()});
|
|
69
|
+
return _.trim(stdout);
|
|
70
|
+
};
|
|
71
|
+
const findNpmLocation = async () => await fs.which(system.isWindows() ? 'npm.cmd' : 'npm');
|
|
72
|
+
const [npmVersion, npmLocation] = await B.all([
|
|
73
|
+
...([getNpmVersion, findNpmLocation].map((f) => getSafeResult(f, 'unknown'))),
|
|
74
|
+
/** @type {any} */ (updateBuildInfo()),
|
|
75
|
+
]);
|
|
76
|
+
const debugInfo = {
|
|
77
|
+
os: {
|
|
78
|
+
platform: os.platform(),
|
|
79
|
+
release: os.release(),
|
|
80
|
+
arch: os.arch(),
|
|
81
|
+
homedir: os.homedir(),
|
|
82
|
+
username: os.userInfo().username,
|
|
83
|
+
},
|
|
84
|
+
node: {
|
|
85
|
+
version: process.version,
|
|
86
|
+
arch: process.arch,
|
|
87
|
+
cwd: process.cwd(),
|
|
88
|
+
argv: process.argv,
|
|
89
|
+
env: process.env,
|
|
90
|
+
npm: {
|
|
91
|
+
location: npmLocation,
|
|
92
|
+
version: npmVersion,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
appium: {
|
|
96
|
+
location: rootDir,
|
|
97
|
+
homedir: appiumHome,
|
|
98
|
+
build: getBuildInfo(),
|
|
99
|
+
drivers: driverConfig.installedExtensions,
|
|
100
|
+
plugins: pluginConfig.installedExtensions,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
console.log(JSON.stringify(debugInfo, null, 2));
|
|
104
|
+
}
|
|
105
|
+
|
|
53
106
|
/**
|
|
54
107
|
* @param {boolean} [useGithubApiFallback]
|
|
55
108
|
* @returns {Promise<string?>}
|
|
56
109
|
*/
|
|
57
|
-
async function getGitRev(useGithubApiFallback = false) {
|
|
110
|
+
export async function getGitRev(useGithubApiFallback = false) {
|
|
58
111
|
const fullGitPath = await getFullGitPath();
|
|
59
112
|
if (fullGitPath) {
|
|
60
113
|
try {
|
|
@@ -122,11 +175,15 @@ async function getGitTimestamp(commitSha, useGithubApiFallback = false) {
|
|
|
122
175
|
* and succeeds.
|
|
123
176
|
* @returns {import('appium/types').BuildInfo}
|
|
124
177
|
*/
|
|
125
|
-
function getBuildInfo() {
|
|
178
|
+
export function getBuildInfo() {
|
|
126
179
|
return BUILD_INFO;
|
|
127
180
|
}
|
|
128
181
|
|
|
129
|
-
|
|
182
|
+
/**
|
|
183
|
+
* @returns {void}
|
|
184
|
+
* @throws {Error} If Node version is outside of the supported range
|
|
185
|
+
*/
|
|
186
|
+
export function checkNodeOk() {
|
|
130
187
|
const version = getNodeVersion();
|
|
131
188
|
if (!semver.satisfies(version, MIN_NODE_VERSION)) {
|
|
132
189
|
throw new Error(
|
|
@@ -135,7 +192,7 @@ function checkNodeOk() {
|
|
|
135
192
|
}
|
|
136
193
|
}
|
|
137
194
|
|
|
138
|
-
async function showBuildInfo() {
|
|
195
|
+
export async function showBuildInfo() {
|
|
139
196
|
await updateBuildInfo(true);
|
|
140
197
|
console.log(JSON.stringify(getBuildInfo())); // eslint-disable-line no-console
|
|
141
198
|
}
|
|
@@ -145,7 +202,7 @@ async function showBuildInfo() {
|
|
|
145
202
|
* @param {Args} parsedArgs
|
|
146
203
|
* @returns {Args}
|
|
147
204
|
*/
|
|
148
|
-
function getNonDefaultServerArgs(parsedArgs) {
|
|
205
|
+
export function getNonDefaultServerArgs(parsedArgs) {
|
|
149
206
|
/**
|
|
150
207
|
* Flattens parsed args into a single level object for comparison with
|
|
151
208
|
* flattened defaults across server args and extension args.
|
|
@@ -253,7 +310,7 @@ const compactConfig = _.partial(
|
|
|
253
310
|
* @param {Partial<ParsedArgs>} defaults - Configuration defaults from schemas
|
|
254
311
|
* @param {ParsedArgs} parsedArgs - Entire parsed args object
|
|
255
312
|
*/
|
|
256
|
-
function showConfig(nonDefaultPreConfigParsedArgs, configResult, defaults, parsedArgs) {
|
|
313
|
+
export function showConfig(nonDefaultPreConfigParsedArgs, configResult, defaults, parsedArgs) {
|
|
257
314
|
console.log('Appium Configuration\n');
|
|
258
315
|
console.log('from defaults:\n');
|
|
259
316
|
console.dir(compactConfig(defaults));
|
|
@@ -308,18 +365,22 @@ export async function requireDir(root, requireWriteable = true, displayName = 'f
|
|
|
308
365
|
}
|
|
309
366
|
}
|
|
310
367
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Calculates the result of the given function and return its value
|
|
370
|
+
* or the default one if there was an exception.
|
|
371
|
+
*
|
|
372
|
+
* @template T
|
|
373
|
+
* @param {() => Promise<T>} f
|
|
374
|
+
* @param {T} defaultValue
|
|
375
|
+
* @returns {Promise<T>}
|
|
376
|
+
*/
|
|
377
|
+
async function getSafeResult(f, defaultValue) {
|
|
378
|
+
try {
|
|
379
|
+
return await f();
|
|
380
|
+
} catch {
|
|
381
|
+
return defaultValue;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
323
384
|
|
|
324
385
|
/**
|
|
325
386
|
* @typedef {import('appium/types').ParsedArgs} ParsedArgs
|
package/lib/constants.js
CHANGED
|
@@ -15,6 +15,12 @@ export const PLUGIN_TYPE = 'plugin';
|
|
|
15
15
|
*/
|
|
16
16
|
export const SERVER_SUBCOMMAND = 'server';
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* The `setup` command of the `appium` CLI
|
|
20
|
+
*/
|
|
21
|
+
export const SETUP_SUBCOMMAND = 'setup';
|
|
22
|
+
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* The value of `--use-plugins` if _all_ plugins should be loaded
|
|
20
26
|
*/
|
|
@@ -33,22 +39,41 @@ export const KNOWN_PLUGINS = Object.freeze(
|
|
|
33
39
|
}),
|
|
34
40
|
);
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
// The drivers in this list will be available to the CLI so users can just
|
|
38
|
-
// type 'appium driver install 'name'', rather than having to specify the full
|
|
39
|
-
// npm package. I.e., these are the officially recognized drivers.
|
|
40
|
-
export const KNOWN_DRIVERS = Object.freeze(
|
|
42
|
+
export const MOBILE_DRIVERS = Object.freeze(
|
|
41
43
|
/** @type {const} */ ({
|
|
42
44
|
uiautomator2: 'appium-uiautomator2-driver',
|
|
43
45
|
xcuitest: 'appium-xcuitest-driver',
|
|
44
|
-
mac2: 'appium-mac2-driver',
|
|
45
46
|
espresso: 'appium-espresso-driver',
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export const DESKTOP_DRIVERS = Object.freeze(
|
|
51
|
+
/** @type {const} */ ({
|
|
52
|
+
mac2: 'appium-mac2-driver',
|
|
53
|
+
windows: 'appium-windows-driver',
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
export const DESKTOP_BROWSERS = Object.freeze(
|
|
58
|
+
/** @type {const} */ ({
|
|
46
59
|
safari: 'appium-safari-driver',
|
|
47
60
|
gecko: 'appium-geckodriver',
|
|
48
61
|
chromium: 'appium-chromium-driver',
|
|
49
62
|
}),
|
|
50
63
|
);
|
|
51
64
|
|
|
65
|
+
// This is a map of driver names to npm packages representing those drivers.
|
|
66
|
+
// The drivers in this list will be available to the CLI so users can just
|
|
67
|
+
// type 'appium driver install 'name'', rather than having to specify the full
|
|
68
|
+
// npm package. I.e., these are the officially recognized drivers.
|
|
69
|
+
export const KNOWN_DRIVERS = Object.freeze(
|
|
70
|
+
/** @type {const} */ ({
|
|
71
|
+
...MOBILE_DRIVERS,
|
|
72
|
+
...DESKTOP_DRIVERS,
|
|
73
|
+
...DESKTOP_BROWSERS,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
|
|
52
77
|
/**
|
|
53
78
|
* Relative path to directory containing any Appium internal files
|
|
54
79
|
*/
|
package/lib/grid-register.js
CHANGED
|
@@ -57,13 +57,13 @@ function postRequest(configHolder, addr, port, basePath) {
|
|
|
57
57
|
// Move Selenium 3 configuration properties to configuration object
|
|
58
58
|
if (!_.has(configHolder, 'configuration')) {
|
|
59
59
|
let configuration = {};
|
|
60
|
-
for (const property in configHolder) {
|
|
60
|
+
for (const property in /** @type {import('@appium/types').StringRecord} */ (configHolder)) {
|
|
61
61
|
if (_.has(configHolder, property) && property !== 'capabilities') {
|
|
62
62
|
configuration[property] = configHolder[property];
|
|
63
63
|
delete configHolder[property];
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
configHolder.configuration = configuration;
|
|
66
|
+
/** @type {import('@appium/types').StringRecord} */ (configHolder).configuration = configuration;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// if the node config does not have the appium/webdriver url, host, and port,
|
package/lib/logsink.js
CHANGED
|
@@ -131,8 +131,13 @@ function createHttpTransport(args, logLvl) {
|
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {import('@appium/types').StringRecord} args
|
|
137
|
+
* @returns {Promise<import('winston-transport')[]>}
|
|
138
|
+
*/
|
|
134
139
|
async function createTransports(args) {
|
|
135
|
-
|
|
140
|
+
const transports = [];
|
|
136
141
|
let consoleLogLevel = null;
|
|
137
142
|
let fileLogLevel = null;
|
|
138
143
|
|
|
@@ -201,11 +206,14 @@ async function init(args) {
|
|
|
201
206
|
// clean up in case we have initiated before since npmlog is a global object
|
|
202
207
|
clear();
|
|
203
208
|
|
|
209
|
+
const transports = await createTransports(args);
|
|
210
|
+
const transportNames = new Set(transports.map((tr) => tr.constructor.name));
|
|
204
211
|
log = createLogger({
|
|
205
|
-
transports
|
|
212
|
+
transports,
|
|
206
213
|
levels,
|
|
207
214
|
});
|
|
208
215
|
|
|
216
|
+
const reportedLoggerErrors = new Set();
|
|
209
217
|
// Capture logs emitted via npmlog and pass them through winston
|
|
210
218
|
npmlog.on('log', ({level, message, prefix}) => {
|
|
211
219
|
const winstonLevel = npmToWinstonLevels[level] || 'info';
|
|
@@ -217,9 +225,20 @@ async function init(args) {
|
|
|
217
225
|
: getColorizedPrefix(decoratedPrefix);
|
|
218
226
|
msg = `${args.logNoColors ? decoratedPrefix : toColorizedDecoratedPrefix()} ${msg}`;
|
|
219
227
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
args.logHandler
|
|
228
|
+
try {
|
|
229
|
+
log[winstonLevel](msg);
|
|
230
|
+
if (_.isFunction(args.logHandler)) {
|
|
231
|
+
args.logHandler(level, msg);
|
|
232
|
+
}
|
|
233
|
+
} catch (e) {
|
|
234
|
+
if (!reportedLoggerErrors.has(e.message) && process.stderr.writable) {
|
|
235
|
+
// eslint-disable-next-line no-console
|
|
236
|
+
console.error(
|
|
237
|
+
`The log message '${_.truncate(msg, {length: 30})}' cannot be written into ` +
|
|
238
|
+
`one or more requested destinations: ${transportNames}. Original error: ${e.message}`
|
|
239
|
+
);
|
|
240
|
+
reportedLoggerErrors.add(e.message);
|
|
241
|
+
}
|
|
223
242
|
}
|
|
224
243
|
});
|
|
225
244
|
}
|
package/lib/main.js
CHANGED
|
@@ -13,6 +13,7 @@ import {asyncify} from 'asyncbox';
|
|
|
13
13
|
import _ from 'lodash';
|
|
14
14
|
import {AppiumDriver} from './appium';
|
|
15
15
|
import {runExtensionCommand} from './cli/extension';
|
|
16
|
+
import { runSetupCommand } from './cli/setup-command';
|
|
16
17
|
import {getParser} from './cli/parser';
|
|
17
18
|
import {
|
|
18
19
|
APPIUM_VER,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
getNonDefaultServerArgs,
|
|
22
23
|
showConfig,
|
|
23
24
|
showBuildInfo,
|
|
25
|
+
showDebugInfo,
|
|
24
26
|
requireDir,
|
|
25
27
|
} from './config';
|
|
26
28
|
import {readConfigFile} from './config-file';
|
|
@@ -38,6 +40,7 @@ import {
|
|
|
38
40
|
fetchInterfaces,
|
|
39
41
|
V4_BROADCAST_IP,
|
|
40
42
|
V6_BROADCAST_IP,
|
|
43
|
+
isSetupCommandArgs,
|
|
41
44
|
} from './utils';
|
|
42
45
|
import net from 'node:net';
|
|
43
46
|
|
|
@@ -216,7 +219,7 @@ async function init(args) {
|
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
// merge config and apply defaults.
|
|
219
|
-
// the order of
|
|
222
|
+
// the order of precedence is:
|
|
220
223
|
// 1. command line args
|
|
221
224
|
// 2. config file
|
|
222
225
|
// 3. defaults from config file.
|
|
@@ -231,6 +234,15 @@ async function init(args) {
|
|
|
231
234
|
return /** @type {InitResult<Cmd>} */ ({});
|
|
232
235
|
}
|
|
233
236
|
|
|
237
|
+
if (preConfigArgs.showDebugInfo) {
|
|
238
|
+
await showDebugInfo({
|
|
239
|
+
driverConfig,
|
|
240
|
+
pluginConfig,
|
|
241
|
+
appiumHome,
|
|
242
|
+
});
|
|
243
|
+
return /** @type {InitResult<Cmd>} */ ({});
|
|
244
|
+
}
|
|
245
|
+
|
|
234
246
|
await logsinkInit(serverArgs);
|
|
235
247
|
|
|
236
248
|
if (serverArgs.logFilters) {
|
|
@@ -276,6 +288,9 @@ async function init(args) {
|
|
|
276
288
|
pluginConfig,
|
|
277
289
|
appiumHome,
|
|
278
290
|
});
|
|
291
|
+
} else if (isSetupCommandArgs(preConfigArgs)) {
|
|
292
|
+
await runSetupCommand(appiumHome, preConfigArgs, driverConfig, pluginConfig);
|
|
293
|
+
return /** @type {InitResult<Cmd>} */ ({});
|
|
279
294
|
} else {
|
|
280
295
|
await requireDir(appiumHome, true, appiumHomeSourceName);
|
|
281
296
|
if (isExtensionCommandArgs(preConfigArgs)) {
|
|
@@ -465,6 +480,7 @@ export {main, init, resolveAppiumHome};
|
|
|
465
480
|
* @typedef {import('appium/types').CliCommandServer} ServerCommand
|
|
466
481
|
* @typedef {import('appium/types').CliCommandDriver} DriverCommand
|
|
467
482
|
* @typedef {import('appium/types').CliCommandPlugin} PluginCommand
|
|
483
|
+
* @typedef {import('appium/types').CliCommandSetup} SetupCommand
|
|
468
484
|
* @typedef {import('./extension').DriverNameMap} DriverNameMap
|
|
469
485
|
* @typedef {import('./extension').PluginNameMap} PluginNameMap
|
|
470
486
|
*/
|