appium 2.0.0-beta.24 → 2.0.0-beta.27
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/appium-config.schema.json +278 -0
- package/build/lib/appium.js +45 -66
- package/build/lib/cli/args.js +19 -39
- 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 +9 -19
- 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 +50 -20
- 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 +42 -71
- package/build/lib/schema/appium-config-schema.js +2 -4
- package/build/lib/schema/arg-spec.js +11 -14
- package/build/lib/schema/cli-args.js +2 -4
- 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 +61 -37
- package/build/lib/utils.js +1 -32
- package/lib/appium.js +50 -68
- package/lib/cli/args.js +19 -23
- 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 +6 -14
- package/lib/cli/plugin-command.js +1 -2
- package/lib/config-file.js +12 -15
- package/lib/config.js +55 -24
- 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 +57 -93
- package/lib/schema/arg-spec.js +3 -3
- package/lib/schema/cli-args.js +1 -0
- package/lib/schema/keywords.js +1 -1
- package/lib/schema/schema.js +67 -29
- package/lib/utils.js +2 -32
- package/package.json +29 -21
- package/{postinstall.js → scripts/postinstall.js} +1 -1
- package/types/types.d.ts +70 -31
- 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 -18
- 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 -246
- package/build/test/driver-e2e-specs.js +0 -435
- package/build/test/driver-specs.js +0 -386
- 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 -532
- 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 -319
- 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 -408
- package/build/test/schema/schema-specs.js +0 -407
- package/build/test/utils-specs.js +0 -288
- 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 -13
|
@@ -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,24 +3,26 @@
|
|
|
3
3
|
// transpile:main
|
|
4
4
|
// @ts-check
|
|
5
5
|
|
|
6
|
-
import
|
|
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
|
|
7
8
|
// @ts-ignore
|
|
8
9
|
import { routeConfiguringFunction as makeRouter, server as baseServer } from '@appium/base-driver';
|
|
9
|
-
import { logger as logFactory, util } from '@appium/support';
|
|
10
|
+
import { logger as logFactory, util, env } from '@appium/support';
|
|
10
11
|
import { asyncify } from 'asyncbox';
|
|
11
12
|
import _ from 'lodash';
|
|
12
13
|
import { AppiumDriver } from './appium';
|
|
13
|
-
import { driverConfig, pluginConfig, USE_ALL_PLUGINS } from './cli/args';
|
|
14
14
|
import { runExtensionCommand } from './cli/extension';
|
|
15
|
-
import {
|
|
16
|
-
import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showBuildInfo, validateTmpDir, warnNodeDeprecations
|
|
15
|
+
import { getParser } from './cli/parser';
|
|
16
|
+
import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showConfig, showBuildInfo, validateTmpDir, warnNodeDeprecations } from './config';
|
|
17
17
|
import { readConfigFile } from './config-file';
|
|
18
|
-
import {
|
|
18
|
+
import { loadExtensions, getActivePlugins, getActiveDrivers } from './extension';
|
|
19
|
+
import { DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND } from './constants';
|
|
19
20
|
import registerNode from './grid-register';
|
|
20
|
-
import {
|
|
21
|
-
import { getDefaultsForSchema } from './schema/schema';
|
|
21
|
+
import { getDefaultsForSchema, validate } from './schema/schema';
|
|
22
22
|
import { inspect } from './utils';
|
|
23
23
|
|
|
24
|
+
const {resolveAppiumHome} = env;
|
|
25
|
+
|
|
24
26
|
/**
|
|
25
27
|
*
|
|
26
28
|
* @param {ParsedArgs} args
|
|
@@ -38,6 +40,8 @@ async function preflightChecks (args, throwInsteadOfExit = false) {
|
|
|
38
40
|
}
|
|
39
41
|
warnNodeDeprecations();
|
|
40
42
|
|
|
43
|
+
validate(args);
|
|
44
|
+
|
|
41
45
|
if (args.tmpDir) {
|
|
42
46
|
await validateTmpDir(args.tmpDir);
|
|
43
47
|
}
|
|
@@ -102,63 +106,11 @@ function logServerPort (address, port) {
|
|
|
102
106
|
logger.info(logMessage);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
/**
|
|
106
|
-
* Find any plugin name which has been installed, and which has been requested for activation by
|
|
107
|
-
* using the --use-plugins flag, and turn each one into its class, so we can send them as objects
|
|
108
|
-
* to the server init. We also want to send/assign them to the umbrella driver so it can use them
|
|
109
|
-
* to wrap command execution
|
|
110
|
-
*
|
|
111
|
-
* @param {Object} args - argparser parsed dict
|
|
112
|
-
* @param {import('./plugin-config').default} pluginConfig - a plugin extension config
|
|
113
|
-
* @returns {PluginExtensionClass[]}
|
|
114
|
-
*/
|
|
115
|
-
function getActivePlugins (args, pluginConfig) {
|
|
116
|
-
return _.compact(Object.keys(pluginConfig.installedExtensions).filter((pluginName) =>
|
|
117
|
-
_.includes(args.usePlugins, pluginName) ||
|
|
118
|
-
(args.usePlugins.length === 1 && args.usePlugins[0] === USE_ALL_PLUGINS)
|
|
119
|
-
).map((pluginName) => {
|
|
120
|
-
try {
|
|
121
|
-
logger.info(`Attempting to load plugin ${pluginName}...`);
|
|
122
|
-
const PluginClass = /** @type {PluginExtensionClass} */(pluginConfig.require(pluginName));
|
|
123
|
-
|
|
124
|
-
PluginClass.pluginName = pluginName; // store the plugin name on the class so it can be used later
|
|
125
|
-
return PluginClass;
|
|
126
|
-
} catch (err) {
|
|
127
|
-
logger.error(`Could not load plugin '${pluginName}', so it will not be available. Error ` +
|
|
128
|
-
`in loading the plugin was: ${err.message}`);
|
|
129
|
-
logger.debug(err.stack);
|
|
130
|
-
}
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Find any driver name which has been installed, and turn each one into its class, so we can send
|
|
136
|
-
* them as objects to the server init in case they need to add methods/routes or update the server.
|
|
137
|
-
* If the --drivers flag was given, this method only loads the given drivers.
|
|
138
|
-
*
|
|
139
|
-
* @param {Object} args - argparser parsed dict
|
|
140
|
-
* @param {import('./driver-config').default} driverConfig - a driver extension config
|
|
141
|
-
*/
|
|
142
|
-
function getActiveDrivers (args, driverConfig) {
|
|
143
|
-
return _.compact(Object.keys(driverConfig.installedExtensions).filter((driverName) =>
|
|
144
|
-
_.includes(args.useDrivers, driverName) || args.useDrivers.length === 0
|
|
145
|
-
).map((driverName) => {
|
|
146
|
-
try {
|
|
147
|
-
logger.info(`Attempting to load driver ${driverName}...`);
|
|
148
|
-
return driverConfig.require(driverName);
|
|
149
|
-
} catch (err) {
|
|
150
|
-
logger.error(`Could not load driver '${driverName}', so it will not be available. Error ` +
|
|
151
|
-
`in loading the driver was: ${err.message}`);
|
|
152
|
-
logger.debug(err.stack);
|
|
153
|
-
}
|
|
154
|
-
}));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
109
|
/**
|
|
158
110
|
* Gets a list of `updateServer` functions from all extensions
|
|
159
|
-
* @param {
|
|
160
|
-
* @param {
|
|
161
|
-
* @returns {
|
|
111
|
+
* @param {DriverClass[]} driverClasses
|
|
112
|
+
* @param {PluginClass[]} pluginClasses
|
|
113
|
+
* @returns {import('./extension/manifest').UpdateServerFn[]}
|
|
162
114
|
*/
|
|
163
115
|
function getServerUpdaters (driverClasses, pluginClasses) {
|
|
164
116
|
return _.compact(_.map([...driverClasses, ...pluginClasses], 'updateServer'));
|
|
@@ -166,8 +118,8 @@ function getServerUpdaters (driverClasses, pluginClasses) {
|
|
|
166
118
|
|
|
167
119
|
/**
|
|
168
120
|
* Makes a big `MethodMap` from all the little `MethodMap`s in the extensions
|
|
169
|
-
* @param {
|
|
170
|
-
* @param {
|
|
121
|
+
* @param {DriverClass[]} driverClasses
|
|
122
|
+
* @param {PluginClass[]} pluginClasses
|
|
171
123
|
* @returns {import('@appium/base-driver').MethodMap}
|
|
172
124
|
*/
|
|
173
125
|
function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
@@ -182,11 +134,10 @@ function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
|
182
134
|
*
|
|
183
135
|
* Use this to get at the configuration schema.
|
|
184
136
|
*
|
|
185
|
-
* If `args` contains a non-empty `subcommand` which is not `server`, this function
|
|
186
|
-
* will resolve with an empty object.
|
|
137
|
+
* If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
|
|
187
138
|
*
|
|
188
|
-
* @param {
|
|
189
|
-
* @returns {Promise<
|
|
139
|
+
* @param {PartialArgs} [args] - Partial args (progammatic usage only)
|
|
140
|
+
* @returns {Promise<ServerInitResult | ExtCommandInitResult>}
|
|
190
141
|
* @example
|
|
191
142
|
* import {init, getSchema} from 'appium';
|
|
192
143
|
* const options = {}; // config object
|
|
@@ -194,11 +145,15 @@ function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
|
194
145
|
* const schema = getSchema(); // entire config schema including plugins and drivers
|
|
195
146
|
*/
|
|
196
147
|
async function init (args) {
|
|
197
|
-
const
|
|
148
|
+
const appiumHome = args?.appiumHome ?? await resolveAppiumHome();
|
|
149
|
+
|
|
150
|
+
const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);
|
|
151
|
+
|
|
152
|
+
const parser = getParser();
|
|
198
153
|
let throwInsteadOfExit = false;
|
|
199
154
|
/** @type {ParsedArgs} */
|
|
200
155
|
let preConfigParsedArgs;
|
|
201
|
-
/** @type {
|
|
156
|
+
/** @type {ParsedArgs} */
|
|
202
157
|
let parsedArgs;
|
|
203
158
|
/**
|
|
204
159
|
* This is a definition (instead of declaration) because TS can't figure out
|
|
@@ -215,7 +170,7 @@ async function init (args) {
|
|
|
215
170
|
// but remove it since it's not a real server arg per se
|
|
216
171
|
delete args.throwInsteadOfExit;
|
|
217
172
|
}
|
|
218
|
-
preConfigParsedArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
|
|
173
|
+
preConfigParsedArgs = /** @type {ParsedArgs} */({...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND});
|
|
219
174
|
} else {
|
|
220
175
|
// otherwise parse from CLI
|
|
221
176
|
preConfigParsedArgs = parser.parseArgs();
|
|
@@ -227,7 +182,6 @@ async function init (args) {
|
|
|
227
182
|
throw new Error(`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`);
|
|
228
183
|
}
|
|
229
184
|
|
|
230
|
-
|
|
231
185
|
// merge config and apply defaults.
|
|
232
186
|
// the order of precendece is:
|
|
233
187
|
// 1. command line args
|
|
@@ -236,16 +190,17 @@ async function init (args) {
|
|
|
236
190
|
if (preConfigParsedArgs.subcommand === SERVER_SUBCOMMAND) {
|
|
237
191
|
defaults = getDefaultsForSchema(false);
|
|
238
192
|
|
|
239
|
-
if (preConfigParsedArgs.showConfig) {
|
|
240
|
-
showConfig(preConfigParsedArgs, configResult, defaults);
|
|
241
|
-
return {};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
193
|
parsedArgs = _.defaultsDeep(
|
|
245
194
|
preConfigParsedArgs,
|
|
246
195
|
configResult.config?.server,
|
|
247
196
|
defaults
|
|
248
197
|
);
|
|
198
|
+
|
|
199
|
+
if (preConfigParsedArgs.showConfig) {
|
|
200
|
+
showConfig(getNonDefaultServerArgs(preConfigParsedArgs), configResult, defaults, parsedArgs);
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
|
|
249
204
|
} else {
|
|
250
205
|
parsedArgs = preConfigParsedArgs;
|
|
251
206
|
}
|
|
@@ -255,11 +210,11 @@ async function init (args) {
|
|
|
255
210
|
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
256
211
|
// but instead pass control to the driver CLI
|
|
257
212
|
if (parsedArgs.subcommand === DRIVER_TYPE) {
|
|
258
|
-
await runExtensionCommand(parsedArgs,
|
|
213
|
+
await runExtensionCommand(parsedArgs, driverConfig);
|
|
259
214
|
return {};
|
|
260
215
|
}
|
|
261
216
|
if (parsedArgs.subcommand === PLUGIN_TYPE) {
|
|
262
|
-
await runExtensionCommand(parsedArgs,
|
|
217
|
+
await runExtensionCommand(parsedArgs, pluginConfig);
|
|
263
218
|
return {};
|
|
264
219
|
}
|
|
265
220
|
|
|
@@ -281,32 +236,32 @@ async function init (args) {
|
|
|
281
236
|
appiumDriver.driverConfig = driverConfig;
|
|
282
237
|
await preflightChecks(parsedArgs, throwInsteadOfExit);
|
|
283
238
|
|
|
284
|
-
return {appiumDriver, parsedArgs};
|
|
239
|
+
return /** @type {ServerInitResult} */({appiumDriver, parsedArgs, driverConfig, pluginConfig});
|
|
285
240
|
}
|
|
286
241
|
|
|
287
242
|
/**
|
|
288
243
|
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
289
244
|
* server instance if so; otherwise resolves w/ `undefined`.
|
|
290
|
-
* @param {
|
|
291
|
-
* @returns {Promise<import('
|
|
245
|
+
* @param {PartialArgs} [args] - Arguments from CLI or otherwise
|
|
246
|
+
* @returns {Promise<import('http').Server|undefined>}
|
|
292
247
|
*/
|
|
293
248
|
async function main (args) {
|
|
294
|
-
const {appiumDriver, parsedArgs} = await init(args);
|
|
249
|
+
const {appiumDriver, parsedArgs, pluginConfig, driverConfig} = /** @type {ServerInitResult} */(await init(args));
|
|
295
250
|
|
|
296
|
-
if (!appiumDriver || !parsedArgs) {
|
|
251
|
+
if (!appiumDriver || !parsedArgs || !pluginConfig || !driverConfig) {
|
|
297
252
|
// if this branch is taken, we've run a different subcommand, so there's nothing
|
|
298
253
|
// left to do here.
|
|
299
254
|
return;
|
|
300
255
|
}
|
|
301
256
|
|
|
302
|
-
const pluginClasses = getActivePlugins(
|
|
257
|
+
const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
|
|
303
258
|
// set the active plugins on the umbrella driver so it can use them for commands
|
|
304
259
|
appiumDriver.pluginClasses = pluginClasses;
|
|
305
260
|
|
|
306
261
|
await logStartupInfo(parsedArgs);
|
|
307
262
|
let routeConfiguringFunction = makeRouter(appiumDriver);
|
|
308
263
|
|
|
309
|
-
const driverClasses = getActiveDrivers(
|
|
264
|
+
const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
|
|
310
265
|
const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
|
|
311
266
|
const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
|
|
312
267
|
|
|
@@ -381,23 +336,32 @@ if (require.main === module) {
|
|
|
381
336
|
}
|
|
382
337
|
|
|
383
338
|
// everything below here is intended to be a public API.
|
|
384
|
-
export { main, init };
|
|
385
|
-
export { APPIUM_HOME } from './extension-config';
|
|
386
|
-
export { getSchema, validate, finalizeSchema } from './schema/schema';
|
|
387
339
|
export { readConfigFile } from './config-file';
|
|
340
|
+
export { finalizeSchema, getSchema, validate } from './schema/schema';
|
|
341
|
+
export { main, init, resolveAppiumHome };
|
|
388
342
|
|
|
389
343
|
/**
|
|
390
344
|
* @typedef {import('../types/types').ParsedArgs} ParsedArgs
|
|
391
345
|
*/
|
|
392
346
|
|
|
393
347
|
/**
|
|
394
|
-
* @typedef {import('
|
|
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
|
|
395
357
|
*/
|
|
396
358
|
|
|
397
359
|
/**
|
|
398
|
-
* @typedef
|
|
360
|
+
* @typedef ServerInitData
|
|
361
|
+
* @property {AppiumDriver} appiumDriver - The Appium driver
|
|
362
|
+
* @property {ParsedArgs} parsedArgs - The parsed arguments
|
|
399
363
|
*/
|
|
400
364
|
|
|
401
365
|
/**
|
|
402
|
-
* @typedef {import('./
|
|
366
|
+
* @typedef {ServerInitData & import('./extension').ExtensionConfigs} ServerInitResult
|
|
403
367
|
*/
|
package/lib/schema/arg-spec.js
CHANGED
|
@@ -176,7 +176,7 @@ export class ArgSpec {
|
|
|
176
176
|
/**
|
|
177
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.
|
|
178
178
|
* @param {string} schemaId - Root schema ID
|
|
179
|
-
* @returns {{extType: ExtensionType|undefined, normalizedExtName: string|undefined}}
|
|
179
|
+
* @returns { {extType: ExtensionType|undefined, normalizedExtName: string|undefined} }
|
|
180
180
|
*/
|
|
181
181
|
static extensionInfoFromRootSchemaId (schemaId) {
|
|
182
182
|
const matches = schemaId.match(SCHEMA_ID_REGEXP);
|
|
@@ -216,7 +216,7 @@ export class ArgSpec {
|
|
|
216
216
|
/**
|
|
217
217
|
* Options for {@link ArgSpec.create}
|
|
218
218
|
* @template D
|
|
219
|
-
* @typedef
|
|
219
|
+
* @typedef ArgSpecOptions
|
|
220
220
|
* @property {string} [extName]
|
|
221
221
|
* @property {ExtensionType} [extType]
|
|
222
222
|
* @property {string} [dest]
|
|
@@ -224,5 +224,5 @@ export class ArgSpec {
|
|
|
224
224
|
*/
|
|
225
225
|
|
|
226
226
|
/**
|
|
227
|
-
* @typedef {import('../
|
|
227
|
+
* @typedef {import('../manifest').ExtensionType} ExtensionType
|
|
228
228
|
*/
|
package/lib/schema/cli-args.js
CHANGED
|
@@ -139,6 +139,7 @@ function subSchemaToArgDef (subSchema, argSpec) {
|
|
|
139
139
|
// handle special cases for various types
|
|
140
140
|
switch (type) {
|
|
141
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.
|
|
142
143
|
case TYPENAMES.BOOLEAN: {
|
|
143
144
|
argOpts.action = 'store_const';
|
|
144
145
|
argOpts.const = true;
|
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]
|
package/lib/schema/schema.js
CHANGED
|
@@ -4,12 +4,42 @@ import Ajv from 'ajv';
|
|
|
4
4
|
import addFormats from 'ajv-formats';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
import path from 'path';
|
|
7
|
-
import { DRIVER_TYPE, PLUGIN_TYPE } from '../
|
|
8
|
-
import { ReadonlyMap } from '../utils';
|
|
7
|
+
import { DRIVER_TYPE, PLUGIN_TYPE } from '../constants';
|
|
9
8
|
import appiumConfigSchema from './appium-config-schema';
|
|
10
9
|
import { APPIUM_CONFIG_SCHEMA_ID, ArgSpec, SERVER_PROP_NAME } from './arg-spec';
|
|
11
10
|
import { keywords } from './keywords';
|
|
12
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Key/value pairs go in... but they don't come out.
|
|
14
|
+
*
|
|
15
|
+
* @template K,V
|
|
16
|
+
* @extends {Map<K,V>}
|
|
17
|
+
*/
|
|
18
|
+
export class RoachHotelMap extends Map {
|
|
19
|
+
/**
|
|
20
|
+
* @param {K} key
|
|
21
|
+
* @param {V} value
|
|
22
|
+
*/
|
|
23
|
+
set (key, value) {
|
|
24
|
+
if (this.has(key)) {
|
|
25
|
+
throw new Error(`${key} is already set`);
|
|
26
|
+
}
|
|
27
|
+
return super.set(key, value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {K} key
|
|
32
|
+
*/
|
|
33
|
+
// eslint-disable-next-line no-unused-vars
|
|
34
|
+
delete (key) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
clear () {
|
|
39
|
+
throw new Error(`Cannot clear RoachHotelMap`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
13
43
|
/**
|
|
14
44
|
* Extensions that an extension schema file can have.
|
|
15
45
|
*/
|
|
@@ -28,9 +58,9 @@ class AppiumSchema {
|
|
|
28
58
|
*
|
|
29
59
|
* Used to provide easy lookups of argument metadata when converting between different representations of those arguments.
|
|
30
60
|
* @private
|
|
31
|
-
* @type {
|
|
61
|
+
* @type {RoachHotelMap<string,ArgSpec>}
|
|
32
62
|
*/
|
|
33
|
-
_argSpecs = new
|
|
63
|
+
_argSpecs = new RoachHotelMap();
|
|
34
64
|
|
|
35
65
|
/**
|
|
36
66
|
* A map of extension types to extension names to schema objects.
|
|
@@ -83,24 +113,27 @@ class AppiumSchema {
|
|
|
83
113
|
* @returns {AppiumSchema}
|
|
84
114
|
*/
|
|
85
115
|
static create () {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
if (!AppiumSchema._instance) {
|
|
117
|
+
const instance = new AppiumSchema();
|
|
118
|
+
AppiumSchema._instance = instance;
|
|
119
|
+
_.bindAll(instance, [
|
|
120
|
+
'finalize',
|
|
121
|
+
'flatten',
|
|
122
|
+
'getAllArgSpecs',
|
|
123
|
+
'getArgSpec',
|
|
124
|
+
'getDefaults',
|
|
125
|
+
'getDefaultsForExtension',
|
|
126
|
+
'getSchema',
|
|
127
|
+
'hasArgSpec',
|
|
128
|
+
'isFinalized',
|
|
129
|
+
'registerSchema',
|
|
130
|
+
'hasRegisteredSchema',
|
|
131
|
+
'reset',
|
|
132
|
+
'validate',
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return AppiumSchema._instance;
|
|
104
137
|
}
|
|
105
138
|
|
|
106
139
|
/**
|
|
@@ -124,6 +157,10 @@ class AppiumSchema {
|
|
|
124
157
|
return Boolean(this._finalizedSchemas);
|
|
125
158
|
}
|
|
126
159
|
|
|
160
|
+
getAllArgSpecs () {
|
|
161
|
+
return this._argSpecs;
|
|
162
|
+
}
|
|
163
|
+
|
|
127
164
|
/**
|
|
128
165
|
* Call this when no more schemas will be registered.
|
|
129
166
|
*
|
|
@@ -145,7 +182,7 @@ class AppiumSchema {
|
|
|
145
182
|
*/
|
|
146
183
|
finalize () {
|
|
147
184
|
if (this.isFinalized()) {
|
|
148
|
-
return /** @type {
|
|
185
|
+
return /** @type {NonNullable<typeof this._finalizedSchemas>} */ (
|
|
149
186
|
this._finalizedSchemas
|
|
150
187
|
);
|
|
151
188
|
}
|
|
@@ -254,7 +291,7 @@ class AppiumSchema {
|
|
|
254
291
|
for (const schemaId of Object.keys(this._finalizedSchemas ?? {})) {
|
|
255
292
|
this._ajv.removeSchema(schemaId);
|
|
256
293
|
}
|
|
257
|
-
this._argSpecs = new
|
|
294
|
+
this._argSpecs = new RoachHotelMap();
|
|
258
295
|
this._registeredSchemas = {
|
|
259
296
|
[DRIVER_TYPE]: new Map(),
|
|
260
297
|
[PLUGIN_TYPE]: new Map(),
|
|
@@ -271,7 +308,7 @@ class AppiumSchema {
|
|
|
271
308
|
* This is "fail-fast" in that the schema will immediately be validated against JSON schema draft-07 _or_ whatever the value of the schema's `$schema` prop is.
|
|
272
309
|
*
|
|
273
310
|
* Does _not_ add the schema to the `ajv` instance (this is done by {@link AppiumSchema.finalize}).
|
|
274
|
-
* @param {
|
|
311
|
+
* @param {ExtensionType} extType - Extension type
|
|
275
312
|
* @param {string} extName - Unique extension name for `type`
|
|
276
313
|
* @param {SchemaObject} schema - Schema object
|
|
277
314
|
* @throws {SchemaNameConflictError} If the schema is an invalid
|
|
@@ -403,7 +440,7 @@ class AppiumSchema {
|
|
|
403
440
|
flatten () {
|
|
404
441
|
const schema = this.getSchema();
|
|
405
442
|
|
|
406
|
-
/** @type {{properties: SchemaObject, prefix: string[]}[]} */
|
|
443
|
+
/** @type { {properties: SchemaObject, prefix: string[]}[] } */
|
|
407
444
|
const stack = [{properties: schema.properties, prefix: []}];
|
|
408
445
|
/** @type {FlattenedSchema} */
|
|
409
446
|
const flattened = [];
|
|
@@ -641,6 +678,7 @@ const appiumSchema = AppiumSchema.create();
|
|
|
641
678
|
|
|
642
679
|
export const {
|
|
643
680
|
registerSchema,
|
|
681
|
+
getAllArgSpecs,
|
|
644
682
|
getArgSpec,
|
|
645
683
|
hasArgSpec,
|
|
646
684
|
isFinalized,
|
|
@@ -660,12 +698,12 @@ export const {isAllowedSchemaFileExtension} = AppiumSchema;
|
|
|
660
698
|
*/
|
|
661
699
|
|
|
662
700
|
/**
|
|
663
|
-
* @typedef {import('../
|
|
701
|
+
* @typedef {import('../extension/manifest').ExtensionType} ExtensionType
|
|
664
702
|
*/
|
|
665
703
|
|
|
666
704
|
/**
|
|
667
705
|
* An object having property `additionalProperties: false`
|
|
668
|
-
* @typedef
|
|
706
|
+
* @typedef StrictProp
|
|
669
707
|
* @property {false} additionalProperties
|
|
670
708
|
*/
|
|
671
709
|
|
|
@@ -678,7 +716,7 @@ export const {isAllowedSchemaFileExtension} = AppiumSchema;
|
|
|
678
716
|
* A list of schemas associated with properties and their corresponding {@link ArgSpec} objects.
|
|
679
717
|
*
|
|
680
718
|
* Intermediate data structure used when converting the entire schema down to CLI arguments.
|
|
681
|
-
* @typedef {{schema: SchemaObject, argSpec: ArgSpec}[]} FlattenedSchema
|
|
719
|
+
* @typedef { {schema: SchemaObject, argSpec: ArgSpec}[] } FlattenedSchema
|
|
682
720
|
*/
|
|
683
721
|
|
|
684
722
|
/**
|
package/lib/utils.js
CHANGED
|
@@ -4,7 +4,6 @@ import _ from 'lodash';
|
|
|
4
4
|
import logger from './logger';
|
|
5
5
|
// @ts-ignore
|
|
6
6
|
import { processCapabilities, PROTOCOLS } from '@appium/base-driver';
|
|
7
|
-
import { fs } from '@appium/support';
|
|
8
7
|
import { inspect as dump } from 'util';
|
|
9
8
|
|
|
10
9
|
const W3C_APPIUM_PREFIX = 'appium';
|
|
@@ -215,36 +214,7 @@ function pullSettings (caps) {
|
|
|
215
214
|
return result;
|
|
216
215
|
}
|
|
217
216
|
|
|
218
|
-
const rootDir = fs.findRoot(__dirname);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* A Map where you can set properties, but only once. And you can't remove anything. So there.
|
|
223
|
-
* @template K,V
|
|
224
|
-
* @extends {Map<K,V>}
|
|
225
|
-
*/
|
|
226
|
-
class ReadonlyMap extends Map {
|
|
227
|
-
/**
|
|
228
|
-
* @param {K} key
|
|
229
|
-
* @param {V} value
|
|
230
|
-
*/
|
|
231
|
-
set (key, value) {
|
|
232
|
-
if (this.has(key)) {
|
|
233
|
-
throw new Error(`${key} is already set`);
|
|
234
|
-
}
|
|
235
|
-
return super.set(key, value);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
delete () {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
clear () {
|
|
243
|
-
throw new Error(`Cannot clear ReadonlyMap`);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
217
|
export {
|
|
248
|
-
inspect, parseCapsForInnerDriver, insertAppiumPrefixes,
|
|
249
|
-
getPackageVersion, pullSettings, removeAppiumPrefixes
|
|
218
|
+
inspect, parseCapsForInnerDriver, insertAppiumPrefixes,
|
|
219
|
+
getPackageVersion, pullSettings, removeAppiumPrefixes
|
|
250
220
|
};
|