appium 2.0.0-beta.25 → 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/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 +2 -4
- package/build/lib/config.js +7 -6
- 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 +40 -68
- 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 +55 -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 +3 -3
- package/lib/config.js +5 -4
- 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 +51 -88
- package/lib/schema/arg-spec.js +2 -2
- package/lib/schema/cli-args.js +1 -0
- package/lib/schema/keywords.js +1 -1
- package/lib/schema/schema.js +60 -28
- 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 -191
- package/build/test/config-file-specs.js +0 -281
- package/build/test/config-specs.js +0 -258
- 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
|
|
@@ -256,11 +210,11 @@ async function init (args) {
|
|
|
256
210
|
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
257
211
|
// but instead pass control to the driver CLI
|
|
258
212
|
if (parsedArgs.subcommand === DRIVER_TYPE) {
|
|
259
|
-
await runExtensionCommand(parsedArgs,
|
|
213
|
+
await runExtensionCommand(parsedArgs, driverConfig);
|
|
260
214
|
return {};
|
|
261
215
|
}
|
|
262
216
|
if (parsedArgs.subcommand === PLUGIN_TYPE) {
|
|
263
|
-
await runExtensionCommand(parsedArgs,
|
|
217
|
+
await runExtensionCommand(parsedArgs, pluginConfig);
|
|
264
218
|
return {};
|
|
265
219
|
}
|
|
266
220
|
|
|
@@ -282,32 +236,32 @@ async function init (args) {
|
|
|
282
236
|
appiumDriver.driverConfig = driverConfig;
|
|
283
237
|
await preflightChecks(parsedArgs, throwInsteadOfExit);
|
|
284
238
|
|
|
285
|
-
return {appiumDriver, parsedArgs};
|
|
239
|
+
return /** @type {ServerInitResult} */({appiumDriver, parsedArgs, driverConfig, pluginConfig});
|
|
286
240
|
}
|
|
287
241
|
|
|
288
242
|
/**
|
|
289
243
|
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
290
244
|
* server instance if so; otherwise resolves w/ `undefined`.
|
|
291
|
-
* @param {
|
|
292
|
-
* @returns {Promise<import('
|
|
245
|
+
* @param {PartialArgs} [args] - Arguments from CLI or otherwise
|
|
246
|
+
* @returns {Promise<import('http').Server|undefined>}
|
|
293
247
|
*/
|
|
294
248
|
async function main (args) {
|
|
295
|
-
const {appiumDriver, parsedArgs} = await init(args);
|
|
249
|
+
const {appiumDriver, parsedArgs, pluginConfig, driverConfig} = /** @type {ServerInitResult} */(await init(args));
|
|
296
250
|
|
|
297
|
-
if (!appiumDriver || !parsedArgs) {
|
|
251
|
+
if (!appiumDriver || !parsedArgs || !pluginConfig || !driverConfig) {
|
|
298
252
|
// if this branch is taken, we've run a different subcommand, so there's nothing
|
|
299
253
|
// left to do here.
|
|
300
254
|
return;
|
|
301
255
|
}
|
|
302
256
|
|
|
303
|
-
const pluginClasses = getActivePlugins(
|
|
257
|
+
const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
|
|
304
258
|
// set the active plugins on the umbrella driver so it can use them for commands
|
|
305
259
|
appiumDriver.pluginClasses = pluginClasses;
|
|
306
260
|
|
|
307
261
|
await logStartupInfo(parsedArgs);
|
|
308
262
|
let routeConfiguringFunction = makeRouter(appiumDriver);
|
|
309
263
|
|
|
310
|
-
const driverClasses = getActiveDrivers(
|
|
264
|
+
const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
|
|
311
265
|
const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
|
|
312
266
|
const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
|
|
313
267
|
|
|
@@ -382,23 +336,32 @@ if (require.main === module) {
|
|
|
382
336
|
}
|
|
383
337
|
|
|
384
338
|
// everything below here is intended to be a public API.
|
|
385
|
-
export { main, init };
|
|
386
|
-
export { APPIUM_HOME } from './extension-config';
|
|
387
|
-
export { getSchema, validate, finalizeSchema } from './schema/schema';
|
|
388
339
|
export { readConfigFile } from './config-file';
|
|
340
|
+
export { finalizeSchema, getSchema, validate } from './schema/schema';
|
|
341
|
+
export { main, init, resolveAppiumHome };
|
|
389
342
|
|
|
390
343
|
/**
|
|
391
344
|
* @typedef {import('../types/types').ParsedArgs} ParsedArgs
|
|
392
345
|
*/
|
|
393
346
|
|
|
394
347
|
/**
|
|
395
|
-
* @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
|
|
396
357
|
*/
|
|
397
358
|
|
|
398
359
|
/**
|
|
399
|
-
* @typedef
|
|
360
|
+
* @typedef ServerInitData
|
|
361
|
+
* @property {AppiumDriver} appiumDriver - The Appium driver
|
|
362
|
+
* @property {ParsedArgs} parsedArgs - The parsed arguments
|
|
400
363
|
*/
|
|
401
364
|
|
|
402
365
|
/**
|
|
403
|
-
* @typedef {import('./
|
|
366
|
+
* @typedef {ServerInitData & import('./extension').ExtensionConfigs} ServerInitResult
|
|
404
367
|
*/
|
package/lib/schema/arg-spec.js
CHANGED
|
@@ -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,25 +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
|
-
|
|
104
|
-
|
|
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;
|
|
105
137
|
}
|
|
106
138
|
|
|
107
139
|
/**
|
|
@@ -150,7 +182,7 @@ class AppiumSchema {
|
|
|
150
182
|
*/
|
|
151
183
|
finalize () {
|
|
152
184
|
if (this.isFinalized()) {
|
|
153
|
-
return /** @type {
|
|
185
|
+
return /** @type {NonNullable<typeof this._finalizedSchemas>} */ (
|
|
154
186
|
this._finalizedSchemas
|
|
155
187
|
);
|
|
156
188
|
}
|
|
@@ -259,7 +291,7 @@ class AppiumSchema {
|
|
|
259
291
|
for (const schemaId of Object.keys(this._finalizedSchemas ?? {})) {
|
|
260
292
|
this._ajv.removeSchema(schemaId);
|
|
261
293
|
}
|
|
262
|
-
this._argSpecs = new
|
|
294
|
+
this._argSpecs = new RoachHotelMap();
|
|
263
295
|
this._registeredSchemas = {
|
|
264
296
|
[DRIVER_TYPE]: new Map(),
|
|
265
297
|
[PLUGIN_TYPE]: new Map(),
|
|
@@ -276,7 +308,7 @@ class AppiumSchema {
|
|
|
276
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.
|
|
277
309
|
*
|
|
278
310
|
* Does _not_ add the schema to the `ajv` instance (this is done by {@link AppiumSchema.finalize}).
|
|
279
|
-
* @param {
|
|
311
|
+
* @param {ExtensionType} extType - Extension type
|
|
280
312
|
* @param {string} extName - Unique extension name for `type`
|
|
281
313
|
* @param {SchemaObject} schema - Schema object
|
|
282
314
|
* @throws {SchemaNameConflictError} If the schema is an invalid
|
|
@@ -666,12 +698,12 @@ export const {isAllowedSchemaFileExtension} = AppiumSchema;
|
|
|
666
698
|
*/
|
|
667
699
|
|
|
668
700
|
/**
|
|
669
|
-
* @typedef {import('../
|
|
701
|
+
* @typedef {import('../extension/manifest').ExtensionType} ExtensionType
|
|
670
702
|
*/
|
|
671
703
|
|
|
672
704
|
/**
|
|
673
705
|
* An object having property `additionalProperties: false`
|
|
674
|
-
* @typedef
|
|
706
|
+
* @typedef StrictProp
|
|
675
707
|
* @property {false} additionalProperties
|
|
676
708
|
*/
|
|
677
709
|
|
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
|
};
|