appium 2.0.0-beta.3 → 2.0.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -11
- package/build/lib/appium.d.ts +215 -0
- package/build/lib/appium.d.ts.map +1 -0
- package/build/lib/appium.js +241 -132
- package/build/lib/cli/args.d.ts +20 -0
- package/build/lib/cli/args.d.ts.map +1 -0
- package/build/lib/cli/args.js +96 -282
- package/build/lib/cli/driver-command.d.ts +36 -0
- package/build/lib/cli/driver-command.d.ts.map +1 -0
- package/build/lib/cli/driver-command.js +19 -12
- package/build/lib/cli/extension-command.d.ts +345 -0
- package/build/lib/cli/extension-command.d.ts.map +1 -0
- package/build/lib/cli/extension-command.js +171 -96
- package/build/lib/cli/extension.d.ts +14 -0
- package/build/lib/cli/extension.d.ts.map +1 -0
- package/build/lib/cli/extension.js +31 -16
- package/build/lib/cli/parser.d.ts +80 -0
- package/build/lib/cli/parser.d.ts.map +1 -0
- package/build/lib/cli/parser.js +152 -95
- package/build/lib/cli/plugin-command.d.ts +39 -0
- package/build/lib/cli/plugin-command.d.ts.map +1 -0
- package/build/lib/cli/plugin-command.js +18 -13
- package/build/lib/cli/utils.d.ts +29 -0
- package/build/lib/cli/utils.d.ts.map +1 -0
- package/build/lib/cli/utils.js +27 -3
- package/build/lib/config-file.d.ts +100 -0
- package/build/lib/config-file.d.ts.map +1 -0
- package/build/lib/config-file.js +136 -0
- package/build/lib/config.d.ts +41 -0
- package/build/lib/config.d.ts.map +1 -0
- package/build/lib/config.js +92 -67
- package/build/lib/constants.d.ts +48 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +60 -0
- package/build/lib/extension/driver-config.d.ts +84 -0
- package/build/lib/extension/driver-config.d.ts.map +1 -0
- package/build/lib/extension/driver-config.js +190 -0
- package/build/lib/extension/extension-config.d.ts +170 -0
- package/build/lib/extension/extension-config.d.ts.map +1 -0
- package/build/lib/extension/extension-config.js +297 -0
- package/build/lib/extension/index.d.ts +39 -0
- package/build/lib/extension/index.d.ts.map +1 -0
- package/build/lib/extension/index.js +77 -0
- package/build/lib/extension/manifest.d.ts +174 -0
- package/build/lib/extension/manifest.d.ts.map +1 -0
- package/build/lib/extension/manifest.js +246 -0
- package/build/lib/extension/package-changed.d.ts +11 -0
- package/build/lib/extension/package-changed.d.ts.map +1 -0
- package/build/lib/extension/package-changed.js +68 -0
- package/build/lib/extension/plugin-config.d.ts +62 -0
- package/build/lib/extension/plugin-config.d.ts.map +1 -0
- package/build/lib/extension/plugin-config.js +87 -0
- package/build/lib/grid-register.d.ts +10 -0
- package/build/lib/grid-register.d.ts.map +1 -0
- package/build/lib/grid-register.js +21 -25
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +4 -6
- package/build/lib/logsink.d.ts +4 -0
- package/build/lib/logsink.d.ts.map +1 -0
- package/build/lib/logsink.js +12 -16
- package/build/lib/main.d.ts +54 -0
- package/build/lib/main.d.ts.map +1 -0
- package/build/lib/main.js +189 -90
- package/build/lib/schema/arg-spec.d.ts +143 -0
- package/build/lib/schema/arg-spec.d.ts.map +1 -0
- package/build/lib/schema/arg-spec.js +119 -0
- package/build/lib/schema/cli-args.d.ts +19 -0
- package/build/lib/schema/cli-args.d.ts.map +1 -0
- package/build/lib/schema/cli-args.js +180 -0
- package/build/lib/schema/cli-transformers.d.ts +5 -0
- package/build/lib/schema/cli-transformers.d.ts.map +1 -0
- package/build/lib/schema/cli-transformers.js +74 -0
- package/build/lib/schema/index.d.ts +3 -0
- package/build/lib/schema/index.d.ts.map +1 -0
- package/build/lib/schema/index.js +34 -0
- package/build/lib/schema/keywords.d.ts +24 -0
- package/build/lib/schema/keywords.d.ts.map +1 -0
- package/build/lib/schema/keywords.js +70 -0
- package/build/lib/schema/schema.d.ts +259 -0
- package/build/lib/schema/schema.d.ts.map +1 -0
- package/build/lib/schema/schema.js +452 -0
- package/build/lib/utils.d.ts +66 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +35 -139
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/types/appium-manifest.d.ts +40 -0
- package/build/types/appium-manifest.d.ts.map +1 -0
- package/build/types/cli.d.ts +112 -0
- package/build/types/cli.d.ts.map +1 -0
- package/build/types/extension.d.ts +43 -0
- package/build/types/extension.d.ts.map +1 -0
- package/build/types/external-manifest.d.ts +47 -0
- package/build/types/external-manifest.d.ts.map +1 -0
- package/build/types/index.d.ts +15 -0
- package/build/types/index.d.ts.map +1 -0
- package/index.js +11 -0
- package/lib/appium-config.schema.json +278 -0
- package/lib/appium.js +402 -155
- package/lib/cli/args.js +174 -377
- package/lib/cli/driver-command.js +22 -7
- package/lib/cli/extension-command.js +372 -177
- package/lib/cli/extension.js +32 -10
- package/lib/cli/parser.js +253 -83
- package/lib/cli/plugin-command.js +19 -6
- package/lib/cli/utils.js +22 -2
- package/lib/config-file.js +223 -0
- package/lib/config.js +170 -69
- package/lib/constants.js +78 -0
- package/lib/extension/driver-config.js +249 -0
- package/lib/extension/extension-config.js +458 -0
- package/lib/extension/index.js +102 -0
- package/lib/extension/manifest.js +484 -0
- package/lib/extension/package-changed.js +63 -0
- package/lib/extension/plugin-config.js +113 -0
- package/lib/grid-register.js +25 -22
- package/lib/logger.js +1 -1
- package/lib/logsink.js +14 -7
- package/lib/main.js +255 -90
- package/lib/schema/arg-spec.js +232 -0
- package/lib/schema/cli-args.js +261 -0
- package/lib/schema/cli-transformers.js +122 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/keywords.js +134 -0
- package/lib/schema/schema.js +734 -0
- package/lib/utils.js +85 -129
- package/package.json +68 -85
- package/scripts/postinstall.js +71 -0
- package/types/appium-manifest.ts +61 -0
- package/types/cli.ts +153 -0
- package/types/extension.ts +56 -0
- package/types/external-manifest.ts +58 -0
- package/types/index.ts +14 -0
- package/CHANGELOG.md +0 -3515
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/lib/cli/npm.js +0 -206
- package/build/lib/cli/parser-helpers.js +0 -82
- package/build/lib/driver-config.js +0 -77
- package/build/lib/drivers.js +0 -96
- package/build/lib/extension-config.js +0 -251
- package/build/lib/plugin-config.js +0 -59
- package/build/lib/plugins.js +0 -14
- package/lib/cli/npm.js +0 -183
- package/lib/cli/parser-helpers.js +0 -79
- package/lib/driver-config.js +0 -46
- package/lib/drivers.js +0 -81
- package/lib/extension-config.js +0 -208
- package/lib/plugin-config.js +0 -34
- package/lib/plugins.js +0 -10
package/lib/main.js
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// transpile:main
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
3
|
+
|
|
4
|
+
import { init as logsinkInit } from './logsink'; // this import needs to come first since it sets up global npmlog
|
|
5
|
+
import logger from './logger'; // logger needs to remain second
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
import { routeConfiguringFunction as makeRouter, server as baseServer } from '@appium/base-driver';
|
|
8
|
+
import { logger as logFactory, util, env } from '@appium/support';
|
|
8
9
|
import { asyncify } from 'asyncbox';
|
|
9
|
-
import
|
|
10
|
-
import { USE_ALL_PLUGINS } from './cli/args';
|
|
11
|
-
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';
|
|
10
|
+
import _ from 'lodash';
|
|
21
11
|
import { AppiumDriver } from './appium';
|
|
12
|
+
import { runExtensionCommand } from './cli/extension';
|
|
13
|
+
import { getParser } from './cli/parser';
|
|
14
|
+
import { APPIUM_VER, checkNodeOk, getGitRev, getNonDefaultServerArgs, showConfig, showBuildInfo, validateTmpDir, warnNodeDeprecations } from './config';
|
|
15
|
+
import { readConfigFile } from './config-file';
|
|
16
|
+
import { loadExtensions, getActivePlugins, getActiveDrivers } from './extension';
|
|
17
|
+
import { DRIVER_TYPE, PLUGIN_TYPE, SERVER_SUBCOMMAND } from './constants';
|
|
22
18
|
import registerNode from './grid-register';
|
|
23
|
-
import {
|
|
19
|
+
import { getDefaultsForSchema, validate } from './schema/schema';
|
|
20
|
+
import { inspect } from './utils';
|
|
24
21
|
|
|
22
|
+
const {resolveAppiumHome} = env;
|
|
25
23
|
|
|
26
|
-
|
|
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) {
|
|
30
33
|
require('longjohn').async_trace_limit = -1;
|
|
31
34
|
}
|
|
32
|
-
if (args.
|
|
33
|
-
await
|
|
35
|
+
if (args.showBuildInfo) {
|
|
36
|
+
await showBuildInfo();
|
|
34
37
|
process.exit(0);
|
|
35
38
|
}
|
|
36
39
|
warnNodeDeprecations();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
|
|
41
|
+
validate(args);
|
|
42
|
+
|
|
40
43
|
if (args.tmpDir) {
|
|
41
44
|
await validateTmpDir(args.tmpDir);
|
|
42
45
|
}
|
|
@@ -50,18 +53,27 @@ async function preflightChecks ({parser, args, driverConfig, pluginConfig, throw
|
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @param {Args} args
|
|
58
|
+
*/
|
|
53
59
|
function logNonDefaultArgsWarning (args) {
|
|
54
60
|
logger.info('Non-default server args:');
|
|
55
|
-
|
|
61
|
+
inspect(args);
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @param {Args['defaultCapabilities']} caps
|
|
66
|
+
*/
|
|
58
67
|
function logDefaultCapabilitiesWarning (caps) {
|
|
59
68
|
logger.info('Default capabilities, which will be added to each request ' +
|
|
60
69
|
'unless overridden by desired capabilities:');
|
|
61
|
-
|
|
70
|
+
inspect(caps);
|
|
62
71
|
}
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
/**
|
|
74
|
+
* @param {ParsedArgs} args
|
|
75
|
+
*/
|
|
76
|
+
async function logStartupInfo (args) {
|
|
65
77
|
let welcome = `Welcome to Appium v${APPIUM_VER}`;
|
|
66
78
|
let appiumRev = await getGitRev();
|
|
67
79
|
if (appiumRev) {
|
|
@@ -69,7 +81,7 @@ async function logStartupInfo (parser, args) {
|
|
|
69
81
|
}
|
|
70
82
|
logger.info(welcome);
|
|
71
83
|
|
|
72
|
-
let showArgs =
|
|
84
|
+
let showArgs = getNonDefaultServerArgs(args);
|
|
73
85
|
if (_.size(showArgs)) {
|
|
74
86
|
logNonDefaultArgsWarning(showArgs);
|
|
75
87
|
}
|
|
@@ -83,20 +95,77 @@ async function logStartupInfo (parser, args) {
|
|
|
83
95
|
// }
|
|
84
96
|
}
|
|
85
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Logs the address and port the server is listening on
|
|
100
|
+
* @param {string} address - Address
|
|
101
|
+
* @param {number} port - Port
|
|
102
|
+
* @returns {void}
|
|
103
|
+
*/
|
|
86
104
|
function logServerPort (address, port) {
|
|
87
105
|
let logMessage = `Appium REST http interface listener started on ` +
|
|
88
106
|
`${address}:${port}`;
|
|
89
107
|
logger.info(logMessage);
|
|
90
108
|
}
|
|
91
109
|
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Gets a list of `updateServer` functions from all extensions
|
|
112
|
+
* @param {DriverClass[]} driverClasses
|
|
113
|
+
* @param {PluginClass[]} pluginClasses
|
|
114
|
+
* @returns {import('@appium/base-driver/lib/basedriver/driver').UpdateServerCallback[]}
|
|
115
|
+
*/
|
|
116
|
+
function getServerUpdaters (driverClasses, pluginClasses) {
|
|
117
|
+
return _.compact(_.map([...driverClasses, ...pluginClasses], 'updateServer'));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Makes a big `MethodMap` from all the little `MethodMap`s in the extensions
|
|
122
|
+
* @param {DriverClass[]} driverClasses
|
|
123
|
+
* @param {PluginClass[]} pluginClasses
|
|
124
|
+
* @returns {import('@appium/types').MethodMap}
|
|
125
|
+
*/
|
|
126
|
+
function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
127
|
+
return [...driverClasses, ...pluginClasses].reduce(
|
|
128
|
+
(map, klass) => ({...map, .../** @type {DriverClass} */(klass).newMethodMap ?? {}}),
|
|
129
|
+
{}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @template [T=WithServerSubcommand]
|
|
135
|
+
* @param {Args<T>} args
|
|
136
|
+
* @returns {args is Args<WithServerSubcommand>}
|
|
137
|
+
*/
|
|
138
|
+
function areServerCommandArgs (args) {
|
|
139
|
+
return args.subcommand === SERVER_SUBCOMMAND;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Initializes Appium, but does not start the server.
|
|
144
|
+
*
|
|
145
|
+
* Use this to get at the configuration schema.
|
|
146
|
+
*
|
|
147
|
+
* If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
|
|
148
|
+
*
|
|
149
|
+
* @template [T=WithServerSubcommand]
|
|
150
|
+
* @param {Args<T>} [args] - Partial args (progammatic usage only)
|
|
151
|
+
* @returns {Promise<ServerInitResult | ExtCommandInitResult>}
|
|
152
|
+
* @example
|
|
153
|
+
* import {init, getSchema} from 'appium';
|
|
154
|
+
* const options = {}; // config object
|
|
155
|
+
* await init(options);
|
|
156
|
+
* const schema = getSchema(); // entire config schema including plugins and drivers
|
|
157
|
+
*/
|
|
158
|
+
async function init (args) {
|
|
159
|
+
const appiumHome = args?.appiumHome ?? await resolveAppiumHome();
|
|
160
|
+
|
|
161
|
+
const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);
|
|
162
|
+
|
|
163
|
+
const parser = getParser();
|
|
94
164
|
let throwInsteadOfExit = false;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// with defaults
|
|
98
|
-
args = Object.assign({}, getDefaultServerArgs(), args);
|
|
165
|
+
/** @type {Args<T>} */
|
|
166
|
+
let preConfigArgs;
|
|
99
167
|
|
|
168
|
+
if (args) {
|
|
100
169
|
// if we have a containing package instead of running as a CLI process,
|
|
101
170
|
// that package might not appreciate us calling 'process.exit' willy-
|
|
102
171
|
// nilly, so give it the option to have us throw instead of exit
|
|
@@ -105,80 +174,136 @@ async function main (args = null) {
|
|
|
105
174
|
// but remove it since it's not a real server arg per se
|
|
106
175
|
delete args.throwInsteadOfExit;
|
|
107
176
|
}
|
|
177
|
+
preConfigArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
|
|
108
178
|
} else {
|
|
109
179
|
// otherwise parse from CLI
|
|
110
|
-
|
|
180
|
+
preConfigArgs = /** @type {Args<T>} */(parser.parseArgs());
|
|
111
181
|
}
|
|
112
|
-
await logsinkInit(args);
|
|
113
182
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
process.exit();
|
|
183
|
+
const configResult = await readConfigFile(preConfigArgs.configFile);
|
|
184
|
+
|
|
185
|
+
if (!_.isEmpty(configResult.errors)) {
|
|
186
|
+
throw new Error(`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`);
|
|
119
187
|
}
|
|
120
188
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
189
|
+
// merge config and apply defaults.
|
|
190
|
+
// the order of precendece is:
|
|
191
|
+
// 1. command line args
|
|
192
|
+
// 2. config file
|
|
193
|
+
// 3. defaults from config file.
|
|
194
|
+
if (!areServerCommandArgs(preConfigArgs)) {
|
|
195
|
+
|
|
196
|
+
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
197
|
+
// but instead pass control to the driver CLI
|
|
198
|
+
if (preConfigArgs.subcommand === DRIVER_TYPE) {
|
|
199
|
+
await runExtensionCommand(preConfigArgs, driverConfig);
|
|
200
|
+
return {};
|
|
126
201
|
}
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${args.logFilters}'`);
|
|
202
|
+
if (preConfigArgs.subcommand === PLUGIN_TYPE) {
|
|
203
|
+
await runExtensionCommand(preConfigArgs, pluginConfig);
|
|
204
|
+
return {};
|
|
131
205
|
}
|
|
206
|
+
/* istanbul ignore next */
|
|
207
|
+
return {}; // should never happen
|
|
208
|
+
} else {
|
|
209
|
+
const defaults = getDefaultsForSchema(false);
|
|
210
|
+
|
|
211
|
+
/** @type {ParsedArgs} */
|
|
212
|
+
const serverArgs = _.defaultsDeep(
|
|
213
|
+
preConfigArgs,
|
|
214
|
+
configResult.config?.server,
|
|
215
|
+
defaults
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
if (preConfigArgs.showConfig) {
|
|
219
|
+
showConfig(getNonDefaultServerArgs(preConfigArgs), configResult, defaults, serverArgs);
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
await logsinkInit(serverArgs);
|
|
224
|
+
|
|
225
|
+
if (serverArgs.logFilters) {
|
|
226
|
+
const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(serverArgs.logFilters);
|
|
227
|
+
if (!_.isEmpty(issues)) {
|
|
228
|
+
throw new Error(`The log filtering rules config '${serverArgs.logFilters}' has issues: ` +
|
|
229
|
+
JSON.stringify(issues, null, 2));
|
|
230
|
+
}
|
|
231
|
+
if (_.isEmpty(rules)) {
|
|
232
|
+
logger.warn(`Found no log filtering rules in '${serverArgs.logFilters}'. Is that expected?`);
|
|
233
|
+
} else {
|
|
234
|
+
logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${serverArgs.logFilters}'`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const appiumDriver = new AppiumDriver(serverArgs);
|
|
239
|
+
// set the config on the umbrella driver so it can match drivers to caps
|
|
240
|
+
appiumDriver.driverConfig = driverConfig;
|
|
241
|
+
await preflightChecks(serverArgs, throwInsteadOfExit);
|
|
242
|
+
|
|
243
|
+
return /** @type {ServerInitResult} */({appiumDriver, parsedArgs: serverArgs, driverConfig, pluginConfig});
|
|
132
244
|
}
|
|
245
|
+
}
|
|
133
246
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
249
|
+
* server instance if so; otherwise resolves w/ `undefined`.
|
|
250
|
+
* @template [T=WithServerSubcommand]
|
|
251
|
+
* @param {Args<T>} [args] - Arguments from CLI or otherwise
|
|
252
|
+
* @returns {Promise<import('@appium/types').AppiumServer|undefined>}
|
|
253
|
+
*/
|
|
254
|
+
async function main (args) {
|
|
255
|
+
const {appiumDriver, parsedArgs, pluginConfig, driverConfig} = /** @type {ServerInitResult} */(await init(args));
|
|
256
|
+
|
|
257
|
+
if (!appiumDriver || !parsedArgs || !pluginConfig || !driverConfig) {
|
|
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(pluginConfig, parsedArgs.usePlugins);
|
|
264
|
+
// set the active plugins on the umbrella driver so it can use them for commands
|
|
265
|
+
appiumDriver.pluginClasses = pluginClasses;
|
|
266
|
+
|
|
267
|
+
await logStartupInfo(parsedArgs);
|
|
140
268
|
let routeConfiguringFunction = makeRouter(appiumDriver);
|
|
141
269
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// it can use them to wrap command execution
|
|
146
|
-
const plugins = Object.keys(pluginConfig.installedExtensions).filter((pluginName) =>
|
|
147
|
-
_.includes(args.plugins, pluginName) ||
|
|
148
|
-
(args.plugins.length === 1 && args.plugins[0] === USE_ALL_PLUGINS)
|
|
149
|
-
).map((pluginName) => {
|
|
150
|
-
try {
|
|
151
|
-
const PluginClass = pluginConfig.require(pluginName);
|
|
152
|
-
return new PluginClass(pluginName);
|
|
153
|
-
} catch (err) {
|
|
154
|
-
logger.error(`Could not load plugin '${pluginName}', so it will not be available. Error ` +
|
|
155
|
-
`in loading the plugin was: ${err}`);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}).filter(Boolean);
|
|
159
|
-
appiumDriver.plugins = plugins;
|
|
270
|
+
const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
|
|
271
|
+
const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
|
|
272
|
+
const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
|
|
160
273
|
|
|
161
|
-
|
|
274
|
+
const serverOpts = {
|
|
162
275
|
routeConfiguringFunction,
|
|
163
|
-
port:
|
|
164
|
-
hostname:
|
|
165
|
-
allowCors:
|
|
166
|
-
basePath:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
276
|
+
port: parsedArgs.port,
|
|
277
|
+
hostname: parsedArgs.address,
|
|
278
|
+
allowCors: parsedArgs.allowCors,
|
|
279
|
+
basePath: parsedArgs.basePath,
|
|
280
|
+
serverUpdaters,
|
|
281
|
+
extraMethodMap,
|
|
282
|
+
};
|
|
283
|
+
if (parsedArgs.keepAliveTimeout) {
|
|
284
|
+
serverOpts.keepAliveTimeout = parsedArgs.keepAliveTimeout * 1000;
|
|
285
|
+
}
|
|
286
|
+
let server;
|
|
287
|
+
try {
|
|
288
|
+
server = await baseServer(serverOpts);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
logger.error(`Could not configure Appium server. It's possible that a driver or plugin tried ` +
|
|
291
|
+
`to update the server and failed. Original error: ${err.message}`);
|
|
292
|
+
logger.debug(err.stack);
|
|
293
|
+
return process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (parsedArgs.allowCors) {
|
|
170
297
|
logger.warn('You have enabled CORS requests from any host. Be careful not ' +
|
|
171
298
|
'to visit sites which could maliciously try to start Appium ' +
|
|
172
299
|
'sessions on your machine');
|
|
173
300
|
}
|
|
174
301
|
appiumDriver.server = server;
|
|
175
302
|
try {
|
|
176
|
-
// TODO prelaunch if args.launch is set
|
|
177
|
-
// TODO: startAlertSocket(server, appiumServer);
|
|
178
|
-
|
|
179
303
|
// configure as node on grid, if necessary
|
|
180
|
-
|
|
181
|
-
|
|
304
|
+
// falsy values should not cause this to run
|
|
305
|
+
if (parsedArgs.nodeconfig) {
|
|
306
|
+
await registerNode(parsedArgs.nodeconfig, parsedArgs.address, parsedArgs.port, parsedArgs.basePath);
|
|
182
307
|
}
|
|
183
308
|
} catch (err) {
|
|
184
309
|
await server.close();
|
|
@@ -202,15 +327,55 @@ async function main (args = null) {
|
|
|
202
327
|
});
|
|
203
328
|
}
|
|
204
329
|
|
|
205
|
-
logServerPort(
|
|
330
|
+
logServerPort(parsedArgs.address, parsedArgs.port);
|
|
206
331
|
driverConfig.print();
|
|
207
|
-
pluginConfig.print(
|
|
332
|
+
pluginConfig.print(pluginClasses.map((p) => p.pluginName));
|
|
208
333
|
|
|
209
334
|
return server;
|
|
210
335
|
}
|
|
211
336
|
|
|
337
|
+
// NOTE: this is here for backwards compat for any scripts referencing `main.js` directly
|
|
338
|
+
// (more specifically, `build/lib/main.js`)
|
|
339
|
+
// the executable is now `../index.js`, so that module will typically be `require.main`.
|
|
212
340
|
if (require.main === module) {
|
|
213
341
|
asyncify(main);
|
|
214
342
|
}
|
|
215
343
|
|
|
216
|
-
|
|
344
|
+
// everything below here is intended to be a public API.
|
|
345
|
+
export { readConfigFile } from './config-file';
|
|
346
|
+
export { finalizeSchema, getSchema, validate } from './schema/schema';
|
|
347
|
+
export { main, init, resolveAppiumHome };
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* @typedef {import('../types').DriverType} DriverType
|
|
351
|
+
* @typedef {import('../types').PluginType} PluginType
|
|
352
|
+
* @typedef {import('../types').DriverClass} DriverClass
|
|
353
|
+
* @typedef {import('../types').PluginClass} PluginClass
|
|
354
|
+
* @typedef {import('../types').WithServerSubcommand} WithServerSubcommand
|
|
355
|
+
*/
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Literally an empty object
|
|
359
|
+
* @typedef { {} } ExtCommandInitResult
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @typedef ServerInitData
|
|
364
|
+
* @property {AppiumDriver} appiumDriver - The Appium driver
|
|
365
|
+
* @property {import('../types').ParsedArgs} parsedArgs - The parsed arguments
|
|
366
|
+
*/
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @typedef {ServerInitData & import('./extension').ExtensionConfigs} ServerInitResult
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* @template [T=WithServerSubcommand]
|
|
374
|
+
* @typedef {import('../types').Args<T>} Args
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @template [T=WithServerSubcommand]
|
|
379
|
+
* @typedef {import('../types').ParsedArgs<T>} ParsedArgs
|
|
380
|
+
*/
|
|
381
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The original ID of the Appium config schema.
|
|
5
|
+
* We use this in the CLI to convert it to `argparse` options.
|
|
6
|
+
*/
|
|
7
|
+
export const APPIUM_CONFIG_SCHEMA_ID = 'appium.json';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The schema prop containing server-related options. Everything in here
|
|
11
|
+
* is "native" to Appium.
|
|
12
|
+
* Used by {@link flattenSchema} for transforming the schema into CLI args.
|
|
13
|
+
*/
|
|
14
|
+
export const SERVER_PROP_NAME = 'server';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Used to parse extension info from a schema ID.
|
|
18
|
+
*/
|
|
19
|
+
const SCHEMA_ID_REGEXP = /^(?<extType>.+?)-(?<normalizedExtName>.+)\.json$/;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Avoid typos by using constants!
|
|
23
|
+
*/
|
|
24
|
+
const PROPERTIES = 'properties';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* An `ArgSpec` is a class representing metadata about an argument (or config
|
|
28
|
+
* option) used for cross-referencing.
|
|
29
|
+
*
|
|
30
|
+
* This class has no instance methods, and is basically just a read-only "struct".
|
|
31
|
+
* @template D
|
|
32
|
+
*/
|
|
33
|
+
export class ArgSpec {
|
|
34
|
+
/**
|
|
35
|
+
* The canonical name of the argument. Corresponds to key in schema's `properties` prop.
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
name;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The `ExtensionType` of the argument. This will be set if the arg came from an extension;
|
|
42
|
+
* otherwise it will be `undefined`.
|
|
43
|
+
* @type {ExtensionType|undefined}
|
|
44
|
+
*/
|
|
45
|
+
extType;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The name of the extension, if this argument came from an extension.
|
|
49
|
+
*
|
|
50
|
+
* Otherwise `undefined`.
|
|
51
|
+
* @type {string|undefined}
|
|
52
|
+
*/
|
|
53
|
+
extName;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The schema ID (`$id`) for the argument. This is automatically determined, and any user-provided `$id`s will be overwritten.
|
|
57
|
+
*
|
|
58
|
+
* @type {string}
|
|
59
|
+
*/
|
|
60
|
+
ref;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The CLI argument, sans leading dashes.
|
|
64
|
+
* @type {string}
|
|
65
|
+
*/
|
|
66
|
+
arg;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The desired keypath for the argument after arguments have been parsed.
|
|
70
|
+
*
|
|
71
|
+
* Typically this is camelCased. If the arg came from an extension, it will be prefixed with
|
|
72
|
+
* `<extType>.<extName>.`
|
|
73
|
+
* @type {string}
|
|
74
|
+
*/
|
|
75
|
+
dest;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The same as {@link ArgSpec.dest} but without the leading `<extType>.<extName>.` prefix.
|
|
79
|
+
*/
|
|
80
|
+
rawDest;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Whatever the default value of this argument is, as specified by the
|
|
84
|
+
* `default` property of the schema.
|
|
85
|
+
* @type {D|undefined}
|
|
86
|
+
*/
|
|
87
|
+
defaultValue;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Builds some computed fields and assigns them to the instance.
|
|
91
|
+
*
|
|
92
|
+
* Undefined properties are not assigned.
|
|
93
|
+
*
|
|
94
|
+
* The _constructor_ is private. Use {@link ArgSpec.create} instead.
|
|
95
|
+
* @private
|
|
96
|
+
* @param {string} name
|
|
97
|
+
* @param {ArgSpecOptions<D>} [opts]
|
|
98
|
+
*/
|
|
99
|
+
constructor (name, {extType, extName, dest, defaultValue} = {}) {
|
|
100
|
+
// we must normalize the extension name to fit into our convention for CLI
|
|
101
|
+
// args.
|
|
102
|
+
const arg = ArgSpec.toArg(name, extType, extName);
|
|
103
|
+
|
|
104
|
+
const ref = ArgSpec.toSchemaRef(name, extType, extName);
|
|
105
|
+
|
|
106
|
+
// if no explicit `dest` provided, just camelCase the name to avoid needing
|
|
107
|
+
// to use bracket syntax when accessing props on the parsed args object.
|
|
108
|
+
const rawDest = _.camelCase(dest ?? name);
|
|
109
|
+
|
|
110
|
+
const destKeypath =
|
|
111
|
+
extType && extName ? [extType, extName, rawDest].join('.') : rawDest;
|
|
112
|
+
|
|
113
|
+
this.defaultValue = defaultValue;
|
|
114
|
+
this.name = name;
|
|
115
|
+
this.extType = extType;
|
|
116
|
+
this.extName = extName;
|
|
117
|
+
this.arg = arg;
|
|
118
|
+
this.dest = destKeypath;
|
|
119
|
+
this.ref = ref;
|
|
120
|
+
this.rawDest = rawDest;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Return the schema ID (`$id`) for the **argument** given the parameters.
|
|
125
|
+
*
|
|
126
|
+
* If you need the "root" or "base" schema ID, use {@link ArgSpec.toSchemaBaseRef} instead.
|
|
127
|
+
* @param {string} name - Argument name
|
|
128
|
+
* @param {ExtensionType} [extType] - Extension type
|
|
129
|
+
* @param {string} [extName] - Extension name
|
|
130
|
+
* @returns {string} Schema ID
|
|
131
|
+
*/
|
|
132
|
+
static toSchemaRef (name, extType, extName) {
|
|
133
|
+
const baseRef = ArgSpec.toSchemaBaseRef(extType, extName);
|
|
134
|
+
if (extType && extName) {
|
|
135
|
+
return [`${baseRef}#`, PROPERTIES, name].join('/');
|
|
136
|
+
}
|
|
137
|
+
return [`${baseRef}#`, PROPERTIES, SERVER_PROP_NAME, PROPERTIES, name].join('/');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Return the schema ID for an extension or the base schema ID.
|
|
142
|
+
* @param {ExtensionType} [extType] - Extension type
|
|
143
|
+
* @param {string} [extName] - Extension name
|
|
144
|
+
*/
|
|
145
|
+
static toSchemaBaseRef (extType, extName) {
|
|
146
|
+
if (extType && extName) {
|
|
147
|
+
return `${extType}-${ArgSpec.toNormalizedExtName(extName)}.json`;
|
|
148
|
+
}
|
|
149
|
+
return APPIUM_CONFIG_SCHEMA_ID;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Return the unique ID for the argument given the parameters.
|
|
154
|
+
* @param {string} name - Argument name
|
|
155
|
+
* @param {ExtensionType} [extType] - Extension type
|
|
156
|
+
* @param {string} [extName] - Extension name
|
|
157
|
+
* @returns {string} Unique ID
|
|
158
|
+
*/
|
|
159
|
+
static toArg (name, extType, extName) {
|
|
160
|
+
const properName = _.kebabCase(name.replace(/^--?/, ''));
|
|
161
|
+
if (extType && extName) {
|
|
162
|
+
return [extType, _.kebabCase(extName), properName].join('-');
|
|
163
|
+
}
|
|
164
|
+
return properName;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Normalizes a raw extension name (not including the type).
|
|
169
|
+
* @param {string} extName - Extension name
|
|
170
|
+
* @returns {string} Normalized extension name
|
|
171
|
+
*/
|
|
172
|
+
static toNormalizedExtName (extName) {
|
|
173
|
+
return _.kebabCase(extName);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
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
|
+
* @param {string} schemaId - Root schema ID
|
|
179
|
+
* @returns { {extType?: ExtensionType, normalizedExtName?: string} }
|
|
180
|
+
*/
|
|
181
|
+
static extensionInfoFromRootSchemaId (schemaId) {
|
|
182
|
+
const matches = schemaId.match(SCHEMA_ID_REGEXP);
|
|
183
|
+
if (matches?.groups) {
|
|
184
|
+
const {extType, normalizedExtName} =
|
|
185
|
+
/** @type { {extType: ExtensionType, normalizedExtName: string} } */ (
|
|
186
|
+
matches.groups
|
|
187
|
+
);
|
|
188
|
+
return {extType, normalizedExtName};
|
|
189
|
+
}
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Creates an `ArgSpec`
|
|
195
|
+
*
|
|
196
|
+
* @param {string} name - The canonical name of the argument. Corresponds to a key in a schema's
|
|
197
|
+
* `properties` property.
|
|
198
|
+
* @template D
|
|
199
|
+
* @param {ArgSpecOptions<D>} [opts] - Options
|
|
200
|
+
* @returns {Readonly<ArgSpec>}
|
|
201
|
+
*/
|
|
202
|
+
static create (name, opts) {
|
|
203
|
+
return Object.freeze(new ArgSpec(name, opts));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* String representation, useful for debugging
|
|
208
|
+
* @returns {string}
|
|
209
|
+
*/
|
|
210
|
+
/* istanbul ignore next */
|
|
211
|
+
toString () {
|
|
212
|
+
let str = `[ArgSpec] ${this.name} (${this.ref})`;
|
|
213
|
+
if (this.extType && this.extName) {
|
|
214
|
+
str += ` (ext: ${this.extType}/${this.extName})`;
|
|
215
|
+
}
|
|
216
|
+
return str;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Options for {@link ArgSpec.create}
|
|
222
|
+
* @template D
|
|
223
|
+
* @typedef ArgSpecOptions
|
|
224
|
+
* @property {string} [extName]
|
|
225
|
+
* @property {ExtensionType} [extType]
|
|
226
|
+
* @property {string} [dest]
|
|
227
|
+
* @property {D} [defaultValue]
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @typedef {import('../extension/manifest').ExtensionType} ExtensionType
|
|
232
|
+
*/
|