appium 2.0.0-beta.23 → 2.0.0-beta.26
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/README.md +1 -2
- package/build/lib/appium-config.schema.json +278 -0
- package/build/lib/appium.js +62 -71
- package/build/lib/cli/args.js +31 -53
- package/build/lib/cli/driver-command.js +5 -9
- package/build/lib/cli/extension-command.js +73 -64
- package/build/lib/cli/extension.js +10 -23
- package/build/lib/cli/parser.js +10 -20
- package/build/lib/cli/plugin-command.js +5 -9
- package/build/lib/cli/utils.js +2 -4
- package/build/lib/config-file.js +5 -10
- package/build/lib/config.js +67 -30
- package/build/lib/constants.js +60 -0
- package/build/lib/extension/driver-config.js +190 -0
- package/build/lib/extension/extension-config.js +297 -0
- package/build/lib/extension/index.js +77 -0
- package/build/lib/extension/manifest.js +246 -0
- package/build/lib/extension/package-changed.js +68 -0
- package/build/lib/extension/plugin-config.js +87 -0
- package/build/lib/grid-register.js +2 -4
- package/build/lib/logger.js +2 -4
- package/build/lib/logsink.js +2 -4
- package/build/lib/main.js +64 -92
- package/build/lib/schema/appium-config-schema.js +2 -4
- package/build/lib/schema/arg-spec.js +14 -15
- package/build/lib/schema/cli-args.js +8 -16
- package/build/lib/schema/cli-transformers.js +2 -4
- package/build/lib/schema/index.js +2 -4
- package/build/lib/schema/keywords.js +2 -4
- package/build/lib/schema/schema.js +136 -41
- package/build/lib/utils.js +13 -64
- package/lib/appium.js +74 -55
- package/lib/cli/args.js +36 -37
- package/lib/cli/driver-command.js +10 -2
- package/lib/cli/extension-command.js +216 -135
- package/lib/cli/extension.js +7 -15
- package/lib/cli/parser.js +7 -15
- package/lib/cli/plugin-command.js +1 -2
- package/lib/config-file.js +12 -15
- package/lib/config.js +111 -36
- package/lib/constants.js +79 -0
- package/lib/extension/driver-config.js +230 -0
- package/lib/extension/extension-config.js +459 -0
- package/lib/extension/index.js +103 -0
- package/lib/extension/manifest.js +590 -0
- package/lib/extension/package-changed.js +64 -0
- package/lib/extension/plugin-config.js +111 -0
- package/lib/grid-register.js +4 -4
- package/lib/main.js +110 -96
- package/lib/schema/arg-spec.js +11 -5
- package/lib/schema/cli-args.js +7 -30
- package/lib/schema/keywords.js +1 -1
- package/lib/schema/schema.js +206 -48
- package/lib/utils.js +27 -58
- package/package.json +29 -21
- package/{postinstall.js → scripts/postinstall.js} +1 -1
- package/types/types.d.ts +72 -28
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/check-npm-pack-files.js +0 -23
- package/build/commands-yml/parse.js +0 -319
- package/build/commands-yml/validator.js +0 -130
- package/build/index.js +0 -19
- package/build/lib/cli/npm.js +0 -220
- package/build/lib/driver-config.js +0 -100
- package/build/lib/drivers.js +0 -100
- package/build/lib/ext-config-io.js +0 -165
- package/build/lib/extension-config.js +0 -320
- package/build/lib/plugin-config.js +0 -69
- package/build/lib/plugins.js +0 -16
- package/build/postinstall.js +0 -90
- package/build/test/cli/cli-e2e-specs.js +0 -221
- package/build/test/cli/cli-helpers.js +0 -86
- package/build/test/cli/cli-specs.js +0 -71
- package/build/test/cli/fixtures/test-driver/package.json +0 -27
- package/build/test/cli/schema-args-specs.js +0 -48
- package/build/test/cli/schema-e2e-specs.js +0 -47
- package/build/test/config-e2e-specs.js +0 -112
- package/build/test/config-file-e2e-specs.js +0 -209
- package/build/test/config-file-specs.js +0 -281
- package/build/test/config-specs.js +0 -159
- package/build/test/driver-e2e-specs.js +0 -435
- package/build/test/driver-specs.js +0 -321
- package/build/test/ext-config-io-specs.js +0 -181
- package/build/test/extension-config-specs.js +0 -365
- package/build/test/fixtures/allow-feat.txt +0 -5
- package/build/test/fixtures/caps.json +0 -3
- package/build/test/fixtures/config/allow-insecure.txt +0 -3
- package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
- package/build/test/fixtures/config/appium.config.bad.json +0 -32
- package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
- package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
- package/build/test/fixtures/config/appium.config.good.js +0 -40
- package/build/test/fixtures/config/appium.config.good.json +0 -33
- package/build/test/fixtures/config/appium.config.good.yaml +0 -30
- package/build/test/fixtures/config/appium.config.invalid.json +0 -31
- package/build/test/fixtures/config/appium.config.security-array.json +0 -5
- package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
- package/build/test/fixtures/config/appium.config.security-path.json +0 -5
- package/build/test/fixtures/config/driver-fake.config.json +0 -8
- package/build/test/fixtures/config/nodeconfig.json +0 -3
- package/build/test/fixtures/config/plugin-fake.config.json +0 -0
- package/build/test/fixtures/default-args.js +0 -35
- package/build/test/fixtures/deny-feat.txt +0 -5
- package/build/test/fixtures/driver.schema.js +0 -20
- package/build/test/fixtures/extensions.yaml +0 -27
- package/build/test/fixtures/flattened-schema.js +0 -504
- package/build/test/fixtures/plugin.schema.js +0 -20
- package/build/test/fixtures/schema-with-extensions.js +0 -28
- package/build/test/grid-register-specs.js +0 -74
- package/build/test/helpers.js +0 -75
- package/build/test/logger-specs.js +0 -76
- package/build/test/npm-specs.js +0 -20
- package/build/test/parser-specs.js +0 -314
- package/build/test/plugin-e2e-specs.js +0 -316
- package/build/test/schema/arg-spec-specs.js +0 -70
- package/build/test/schema/cli-args-specs.js +0 -431
- package/build/test/schema/schema-specs.js +0 -389
- package/build/test/utils-specs.js +0 -266
- package/lib/cli/npm.js +0 -251
- package/lib/driver-config.js +0 -101
- package/lib/drivers.js +0 -84
- package/lib/ext-config-io.js +0 -287
- package/lib/extension-config.js +0 -366
- package/lib/plugin-config.js +0 -63
- package/lib/plugins.js +0 -11
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import {ExtensionConfig} from './extension-config';
|
|
5
|
+
import log from '../logger';
|
|
6
|
+
import {PLUGIN_TYPE} from '../constants';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @extends {ExtensionConfig<PluginType>}
|
|
10
|
+
*/
|
|
11
|
+
export class PluginConfig extends ExtensionConfig {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A mapping of {@link Manifest} instances to {@link PluginConfig} instances.
|
|
15
|
+
*
|
|
16
|
+
* `Manifest` and {@link ExtensionConfig} have a one-to-many relationship; each `Manifest` should be associated with a `DriverConfig` and a `PluginConfig`; no more, no less.
|
|
17
|
+
*
|
|
18
|
+
* This variable tracks the `Manifest`-to-`PluginConfig` portion.
|
|
19
|
+
*
|
|
20
|
+
* @type {WeakMap<Manifest,PluginConfig>}
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
static _instances = new WeakMap();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Call {@link PluginConfig.create} instead.
|
|
27
|
+
*
|
|
28
|
+
* Just calls the superclass' constructor with the correct extension type
|
|
29
|
+
* @private
|
|
30
|
+
* @param {import('./manifest').Manifest} manifest - IO object
|
|
31
|
+
* @param {PluginConfigOptions} [opts]
|
|
32
|
+
*/
|
|
33
|
+
constructor (manifest, {extData, logFn} = {}) {
|
|
34
|
+
super(PLUGIN_TYPE, manifest, logFn);
|
|
35
|
+
|
|
36
|
+
if (extData) {
|
|
37
|
+
this.validate(extData);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new {@link PluginConfig} instance for a {@link Manifest} instance.
|
|
43
|
+
*
|
|
44
|
+
* @param {Manifest} manifest
|
|
45
|
+
* @param {PluginConfigOptions} [opts]
|
|
46
|
+
* @throws If `manifest` already associated with a `PluginConfig`
|
|
47
|
+
* @returns {PluginConfig}
|
|
48
|
+
*/
|
|
49
|
+
static create (manifest, {extData, logFn} = {}) {
|
|
50
|
+
const instance = new PluginConfig(manifest, {logFn, extData});
|
|
51
|
+
if (PluginConfig.getInstance(manifest)) {
|
|
52
|
+
throw new Error(`Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it.`);
|
|
53
|
+
}
|
|
54
|
+
PluginConfig._instances.set(manifest, instance);
|
|
55
|
+
return instance;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns a PluginConfig associated with a Manifest
|
|
60
|
+
* @param {Manifest} manifest
|
|
61
|
+
* @returns {PluginConfig|undefined}
|
|
62
|
+
*/
|
|
63
|
+
static getInstance (manifest) {
|
|
64
|
+
return PluginConfig._instances.get(manifest);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} pluginName
|
|
68
|
+
* @param {PluginData} pluginData
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
extensionDesc (pluginName, {version}) {
|
|
72
|
+
return `${pluginName}@${version}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* @param {(keyof import('./manifest').ExtRecord<PluginType>)[]} activeNames
|
|
78
|
+
* @returns {void}
|
|
79
|
+
*/
|
|
80
|
+
print (activeNames) {
|
|
81
|
+
const pluginNames = Object.keys(this.installedExtensions);
|
|
82
|
+
|
|
83
|
+
if (_.isEmpty(pluginNames)) {
|
|
84
|
+
log.info(`No plugins have been installed. Use the "appium plugin" ` +
|
|
85
|
+
'command to install the one(s) you want to use.');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
log.info(`Available plugins:`);
|
|
90
|
+
for (const [pluginName, pluginData] of _.toPairs(this.installedExtensions)) {
|
|
91
|
+
const activeTxt = _.includes(activeNames, pluginName) ? ' (ACTIVE)' : '';
|
|
92
|
+
log.info(` - ${this.extensionDesc(pluginName, pluginData)}${activeTxt}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (_.isEmpty(activeNames)) {
|
|
96
|
+
log.info('No plugins activated. Use the --use-plugins flag with names of plugins to activate');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @typedef PluginConfigOptions
|
|
103
|
+
* @property {import('./extension-config').ExtensionLogFn} [logFn] - Optional logging function
|
|
104
|
+
* @property {import('./manifest').ExtRecord<PluginType>} [extData] - Extension data
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {import('./manifest').PluginType} PluginType
|
|
109
|
+
* @typedef {import('./manifest').ExtData<PluginType>} PluginData
|
|
110
|
+
* @typedef {import('./manifest').Manifest} Manifest
|
|
111
|
+
*/
|
package/lib/grid-register.js
CHANGED
|
@@ -11,10 +11,10 @@ const hubUri = (config) => {
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Registers a new node with a selenium grid
|
|
14
|
-
* @param {string|object} data - Path or object representing selenium grid node config file
|
|
15
|
-
* @param {string} addr - Bind to this address
|
|
16
|
-
* @param {number} port - Bind to this port
|
|
17
|
-
* @param {string} basePath - Base path for the grid
|
|
14
|
+
* @param {string|object} data - Path or object representing selenium grid node config file. If a `string`, all subsequent arguments are required!
|
|
15
|
+
* @param {string} [addr] - Bind to this address
|
|
16
|
+
* @param {number} [port] - Bind to this port
|
|
17
|
+
* @param {string} [basePath] - Base path for the grid
|
|
18
18
|
*/
|
|
19
19
|
async function registerNode (data, addr, port, basePath) {
|
|
20
20
|
let configFilePath;
|
package/lib/main.js
CHANGED
|
@@ -3,23 +3,25 @@
|
|
|
3
3
|
// transpile:main
|
|
4
4
|
// @ts-check
|
|
5
5
|
|
|
6
|
+
import { init as logsinkInit } from './logsink'; // this import needs to come first since it sets up global npmlog
|
|
7
|
+
import logger from './logger'; // logger needs to remain second
|
|
6
8
|
// @ts-ignore
|
|
7
9
|
import { routeConfiguringFunction as makeRouter, server as baseServer } from '@appium/base-driver';
|
|
8
|
-
import { logger as logFactory, util } from '@appium/support';
|
|
10
|
+
import { logger as logFactory, util, env } from '@appium/support';
|
|
9
11
|
import { asyncify } from 'asyncbox';
|
|
10
12
|
import _ from 'lodash';
|
|
11
13
|
import { AppiumDriver } from './appium';
|
|
12
|
-
import { driverConfig, pluginConfig, USE_ALL_PLUGINS } from './cli/args';
|
|
13
14
|
import { runExtensionCommand } from './cli/extension';
|
|
14
|
-
import {
|
|
15
|
-
import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showConfig, validateTmpDir, warnNodeDeprecations } from './config';
|
|
15
|
+
import { getParser } from './cli/parser';
|
|
16
|
+
import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showConfig, showBuildInfo, validateTmpDir, warnNodeDeprecations } from './config';
|
|
16
17
|
import { readConfigFile } from './config-file';
|
|
17
|
-
import {
|
|
18
|
+
import { loadExtensions, getActivePlugins, getActiveDrivers } from './extension';
|
|
19
|
+
import { DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND } from './constants';
|
|
18
20
|
import registerNode from './grid-register';
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { getDefaultsForSchema, validate } from './schema/schema';
|
|
22
|
+
import { inspect } from './utils';
|
|
23
|
+
|
|
24
|
+
const {resolveAppiumHome} = env;
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
*
|
|
@@ -32,8 +34,8 @@ async function preflightChecks (args, throwInsteadOfExit = false) {
|
|
|
32
34
|
if (args.longStacktrace) {
|
|
33
35
|
require('longjohn').async_trace_limit = -1;
|
|
34
36
|
}
|
|
35
|
-
if (args.
|
|
36
|
-
await
|
|
37
|
+
if (args.showBuildInfo) {
|
|
38
|
+
await showBuildInfo();
|
|
37
39
|
process.exit(0);
|
|
38
40
|
}
|
|
39
41
|
warnNodeDeprecations();
|
|
@@ -53,18 +55,24 @@ async function preflightChecks (args, throwInsteadOfExit = false) {
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @param {Partial<ParsedArgs>} args
|
|
60
|
+
*/
|
|
56
61
|
function logNonDefaultArgsWarning (args) {
|
|
57
62
|
logger.info('Non-default server args:');
|
|
58
|
-
|
|
63
|
+
inspect(args);
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
function logDefaultCapabilitiesWarning (caps) {
|
|
62
67
|
logger.info('Default capabilities, which will be added to each request ' +
|
|
63
68
|
'unless overridden by desired capabilities:');
|
|
64
|
-
|
|
69
|
+
inspect(caps);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
/**
|
|
73
|
+
* @param {ParsedArgs} args
|
|
74
|
+
*/
|
|
75
|
+
async function logStartupInfo (args) {
|
|
68
76
|
let welcome = `Welcome to Appium v${APPIUM_VER}`;
|
|
69
77
|
let appiumRev = await getGitRev();
|
|
70
78
|
if (appiumRev) {
|
|
@@ -72,7 +80,7 @@ async function logStartupInfo (parser, args) {
|
|
|
72
80
|
}
|
|
73
81
|
logger.info(welcome);
|
|
74
82
|
|
|
75
|
-
let showArgs = getNonDefaultServerArgs(
|
|
83
|
+
let showArgs = getNonDefaultServerArgs(args);
|
|
76
84
|
if (_.size(showArgs)) {
|
|
77
85
|
logNonDefaultArgsWarning(showArgs);
|
|
78
86
|
}
|
|
@@ -86,6 +94,12 @@ async function logStartupInfo (parser, args) {
|
|
|
86
94
|
// }
|
|
87
95
|
}
|
|
88
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Logs the address and port the server is listening on
|
|
99
|
+
* @param {string} address - Address
|
|
100
|
+
* @param {number} port - Port
|
|
101
|
+
* @returns {void}
|
|
102
|
+
*/
|
|
89
103
|
function logServerPort (address, port) {
|
|
90
104
|
let logMessage = `Appium REST http interface listener started on ` +
|
|
91
105
|
`${address}:${port}`;
|
|
@@ -93,61 +107,21 @@ function logServerPort (address, port) {
|
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* @param {Object} args - argparser parsed dict
|
|
102
|
-
* @param {import('./plugin-config').default} pluginConfig - a plugin extension config
|
|
103
|
-
* @returns {({pluginName: string} & ((...args: any[]) => unknown))[]}
|
|
110
|
+
* Gets a list of `updateServer` functions from all extensions
|
|
111
|
+
* @param {DriverClass[]} driverClasses
|
|
112
|
+
* @param {PluginClass[]} pluginClasses
|
|
113
|
+
* @returns {import('./extension/manifest').UpdateServerFn[]}
|
|
104
114
|
*/
|
|
105
|
-
function
|
|
106
|
-
return _.compact(
|
|
107
|
-
_.includes(args.usePlugins, pluginName) ||
|
|
108
|
-
(args.usePlugins.length === 1 && args.usePlugins[0] === USE_ALL_PLUGINS)
|
|
109
|
-
).map((pluginName) => {
|
|
110
|
-
try {
|
|
111
|
-
logger.info(`Attempting to load plugin ${pluginName}...`);
|
|
112
|
-
const PluginClass = /** @type {{pluginName: string} & ((...args: any[]) => unknown)} */(pluginConfig.require(pluginName));
|
|
113
|
-
|
|
114
|
-
PluginClass.pluginName = pluginName; // store the plugin name on the class so it can be used later
|
|
115
|
-
return PluginClass;
|
|
116
|
-
} catch (err) {
|
|
117
|
-
logger.error(`Could not load plugin '${pluginName}', so it will not be available. Error ` +
|
|
118
|
-
`in loading the plugin was: ${err.message}`);
|
|
119
|
-
logger.debug(err.stack);
|
|
120
|
-
}
|
|
121
|
-
}));
|
|
115
|
+
function getServerUpdaters (driverClasses, pluginClasses) {
|
|
116
|
+
return _.compact(_.map([...driverClasses, ...pluginClasses], 'updateServer'));
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* @param {Object} args - argparser parsed dict
|
|
130
|
-
* @param {import('./driver-config').default} driverConfig - a driver extension config
|
|
120
|
+
* Makes a big `MethodMap` from all the little `MethodMap`s in the extensions
|
|
121
|
+
* @param {DriverClass[]} driverClasses
|
|
122
|
+
* @param {PluginClass[]} pluginClasses
|
|
123
|
+
* @returns {import('@appium/base-driver').MethodMap}
|
|
131
124
|
*/
|
|
132
|
-
function getActiveDrivers (args, driverConfig) {
|
|
133
|
-
return _.compact(Object.keys(driverConfig.installedExtensions).filter((driverName) =>
|
|
134
|
-
_.includes(args.useDrivers, driverName) || args.useDrivers.length === 0
|
|
135
|
-
).map((driverName) => {
|
|
136
|
-
try {
|
|
137
|
-
logger.info(`Attempting to load driver ${driverName}...`);
|
|
138
|
-
return driverConfig.require(driverName);
|
|
139
|
-
} catch (err) {
|
|
140
|
-
logger.error(`Could not load driver '${driverName}', so it will not be available. Error ` +
|
|
141
|
-
`in loading the driver was: ${err.message}`);
|
|
142
|
-
logger.debug(err.stack);
|
|
143
|
-
}
|
|
144
|
-
}));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function getServerUpdaters (driverClasses, pluginClasses) {
|
|
148
|
-
return [...driverClasses, ...pluginClasses].map((klass) => klass.updateServer).filter(Boolean);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
125
|
function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
152
126
|
return [...driverClasses, ...pluginClasses].reduce(
|
|
153
127
|
(map, klass) => ({...map, ...klass.newMethodMap}),
|
|
@@ -160,19 +134,33 @@ function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
|
160
134
|
*
|
|
161
135
|
* Use this to get at the configuration schema.
|
|
162
136
|
*
|
|
137
|
+
* If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
|
|
138
|
+
*
|
|
139
|
+
* @param {PartialArgs} [args] - Partial args (progammatic usage only)
|
|
140
|
+
* @returns {Promise<ServerInitResult | ExtCommandInitResult>}
|
|
163
141
|
* @example
|
|
164
142
|
* import {init, getSchema} from 'appium';
|
|
165
143
|
* const options = {}; // config object
|
|
166
144
|
* await init(options);
|
|
167
145
|
* const schema = getSchema(); // entire config schema including plugins and drivers
|
|
168
|
-
* @param {ParsedArgs} [args] - Parsed args
|
|
169
|
-
* @returns {Promise<{parser: import('./cli/parser').ArgParser} & Partial<{appiumDriver: AppiumDriver, parsedArgs: ParsedArgs}>>}
|
|
170
146
|
*/
|
|
171
147
|
async function init (args) {
|
|
172
|
-
const
|
|
148
|
+
const appiumHome = args?.appiumHome ?? await resolveAppiumHome();
|
|
149
|
+
|
|
150
|
+
const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);
|
|
151
|
+
|
|
152
|
+
const parser = getParser();
|
|
173
153
|
let throwInsteadOfExit = false;
|
|
174
154
|
/** @type {ParsedArgs} */
|
|
155
|
+
let preConfigParsedArgs;
|
|
156
|
+
/** @type {ParsedArgs} */
|
|
175
157
|
let parsedArgs;
|
|
158
|
+
/**
|
|
159
|
+
* This is a definition (instead of declaration) because TS can't figure out
|
|
160
|
+
* the value will be defined when it's used.
|
|
161
|
+
* @type {ReturnType<getDefaultsForSchema>}
|
|
162
|
+
*/
|
|
163
|
+
let defaults = {};
|
|
176
164
|
if (args) {
|
|
177
165
|
// if we have a containing package instead of running as a CLI process,
|
|
178
166
|
// that package might not appreciate us calling 'process.exit' willy-
|
|
@@ -182,13 +170,13 @@ async function init (args) {
|
|
|
182
170
|
// but remove it since it's not a real server arg per se
|
|
183
171
|
delete args.throwInsteadOfExit;
|
|
184
172
|
}
|
|
185
|
-
|
|
173
|
+
preConfigParsedArgs = /** @type {ParsedArgs} */({...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND});
|
|
186
174
|
} else {
|
|
187
175
|
// otherwise parse from CLI
|
|
188
|
-
|
|
176
|
+
preConfigParsedArgs = parser.parseArgs();
|
|
189
177
|
}
|
|
190
178
|
|
|
191
|
-
const configResult = await readConfigFile(
|
|
179
|
+
const configResult = await readConfigFile(preConfigParsedArgs.configFile);
|
|
192
180
|
|
|
193
181
|
if (!_.isEmpty(configResult.errors)) {
|
|
194
182
|
throw new Error(`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`);
|
|
@@ -199,30 +187,35 @@ async function init (args) {
|
|
|
199
187
|
// 1. command line args
|
|
200
188
|
// 2. config file
|
|
201
189
|
// 3. defaults from config file.
|
|
202
|
-
if (
|
|
190
|
+
if (preConfigParsedArgs.subcommand === SERVER_SUBCOMMAND) {
|
|
191
|
+
defaults = getDefaultsForSchema(false);
|
|
192
|
+
|
|
203
193
|
parsedArgs = _.defaultsDeep(
|
|
204
|
-
|
|
194
|
+
preConfigParsedArgs,
|
|
205
195
|
configResult.config?.server,
|
|
206
|
-
|
|
196
|
+
defaults
|
|
207
197
|
);
|
|
208
|
-
}
|
|
209
198
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
199
|
+
if (preConfigParsedArgs.showConfig) {
|
|
200
|
+
showConfig(getNonDefaultServerArgs(preConfigParsedArgs), configResult, defaults, parsedArgs);
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
} else {
|
|
205
|
+
parsedArgs = preConfigParsedArgs;
|
|
206
|
+
}
|
|
214
207
|
|
|
215
208
|
await logsinkInit(parsedArgs);
|
|
216
209
|
|
|
217
210
|
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
218
211
|
// but instead pass control to the driver CLI
|
|
219
212
|
if (parsedArgs.subcommand === DRIVER_TYPE) {
|
|
220
|
-
await runExtensionCommand(parsedArgs,
|
|
221
|
-
return {
|
|
213
|
+
await runExtensionCommand(parsedArgs, driverConfig);
|
|
214
|
+
return {};
|
|
222
215
|
}
|
|
223
216
|
if (parsedArgs.subcommand === PLUGIN_TYPE) {
|
|
224
|
-
await runExtensionCommand(parsedArgs,
|
|
225
|
-
return {
|
|
217
|
+
await runExtensionCommand(parsedArgs, pluginConfig);
|
|
218
|
+
return {};
|
|
226
219
|
}
|
|
227
220
|
|
|
228
221
|
if (parsedArgs.logFilters) {
|
|
@@ -243,31 +236,32 @@ async function init (args) {
|
|
|
243
236
|
appiumDriver.driverConfig = driverConfig;
|
|
244
237
|
await preflightChecks(parsedArgs, throwInsteadOfExit);
|
|
245
238
|
|
|
246
|
-
return {
|
|
239
|
+
return /** @type {ServerInitResult} */({appiumDriver, parsedArgs, driverConfig, pluginConfig});
|
|
247
240
|
}
|
|
248
241
|
|
|
249
242
|
/**
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* @
|
|
243
|
+
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
244
|
+
* server instance if so; otherwise resolves w/ `undefined`.
|
|
245
|
+
* @param {PartialArgs} [args] - Arguments from CLI or otherwise
|
|
246
|
+
* @returns {Promise<import('http').Server|undefined>}
|
|
253
247
|
*/
|
|
254
248
|
async function main (args) {
|
|
255
|
-
const {
|
|
249
|
+
const {appiumDriver, parsedArgs, pluginConfig, driverConfig} = /** @type {ServerInitResult} */(await init(args));
|
|
256
250
|
|
|
257
|
-
if (!appiumDriver || !parsedArgs) {
|
|
251
|
+
if (!appiumDriver || !parsedArgs || !pluginConfig || !driverConfig) {
|
|
258
252
|
// if this branch is taken, we've run a different subcommand, so there's nothing
|
|
259
253
|
// left to do here.
|
|
260
254
|
return;
|
|
261
255
|
}
|
|
262
256
|
|
|
263
|
-
const pluginClasses = getActivePlugins(
|
|
257
|
+
const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
|
|
264
258
|
// set the active plugins on the umbrella driver so it can use them for commands
|
|
265
259
|
appiumDriver.pluginClasses = pluginClasses;
|
|
266
260
|
|
|
267
|
-
await logStartupInfo(
|
|
261
|
+
await logStartupInfo(parsedArgs);
|
|
268
262
|
let routeConfiguringFunction = makeRouter(appiumDriver);
|
|
269
263
|
|
|
270
|
-
const driverClasses = getActiveDrivers(
|
|
264
|
+
const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
|
|
271
265
|
const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
|
|
272
266
|
const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
|
|
273
267
|
|
|
@@ -298,7 +292,6 @@ async function main (args) {
|
|
|
298
292
|
'to visit sites which could maliciously try to start Appium ' +
|
|
299
293
|
'sessions on your machine');
|
|
300
294
|
}
|
|
301
|
-
// @ts-ignore
|
|
302
295
|
appiumDriver.server = server;
|
|
303
296
|
try {
|
|
304
297
|
// configure as node on grid, if necessary
|
|
@@ -343,11 +336,32 @@ if (require.main === module) {
|
|
|
343
336
|
}
|
|
344
337
|
|
|
345
338
|
// everything below here is intended to be a public API.
|
|
346
|
-
export { main, init };
|
|
347
|
-
export { APPIUM_HOME } from './extension-config';
|
|
348
|
-
export { getSchema, validate, finalizeSchema } from './schema/schema';
|
|
349
339
|
export { readConfigFile } from './config-file';
|
|
340
|
+
export { finalizeSchema, getSchema, validate } from './schema/schema';
|
|
341
|
+
export { main, init, resolveAppiumHome };
|
|
350
342
|
|
|
351
343
|
/**
|
|
352
344
|
* @typedef {import('../types/types').ParsedArgs} ParsedArgs
|
|
353
345
|
*/
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @typedef {import('../types/types').PartialArgs} PartialArgs
|
|
349
|
+
* @typedef {import('./extension/manifest').DriverType} DriverType
|
|
350
|
+
* @typedef {import('./extension/manifest').PluginType} PluginType
|
|
351
|
+
* @typedef {import('./extension/manifest').DriverClass} DriverClass
|
|
352
|
+
* @typedef {import('./extension/manifest').PluginClass} PluginClass
|
|
353
|
+
*/
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @typedef { {} } ExtCommandInitResult
|
|
357
|
+
*/
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* @typedef ServerInitData
|
|
361
|
+
* @property {AppiumDriver} appiumDriver - The Appium driver
|
|
362
|
+
* @property {ParsedArgs} parsedArgs - The parsed arguments
|
|
363
|
+
*/
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @typedef {ServerInitData & import('./extension').ExtensionConfigs} ServerInitResult
|
|
367
|
+
*/
|
package/lib/schema/arg-spec.js
CHANGED
|
@@ -73,6 +73,11 @@ export class ArgSpec {
|
|
|
73
73
|
*/
|
|
74
74
|
dest;
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The same as {@link ArgSpec.dest} but without the leading `<extType>.<extName>.` prefix.
|
|
78
|
+
*/
|
|
79
|
+
rawDest;
|
|
80
|
+
|
|
76
81
|
/**
|
|
77
82
|
* Whatever the default value of this argument is, as specified by the
|
|
78
83
|
* `default` property of the schema.
|
|
@@ -100,10 +105,10 @@ export class ArgSpec {
|
|
|
100
105
|
|
|
101
106
|
// if no explicit `dest` provided, just camelCase the name to avoid needing
|
|
102
107
|
// to use bracket syntax when accessing props on the parsed args object.
|
|
103
|
-
const
|
|
108
|
+
const rawDest = _.camelCase(dest ?? name);
|
|
104
109
|
|
|
105
110
|
const destKeypath =
|
|
106
|
-
extType && extName ? [extType, extName,
|
|
111
|
+
extType && extName ? [extType, extName, rawDest].join('.') : rawDest;
|
|
107
112
|
|
|
108
113
|
this.defaultValue = defaultValue;
|
|
109
114
|
this.name = name;
|
|
@@ -112,6 +117,7 @@ export class ArgSpec {
|
|
|
112
117
|
this.arg = arg;
|
|
113
118
|
this.dest = destKeypath;
|
|
114
119
|
this.ref = ref;
|
|
120
|
+
this.rawDest = rawDest;
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
/**
|
|
@@ -170,7 +176,7 @@ export class ArgSpec {
|
|
|
170
176
|
/**
|
|
171
177
|
* When given the root ID of a schema for an extension (`<extType>-<normalizedExtName>.json`) Returns an object containing the extension type and the _normalized_ extension name.
|
|
172
178
|
* @param {string} schemaId - Root schema ID
|
|
173
|
-
* @returns {{extType: ExtensionType|undefined, normalizedExtName: string|undefined}}
|
|
179
|
+
* @returns { {extType: ExtensionType|undefined, normalizedExtName: string|undefined} }
|
|
174
180
|
*/
|
|
175
181
|
static extensionInfoFromRootSchemaId (schemaId) {
|
|
176
182
|
const matches = schemaId.match(SCHEMA_ID_REGEXP);
|
|
@@ -210,7 +216,7 @@ export class ArgSpec {
|
|
|
210
216
|
/**
|
|
211
217
|
* Options for {@link ArgSpec.create}
|
|
212
218
|
* @template D
|
|
213
|
-
* @typedef
|
|
219
|
+
* @typedef ArgSpecOptions
|
|
214
220
|
* @property {string} [extName]
|
|
215
221
|
* @property {ExtensionType} [extType]
|
|
216
222
|
* @property {string} [dest]
|
|
@@ -218,5 +224,5 @@ export class ArgSpec {
|
|
|
218
224
|
*/
|
|
219
225
|
|
|
220
226
|
/**
|
|
221
|
-
* @typedef {import('../
|
|
227
|
+
* @typedef {import('../manifest').ExtensionType} ExtensionType
|
|
222
228
|
*/
|
package/lib/schema/cli-args.js
CHANGED
|
@@ -98,11 +98,9 @@ function makeDescription (schema) {
|
|
|
98
98
|
* as understood by `argparse`.
|
|
99
99
|
* @param {AppiumJSONSchema} subSchema - JSON schema for the option
|
|
100
100
|
* @param {ArgSpec} argSpec - Argument spec tuple
|
|
101
|
-
* @param {SubSchemaToArgDefOptions} [opts] - Options
|
|
102
101
|
* @returns {[string[], import('argparse').ArgumentOptions]} Tuple of flag and options
|
|
103
102
|
*/
|
|
104
|
-
function subSchemaToArgDef (subSchema, argSpec
|
|
105
|
-
const {overrides = {}} = opts;
|
|
103
|
+
function subSchemaToArgDef (subSchema, argSpec) {
|
|
106
104
|
let {
|
|
107
105
|
type,
|
|
108
106
|
appiumCliAliases,
|
|
@@ -110,7 +108,7 @@ function subSchemaToArgDef (subSchema, argSpec, opts = {}) {
|
|
|
110
108
|
enum: enumValues,
|
|
111
109
|
} = subSchema;
|
|
112
110
|
|
|
113
|
-
const {name, arg
|
|
111
|
+
const {name, arg} = argSpec;
|
|
114
112
|
|
|
115
113
|
const aliases = [
|
|
116
114
|
aliasToFlag(argSpec),
|
|
@@ -141,8 +139,10 @@ function subSchemaToArgDef (subSchema, argSpec, opts = {}) {
|
|
|
141
139
|
// handle special cases for various types
|
|
142
140
|
switch (type) {
|
|
143
141
|
// booleans do not have a type per `ArgumentOptions`, just an "action"
|
|
142
|
+
// NOTE: due to limitations of `argparse`, we cannot provide fancy help text, and must rely on its internal error messaging.
|
|
144
143
|
case TYPENAMES.BOOLEAN: {
|
|
145
|
-
argOpts.action = '
|
|
144
|
+
argOpts.action = 'store_const';
|
|
145
|
+
argOpts.const = true;
|
|
146
146
|
break;
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -227,16 +227,6 @@ function subSchemaToArgDef (subSchema, argSpec, opts = {}) {
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
// overrides override anything we computed here. usually this involves "custom types",
|
|
231
|
-
// which are really just transform functions.
|
|
232
|
-
argOpts = _.merge(
|
|
233
|
-
argOpts,
|
|
234
|
-
/** should the override keys correspond to the prop name or the prop dest?
|
|
235
|
-
* the prop dest is computed by {@link aliasToDest}.
|
|
236
|
-
*/
|
|
237
|
-
overrides[dest] ?? {},
|
|
238
|
-
);
|
|
239
|
-
|
|
240
230
|
return [aliases, argOpts];
|
|
241
231
|
}
|
|
242
232
|
|
|
@@ -244,32 +234,19 @@ function subSchemaToArgDef (subSchema, argSpec, opts = {}) {
|
|
|
244
234
|
* Converts the finalized, flattened schema representation into
|
|
245
235
|
* ArgumentDefinitions for handoff to `argparse`.
|
|
246
236
|
*
|
|
247
|
-
* @param {ToParserArgsOptions} opts - Options
|
|
248
237
|
* @throws If schema has not been added to ajv (via `finalizeSchema()`)
|
|
249
238
|
* @returns {import('../cli/args').ArgumentDefinitions} A map of arryas of
|
|
250
239
|
* aliases to `argparse` arguments; empty if no schema found
|
|
251
240
|
*/
|
|
252
|
-
export function toParserArgs (
|
|
241
|
+
export function toParserArgs () {
|
|
253
242
|
const flattened = flattenSchema().filter(({schema}) => !schema.appiumCliIgnored);
|
|
254
243
|
return new Map(
|
|
255
244
|
_.map(flattened, ({schema, argSpec}) =>
|
|
256
|
-
subSchemaToArgDef(schema, argSpec
|
|
245
|
+
subSchemaToArgDef(schema, argSpec),
|
|
257
246
|
),
|
|
258
247
|
);
|
|
259
248
|
}
|
|
260
249
|
|
|
261
|
-
/**
|
|
262
|
-
* Options for {@link toParserArgs}
|
|
263
|
-
* @typedef {SubSchemaToArgDefOptions} ToParserArgsOptions
|
|
264
|
-
*/
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Options for {@link subSchemaToArgDef}.
|
|
268
|
-
* @typedef {Object} SubSchemaToArgDefOptions
|
|
269
|
-
* @property {string} [prefix] - The prefix to use for the flag, if any
|
|
270
|
-
* @property {{[key: string]: import('argparse').ArgumentOptions}} [overrides] - An object of key/value pairs to override the default values
|
|
271
|
-
*/
|
|
272
|
-
|
|
273
250
|
/**
|
|
274
251
|
* @template T
|
|
275
252
|
* @typedef {import('ajv/dist/types').FormatValidator<T>} FormatValidator<T>
|
package/lib/schema/keywords.js
CHANGED
|
@@ -120,7 +120,7 @@ export const keywords = {
|
|
|
120
120
|
/**
|
|
121
121
|
* These are the custom keywords that Appium recognizes.
|
|
122
122
|
*
|
|
123
|
-
* @typedef
|
|
123
|
+
* @typedef AppiumJSONSchemaKeywords
|
|
124
124
|
* @property {string} [appiumCliDest]
|
|
125
125
|
* @property {string} [appiumCliDescription]
|
|
126
126
|
* @property {string[]} [appiumCliAliases]
|