appium 2.0.0-beta.17 → 2.0.0-beta.20

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.
Files changed (53) hide show
  1. package/build/lib/appium-config.schema.json +0 -0
  2. package/build/lib/appium.js +84 -69
  3. package/build/lib/cli/argparse-actions.js +1 -1
  4. package/build/lib/cli/args.js +87 -223
  5. package/build/lib/cli/extension-command.js +2 -2
  6. package/build/lib/cli/extension.js +14 -6
  7. package/build/lib/cli/parser.js +142 -106
  8. package/build/lib/cli/utils.js +1 -1
  9. package/build/lib/config-file.js +141 -0
  10. package/build/lib/config.js +42 -64
  11. package/build/lib/driver-config.js +41 -20
  12. package/build/lib/drivers.js +1 -1
  13. package/build/lib/ext-config-io.js +165 -0
  14. package/build/lib/extension-config.js +110 -60
  15. package/build/lib/grid-register.js +19 -21
  16. package/build/lib/logsink.js +1 -1
  17. package/build/lib/main.js +135 -72
  18. package/build/lib/plugin-config.js +17 -8
  19. package/build/lib/schema/appium-config-schema.js +252 -0
  20. package/build/lib/schema/arg-spec.js +120 -0
  21. package/build/lib/schema/cli-args.js +173 -0
  22. package/build/lib/schema/cli-transformers.js +76 -0
  23. package/build/lib/schema/index.js +36 -0
  24. package/build/lib/schema/keywords.js +62 -0
  25. package/build/lib/schema/schema.js +357 -0
  26. package/build/lib/utils.js +26 -35
  27. package/lib/appium-config.schema.json +277 -0
  28. package/lib/appium.js +99 -75
  29. package/lib/cli/args.js +138 -335
  30. package/lib/cli/extension-command.js +7 -6
  31. package/lib/cli/extension.js +12 -4
  32. package/lib/cli/parser.js +248 -96
  33. package/lib/config-file.js +227 -0
  34. package/lib/config.js +71 -61
  35. package/lib/driver-config.js +66 -11
  36. package/lib/ext-config-io.js +287 -0
  37. package/lib/extension-config.js +209 -66
  38. package/lib/grid-register.js +24 -21
  39. package/lib/main.js +139 -68
  40. package/lib/plugin-config.js +32 -2
  41. package/lib/schema/appium-config-schema.js +286 -0
  42. package/lib/schema/arg-spec.js +218 -0
  43. package/lib/schema/cli-args.js +273 -0
  44. package/lib/schema/cli-transformers.js +123 -0
  45. package/lib/schema/index.js +2 -0
  46. package/lib/schema/keywords.js +119 -0
  47. package/lib/schema/schema.js +577 -0
  48. package/lib/utils.js +29 -52
  49. package/package.json +16 -11
  50. package/types/appium-config.d.ts +197 -0
  51. package/types/types.d.ts +201 -0
  52. package/build/lib/cli/parser-helpers.js +0 -106
  53. package/lib/cli/parser-helpers.js +0 -106
package/lib/main.js CHANGED
@@ -1,29 +1,32 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  // transpile:main
4
+ // @ts-check
3
5
 
4
- import { init as logsinkInit } from './logsink';
5
- import logger from './logger'; // logger needs to remain first of imports
6
- import _ from 'lodash';
7
- import { server as baseServer, routeConfiguringFunction as makeRouter } from '@appium/base-driver';
8
- import { asyncify } from 'asyncbox';
9
- import { default as getParser, getDefaultServerArgs } from './cli/parser';
10
- import { USE_ALL_PLUGINS } from './cli/args';
6
+ // @ts-ignore
7
+ import { routeConfiguringFunction as makeRouter, server as baseServer } from '@appium/base-driver';
11
8
  import { logger as logFactory, util } from '@appium/support';
12
- import {
13
- showConfig, checkNodeOk, validateServerArgs,
14
- warnNodeDeprecations, validateTmpDir, getNonDefaultArgs,
15
- getGitRev, APPIUM_VER
16
- } from './config';
17
- import DriverConfig from './driver-config';
18
- import PluginConfig from './plugin-config';
19
- import { DRIVER_TYPE, PLUGIN_TYPE } from './extension-config';
20
- import { runExtensionCommand } from './cli/extension';
9
+ import { asyncify } from 'asyncbox';
10
+ import _ from 'lodash';
21
11
  import { AppiumDriver } from './appium';
12
+ import { driverConfig, pluginConfig, USE_ALL_PLUGINS } from './cli/args';
13
+ import { runExtensionCommand } from './cli/extension';
14
+ import { default as getParser, SERVER_SUBCOMMAND } from './cli/parser';
15
+ import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showConfig, validateTmpDir, warnNodeDeprecations } from './config';
16
+ import { readConfigFile } from './config-file';
17
+ import { DRIVER_TYPE, PLUGIN_TYPE } from './extension-config';
22
18
  import registerNode from './grid-register';
19
+ import logger from './logger'; // logger needs to remain first of imports
20
+ import { init as logsinkInit } from './logsink';
21
+ import { getDefaultsFromSchema, validate } from './schema/schema';
23
22
  import { inspectObject } from './utils';
24
23
 
25
-
26
- async function preflightChecks ({parser, args, driverConfig, pluginConfig, throwInsteadOfExit = false}) {
24
+ /**
25
+ *
26
+ * @param {ParsedArgs} args
27
+ * @param {boolean} [throwInsteadOfExit]
28
+ */
29
+ async function preflightChecks (args, throwInsteadOfExit = false) {
27
30
  try {
28
31
  checkNodeOk();
29
32
  if (args.longStacktrace) {
@@ -34,9 +37,9 @@ async function preflightChecks ({parser, args, driverConfig, pluginConfig, throw
34
37
  process.exit(0);
35
38
  }
36
39
  warnNodeDeprecations();
37
- validateServerArgs(parser, args);
38
- await driverConfig.read();
39
- await pluginConfig.read();
40
+
41
+ validate(args);
42
+
40
43
  if (args.tmpDir) {
41
44
  await validateTmpDir(args.tmpDir);
42
45
  }
@@ -69,7 +72,7 @@ async function logStartupInfo (parser, args) {
69
72
  }
70
73
  logger.info(welcome);
71
74
 
72
- let showArgs = getNonDefaultArgs(parser, args);
75
+ let showArgs = getNonDefaultServerArgs(parser, args);
73
76
  if (_.size(showArgs)) {
74
77
  logNonDefaultArgsWarning(showArgs);
75
78
  }
@@ -96,25 +99,26 @@ function logServerPort (address, port) {
96
99
  * wrap command execution
97
100
  *
98
101
  * @param {Object} args - argparser parsed dict
99
- * @param {PluginConfig} pluginConfig - a plugin extension config
102
+ * @param {import('./plugin-config').default} pluginConfig - a plugin extension config
103
+ * @returns {({pluginName: string} & ((...args: any[]) => unknown))[]}
100
104
  */
101
105
  function getActivePlugins (args, pluginConfig) {
102
- return Object.keys(pluginConfig.installedExtensions).filter((pluginName) =>
103
- _.includes(args.plugins, pluginName) ||
104
- (args.plugins.length === 1 && args.plugins[0] === USE_ALL_PLUGINS)
106
+ return _.compact(Object.keys(pluginConfig.installedExtensions).filter((pluginName) =>
107
+ _.includes(args.usePlugins, pluginName) ||
108
+ (args.usePlugins.length === 1 && args.usePlugins[0] === USE_ALL_PLUGINS)
105
109
  ).map((pluginName) => {
106
110
  try {
107
111
  logger.info(`Attempting to load plugin ${pluginName}...`);
108
- const PluginClass = pluginConfig.require(pluginName);
112
+ const PluginClass = /** @type {{pluginName: string} & ((...args: any[]) => unknown)} */(pluginConfig.require(pluginName));
113
+
109
114
  PluginClass.pluginName = pluginName; // store the plugin name on the class so it can be used later
110
115
  return PluginClass;
111
116
  } catch (err) {
112
117
  logger.error(`Could not load plugin '${pluginName}', so it will not be available. Error ` +
113
118
  `in loading the plugin was: ${err.message}`);
114
119
  logger.debug(err.stack);
115
- return false;
116
120
  }
117
- }).filter(Boolean);
121
+ }));
118
122
  }
119
123
 
120
124
  /**
@@ -123,11 +127,11 @@ function getActivePlugins (args, pluginConfig) {
123
127
  * If the --drivers flag was given, this method only loads the given drivers.
124
128
  *
125
129
  * @param {Object} args - argparser parsed dict
126
- * @param {DriverConfig} driverConfig - a driver extension config
130
+ * @param {import('./driver-config').default} driverConfig - a driver extension config
127
131
  */
128
132
  function getActiveDrivers (args, driverConfig) {
129
- return Object.keys(driverConfig.installedExtensions).filter((driverName) =>
130
- _.includes(args.drivers, driverName) || args.drivers.length === 0
133
+ return _.compact(Object.keys(driverConfig.installedExtensions).filter((driverName) =>
134
+ _.includes(args.useDrivers, driverName) || args.useDrivers.length === 0
131
135
  ).map((driverName) => {
132
136
  try {
133
137
  logger.info(`Attempting to load driver ${driverName}...`);
@@ -136,9 +140,8 @@ function getActiveDrivers (args, driverConfig) {
136
140
  logger.error(`Could not load driver '${driverName}', so it will not be available. Error ` +
137
141
  `in loading the driver was: ${err.message}`);
138
142
  logger.debug(err.stack);
139
- return false;
140
143
  }
141
- }).filter(Boolean);
144
+ }));
142
145
  }
143
146
 
144
147
  function getServerUpdaters (driverClasses, pluginClasses) {
@@ -152,14 +155,25 @@ function getExtraMethodMap (driverClasses, pluginClasses) {
152
155
  );
153
156
  }
154
157
 
155
- async function main (args = null) {
156
- let parser = getParser();
158
+ /**
159
+ * Initializes Appium, but does not start the server.
160
+ *
161
+ * Use this to get at the configuration schema.
162
+ *
163
+ * @example
164
+ * import {init, getSchema} from 'appium';
165
+ * const options = {}; // config object
166
+ * await init(options);
167
+ * 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
+ */
171
+ async function init (args) {
172
+ const parser = await getParser();
157
173
  let throwInsteadOfExit = false;
174
+ /** @type {ParsedArgs} */
175
+ let parsedArgs;
158
176
  if (args) {
159
- // a containing package passed in their own args, let's fill them out
160
- // with defaults
161
- args = Object.assign({}, getDefaultServerArgs(), args);
162
-
163
177
  // if we have a containing package instead of running as a CLI process,
164
178
  // that package might not appreciate us calling 'process.exit' willy-
165
179
  // nilly, so give it the option to have us throw instead of exit
@@ -168,59 +182,106 @@ async function main (args = null) {
168
182
  // but remove it since it's not a real server arg per se
169
183
  delete args.throwInsteadOfExit;
170
184
  }
185
+ parsedArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
171
186
  } else {
172
187
  // otherwise parse from CLI
173
- args = parser.parse_args();
188
+ parsedArgs = parser.parseArgs();
189
+ }
190
+
191
+ const configResult = await readConfigFile(parsedArgs.configFile);
192
+
193
+ if (!_.isEmpty(configResult.errors)) {
194
+ throw new Error(`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`);
195
+ }
196
+
197
+ // merge config and apply defaults.
198
+ // the order of precendece is:
199
+ // 1. command line args
200
+ // 2. config file
201
+ // 3. defaults from config file.
202
+ if (parsedArgs.subcommand === SERVER_SUBCOMMAND) {
203
+ parsedArgs = _.defaultsDeep(
204
+ parsedArgs,
205
+ configResult.config?.server,
206
+ getDefaultsFromSchema()
207
+ );
174
208
  }
175
- await logsinkInit(args);
209
+
210
+ parsedArgs = _.defaultsDeep(
211
+ parsedArgs,
212
+ configResult.config ?? {},
213
+ );
214
+
215
+ await logsinkInit(parsedArgs);
176
216
 
177
217
  // if the user has requested the 'driver' CLI, don't run the normal server,
178
218
  // but instead pass control to the driver CLI
179
- if (args.subcommand === DRIVER_TYPE || args.subcommand === PLUGIN_TYPE) {
180
- await runExtensionCommand(args, args.subcommand);
181
- process.exit();
219
+ if (parsedArgs.subcommand === DRIVER_TYPE) {
220
+ await runExtensionCommand(parsedArgs, parsedArgs.subcommand, driverConfig);
221
+ return {parser};
222
+ }
223
+ if (parsedArgs.subcommand === PLUGIN_TYPE) {
224
+ await runExtensionCommand(parsedArgs, parsedArgs.subcommand, pluginConfig);
225
+ return {parser};
182
226
  }
183
227
 
184
- if (args.logFilters) {
185
- const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(args.logFilters);
228
+ if (parsedArgs.logFilters) {
229
+ const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(parsedArgs.logFilters);
186
230
  if (!_.isEmpty(issues)) {
187
- throw new Error(`The log filtering rules config '${args.logFilters}' has issues: ` +
231
+ throw new Error(`The log filtering rules config '${parsedArgs.logFilters}' has issues: ` +
188
232
  JSON.stringify(issues, null, 2));
189
233
  }
190
234
  if (_.isEmpty(rules)) {
191
- logger.warn(`Found no log filtering rules in '${args.logFilters}'. Is that expected?`);
235
+ logger.warn(`Found no log filtering rules in '${parsedArgs.logFilters}'. Is that expected?`);
192
236
  } else {
193
- logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${args.logFilters}'`);
237
+ logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${parsedArgs.logFilters}'`);
194
238
  }
195
239
  }
196
240
 
197
- let appiumDriver = new AppiumDriver(args);
198
- const driverConfig = new DriverConfig(args.appiumHome);
241
+ const appiumDriver = new AppiumDriver(parsedArgs);
199
242
  // set the config on the umbrella driver so it can match drivers to caps
200
243
  appiumDriver.driverConfig = driverConfig;
201
- const pluginConfig = new PluginConfig(args.appiumHome);
202
- await preflightChecks({parser, args, driverConfig, pluginConfig, throwInsteadOfExit});
203
- const pluginClasses = getActivePlugins(args, pluginConfig);
244
+ await preflightChecks(parsedArgs, throwInsteadOfExit);
245
+
246
+ return {parser, appiumDriver, parsedArgs};
247
+ }
248
+
249
+ /**
250
+ *
251
+ * @param {ParsedArgs} [args]
252
+ * @returns
253
+ */
254
+ async function main (args) {
255
+ const {parser, appiumDriver, parsedArgs} = await init(args);
256
+
257
+ if (!appiumDriver || !parsedArgs) {
258
+ // if this branch is taken, we've run a different subcommand, so there's nothing
259
+ // left to do here.
260
+ return;
261
+ }
262
+
263
+ const pluginClasses = getActivePlugins(parsedArgs, pluginConfig);
204
264
  // set the active plugins on the umbrella driver so it can use them for commands
205
265
  appiumDriver.pluginClasses = pluginClasses;
206
- await logStartupInfo(parser, args);
266
+
267
+ await logStartupInfo(parser, parsedArgs);
207
268
  let routeConfiguringFunction = makeRouter(appiumDriver);
208
269
 
209
- const driverClasses = getActiveDrivers(args, driverConfig);
270
+ const driverClasses = getActiveDrivers(parsedArgs, driverConfig);
210
271
  const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
211
272
  const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
212
273
 
213
274
  const serverOpts = {
214
275
  routeConfiguringFunction,
215
- port: args.port,
216
- hostname: args.address,
217
- allowCors: args.allowCors,
218
- basePath: args.basePath,
276
+ port: parsedArgs.port,
277
+ hostname: parsedArgs.address,
278
+ allowCors: parsedArgs.allowCors,
279
+ basePath: parsedArgs.basePath,
219
280
  serverUpdaters,
220
281
  extraMethodMap,
221
282
  };
222
- if (args.keepAliveTimeout) {
223
- serverOpts.keepAliveTimeout = args.keepAliveTimeout * 1000;
283
+ if (parsedArgs.keepAliveTimeout) {
284
+ serverOpts.keepAliveTimeout = parsedArgs.keepAliveTimeout * 1000;
224
285
  }
225
286
  let server;
226
287
  try {
@@ -232,16 +293,18 @@ async function main (args = null) {
232
293
  return process.exit(1);
233
294
  }
234
295
 
235
- if (args.allowCors) {
296
+ if (parsedArgs.allowCors) {
236
297
  logger.warn('You have enabled CORS requests from any host. Be careful not ' +
237
298
  'to visit sites which could maliciously try to start Appium ' +
238
299
  'sessions on your machine');
239
300
  }
301
+ // @ts-ignore
240
302
  appiumDriver.server = server;
241
303
  try {
242
304
  // configure as node on grid, if necessary
243
- if (args.nodeconfig !== null) {
244
- await registerNode(args.nodeconfig, args.address, args.port, args.basePath);
305
+ // falsy values should not cause this to run
306
+ if (parsedArgs.nodeconfig) {
307
+ await registerNode(parsedArgs.nodeconfig, parsedArgs.address, parsedArgs.port, parsedArgs.basePath);
245
308
  }
246
309
  } catch (err) {
247
310
  await server.close();
@@ -265,7 +328,7 @@ async function main (args = null) {
265
328
  });
266
329
  }
267
330
 
268
- logServerPort(args.address, args.port);
331
+ logServerPort(parsedArgs.address, parsedArgs.port);
269
332
  driverConfig.print();
270
333
  pluginConfig.print(pluginClasses.map((p) => p.pluginName));
271
334
 
@@ -276,4 +339,12 @@ if (require.main === module) {
276
339
  asyncify(main);
277
340
  }
278
341
 
279
- export { main };
342
+ // everything below here is intended to be a public API.
343
+ export { main, init };
344
+ export { APPIUM_HOME } from './extension-config';
345
+ export { getSchema, validate, finalizeSchema } from './schema/schema';
346
+ export { readConfigFile } from './config-file';
347
+
348
+ /**
349
+ * @typedef {import('../types/types').ParsedArgs} ParsedArgs
350
+ */
@@ -1,12 +1,42 @@
1
1
  import _ from 'lodash';
2
- import ExtensionConfig, { PLUGIN_TYPE } from './extension-config';
2
+ import ExtensionConfig from './extension-config';
3
+ import { PLUGIN_TYPE } from './ext-config-io';
3
4
  import log from './logger';
4
5
 
5
6
  export default class PluginConfig extends ExtensionConfig {
6
- constructor (appiumHome, logFn = null) {
7
+
8
+ /**
9
+ * A mapping of `APPIUM_HOME` values to {@link PluginConfig} instances.
10
+ * Each `APPIUM_HOME` should only have one associated `PluginConfig` instance.
11
+ * @type {Record<string,PluginConfig>}
12
+ * @private
13
+ */
14
+ static _instances = {};
15
+
16
+ /**
17
+ * Call {@link PluginConfig.getInstance} instead.
18
+ *
19
+ * Just calls the superclass' constructor with the correct extension type
20
+ * @private
21
+ * @param {string} appiumHome - `APPIUM_HOME` path
22
+ * @param {(...args: any[]) => void)} [logFn] - Optional logging function
23
+ */
24
+ constructor (appiumHome, logFn) {
7
25
  super(appiumHome, PLUGIN_TYPE, logFn);
8
26
  }
9
27
 
28
+ /**
29
+ * Creates or gets an instance of {@link PluginConfig} based value of `appiumHome`
30
+ * @param {string} appiumHome - `APPIUM_HOME` path
31
+ * @param {(...args: any[]) => void} [logFn] - Optional logging function
32
+ * @returns {PluginConfig}
33
+ */
34
+ static getInstance (appiumHome, logFn) {
35
+ const instance = PluginConfig._instances[appiumHome] ?? new PluginConfig(appiumHome, logFn);
36
+ PluginConfig._instances[appiumHome] = instance;
37
+ return instance;
38
+ }
39
+
10
40
  extensionDesc (pluginName, {version}) {
11
41
  return `${pluginName}@${version}`;
12
42
  }
@@ -0,0 +1,286 @@
1
+ // @ts-check
2
+
3
+ const schema = /** @type {const} */ ({
4
+ $schema: 'http://json-schema.org/draft-07/schema',
5
+ additionalProperties: false,
6
+ description: 'A schema for Appium configuration files',
7
+ properties: {
8
+ server: {
9
+ additionalProperties: false,
10
+ description: 'Configuration when running Appium as a server',
11
+ properties: {
12
+ address: {
13
+ $comment:
14
+ 'I think hostname covers both DNS and IPv4...could be wrong',
15
+ appiumCliAliases: ['a'],
16
+ default: '0.0.0.0',
17
+ description: 'IP address to listen on',
18
+ format: 'hostname',
19
+ title: 'address config',
20
+ type: 'string',
21
+ },
22
+ 'allow-cors': {
23
+ description:
24
+ 'Whether the Appium server should allow web browser connections from any host',
25
+ title: 'allow-cors config',
26
+ type: 'boolean',
27
+ default: false,
28
+ },
29
+ 'allow-insecure': {
30
+ appiumCliTransformer: 'csv',
31
+ default: [],
32
+ description:
33
+ 'Set which insecure features are allowed to run in this server\'s sessions. Features are defined on a driver level; see documentation for more details. Note that features defined via "deny-insecure" will be disabled, even if also listed here. If string, a path to a text file containing policy or a comma-delimited list.',
34
+ items: {
35
+ type: 'string',
36
+ },
37
+ title: 'allow-insecure config',
38
+ type: 'array',
39
+ uniqueItems: true,
40
+ },
41
+ 'base-path': {
42
+ appiumCliAliases: ['pa'],
43
+ default: '',
44
+ description:
45
+ 'Base path to use as the prefix for all webdriver routes running on the server',
46
+ title: 'base-path config',
47
+ type: 'string',
48
+ },
49
+ 'callback-address': {
50
+ appiumCliAliases: ['ca'],
51
+ description: 'Callback IP address (default: same as "address")',
52
+ title: 'callback-address config',
53
+ type: 'string',
54
+ },
55
+ 'callback-port': {
56
+ appiumCliAliases: ['cp'],
57
+ default: 4723,
58
+ description: 'Callback port (default: same as "port")',
59
+ maximum: 65535,
60
+ minimum: 1,
61
+ title: 'callback-port config',
62
+ type: 'integer',
63
+ },
64
+ 'debug-log-spacing': {
65
+ default: false,
66
+ description:
67
+ 'Add exaggerated spacing in logs to help with visual inspection',
68
+ title: 'debug-log-spacing config',
69
+ type: 'boolean',
70
+ },
71
+ 'default-capabilities': {
72
+ $comment: 'TODO',
73
+ appiumCliAliases: ['dc'],
74
+ description:
75
+ 'Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. If a string, a path to a JSON file containing the capabilities, or raw JSON.',
76
+ title: 'default-capabilities config',
77
+ type: 'object',
78
+ },
79
+ 'deny-insecure': {
80
+ $comment: 'Allowed values are defined by drivers',
81
+ appiumCliTransformer: 'csv',
82
+ default: [],
83
+ description:
84
+ 'Set which insecure features are not allowed to run in this server\'s sessions. Features are defined on a driver level; see documentation for more details. Features listed here will not be enabled even if also listed in "allow-insecure", and even if "relaxed-security" is enabled. If string, a path to a text file containing policy or a comma-delimited list.',
85
+ items: {
86
+ type: 'string',
87
+ },
88
+ title: 'deny-insecure config',
89
+ type: 'array',
90
+ uniqueItems: true,
91
+ },
92
+ driver: {
93
+ description:
94
+ 'Driver-specific configuration. Keys should correspond to driver package names',
95
+ properties: {},
96
+ title: 'driver config',
97
+ type: 'object',
98
+ },
99
+ 'keep-alive-timeout': {
100
+ appiumCliAliases: ['ka'],
101
+ default: 600,
102
+ description:
103
+ 'Number of seconds the Appium server should apply as both the keep-alive timeout and the connection timeout for all requests. A value of 0 disables the timeout.',
104
+ minimum: 0,
105
+ title: 'keep-alive-timeout config',
106
+ type: 'integer',
107
+ },
108
+ 'local-timezone': {
109
+ default: false,
110
+ description: 'Use local timezone for timestamps',
111
+ title: 'local-timezone config',
112
+ type: 'boolean',
113
+ },
114
+ log: {
115
+ appiumCliAliases: ['g'],
116
+ appiumCliDest: 'logFile',
117
+ description: 'Also send log output to this file',
118
+ title: 'log config',
119
+ type: 'string',
120
+ },
121
+ 'log-filters': {
122
+ $comment: 'TODO',
123
+ description: 'One or more log filtering rules',
124
+ items: {
125
+ type: 'string',
126
+ },
127
+ title: 'log-filters config',
128
+ type: 'array',
129
+ },
130
+ 'log-level': {
131
+ appiumCliDest: 'loglevel',
132
+ default: 'debug',
133
+ description: 'Log level (console[:file])',
134
+ enum: [
135
+ 'info',
136
+ 'info:debug',
137
+ 'info:info',
138
+ 'info:warn',
139
+ 'info:error',
140
+ 'warn',
141
+ 'warn:debug',
142
+ 'warn:info',
143
+ 'warn:warn',
144
+ 'warn:error',
145
+ 'error',
146
+ 'error:debug',
147
+ 'error:info',
148
+ 'error:warn',
149
+ 'error:error',
150
+ 'debug',
151
+ 'debug:debug',
152
+ 'debug:info',
153
+ 'debug:warn',
154
+ 'debug:error',
155
+ ],
156
+ title: 'log-level config',
157
+ type: 'string',
158
+ },
159
+ 'log-no-colors': {
160
+ default: false,
161
+ description: 'Do not use color in console output',
162
+ title: 'log-no-colors config',
163
+ type: 'boolean',
164
+ },
165
+ 'log-timestamp': {
166
+ default: false,
167
+ description: 'Show timestamps in console output',
168
+ title: 'log-timestamp config',
169
+ type: 'boolean',
170
+ },
171
+ 'long-stacktrace': {
172
+ default: false,
173
+ description:
174
+ 'Add long stack traces to log entries. Recommended for debugging only.',
175
+ title: 'long-stacktrace config',
176
+ type: 'boolean',
177
+ },
178
+ 'no-perms-check': {
179
+ default: false,
180
+ description:
181
+ 'Do not check that needed files are readable and/or writable',
182
+ title: 'no-perms-check config',
183
+ type: 'boolean',
184
+ },
185
+ nodeconfig: {
186
+ $comment:
187
+ 'Selenium Grid 3 is unmaintained and Selenium Grid 4 no longer supports this file.',
188
+ description:
189
+ 'Path to configuration JSON file to register Appium as a node with Selenium Grid 3; otherwise the configuration itself',
190
+ title: 'nodeconfig config',
191
+ type: 'object',
192
+ },
193
+ plugin: {
194
+ description:
195
+ 'Plugin-specific configuration. Keys should correspond to plugin package names',
196
+ properties: {},
197
+ title: 'plugin config',
198
+ type: 'object',
199
+ },
200
+ port: {
201
+ appiumCliAliases: ['p'],
202
+ default: 4723,
203
+ description: 'Port to listen on',
204
+ maximum: 65535,
205
+ minimum: 1,
206
+ title: 'port config',
207
+ type: 'integer',
208
+ },
209
+ 'relaxed-security': {
210
+ default: false,
211
+ description:
212
+ 'Disable additional security checks, so it is possible to use some advanced features, provided by drivers supporting this option. Only enable it if all the clients are in the trusted network and it\'s not the case if a client could potentially break out of the session sandbox. Specific features can be overridden by using "deny-insecure"',
213
+ title: 'relaxed-security config',
214
+ type: 'boolean',
215
+ },
216
+ 'session-override': {
217
+ default: false,
218
+ description: 'Enables session override (clobbering)',
219
+ title: 'session-override config',
220
+ type: 'boolean',
221
+ },
222
+ 'strict-caps': {
223
+ default: false,
224
+ description:
225
+ 'Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device',
226
+ title: 'strict-caps config',
227
+ type: 'boolean',
228
+ },
229
+ tmp: {
230
+ appiumCliDest: 'tmpDir',
231
+ description:
232
+ 'Absolute path to directory Appium can use to manage temp files. Defaults to C:\\Windows\\Temp on Windows and /tmp otherwise.',
233
+ title: 'tmp config',
234
+ type: 'string',
235
+ },
236
+ 'trace-dir': {
237
+ description:
238
+ 'Absolute path to directory Appium can use to save iOS instrument traces; defaults to <tmp>/appium-instruments',
239
+ title: 'trace-dir config',
240
+ type: 'string',
241
+ },
242
+ 'use-drivers': {
243
+ appiumCliDescription:
244
+ 'A list of drivers to activate. Can be a comma-delimited string or path to CSV file. By default, all installed drivers will be activated.',
245
+ default: [],
246
+ description:
247
+ 'A list of drivers to activate. By default, all installed drivers will be activated.',
248
+ items: {
249
+ type: 'string',
250
+ },
251
+ title: 'use-drivers config',
252
+ type: 'array',
253
+ uniqueItems: true,
254
+ },
255
+ 'use-plugins': {
256
+ appiumCliDescription:
257
+ 'A list of plugins to activate. Can be a comma-delimited string, path to CSV file, or the string "all" to use all installed plugins.',
258
+ default: [],
259
+ description:
260
+ 'A list of plugins to activate. To activate all plugins, the value should be an array with a single item "all".',
261
+ items: {
262
+ type: 'string',
263
+ },
264
+ title: 'use-plugins config',
265
+ type: 'array',
266
+ uniqueItems: true,
267
+ },
268
+ webhook: {
269
+ $comment:
270
+ 'This should probably use a uri-template format to restrict the protocol to http/https',
271
+ appiumCliAliases: ['G'],
272
+ description: 'Also send log output to this http listener',
273
+ format: 'uri',
274
+ title: 'webhook config',
275
+ type: 'string',
276
+ },
277
+ },
278
+ title: 'server config',
279
+ type: 'object',
280
+ },
281
+ },
282
+ title: 'Appium Configuration',
283
+ type: 'object',
284
+ });
285
+
286
+ export default schema;