appium 2.0.0-beta.3 → 2.0.0-beta.30
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 +238 -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 +79 -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 +40 -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 +51 -0
- package/build/lib/main.d.ts.map +1 -0
- package/build/lib/main.js +174 -82
- 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/index.js +11 -0
- package/lib/appium-config.schema.json +278 -0
- package/lib/appium.js +398 -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 +252 -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 +169 -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 +486 -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 +233 -83
- 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 +62 -85
- package/scripts/postinstall.js +71 -0
- package/types/appium-manifest.d.ts +61 -0
- package/types/cli.d.ts +134 -0
- package/types/extension.d.ts +56 -0
- package/types/external-manifest.d.ts +58 -0
- package/types/index.d.ts +7 -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
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import {ExtensionConfig} from './extension-config';
|
|
4
|
+
import log from '../logger';
|
|
5
|
+
import {PLUGIN_TYPE} from '../constants';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @extends {ExtensionConfig<PluginType>}
|
|
9
|
+
*/
|
|
10
|
+
export class PluginConfig extends ExtensionConfig {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A mapping of {@link Manifest} instances to {@link PluginConfig} instances.
|
|
14
|
+
*
|
|
15
|
+
* `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.
|
|
16
|
+
*
|
|
17
|
+
* This variable tracks the `Manifest`-to-`PluginConfig` portion.
|
|
18
|
+
*
|
|
19
|
+
* @type {WeakMap<Manifest,PluginConfig>}
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
static _instances = new WeakMap();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Call {@link PluginConfig.create} instead.
|
|
26
|
+
*
|
|
27
|
+
* Just calls the superclass' constructor with the correct extension type
|
|
28
|
+
* @private
|
|
29
|
+
* @param {Manifest} manifest - IO object
|
|
30
|
+
* @param {PluginConfigOptions} [opts]
|
|
31
|
+
*/
|
|
32
|
+
constructor (manifest, {extData, logFn} = {}) {
|
|
33
|
+
super(PLUGIN_TYPE, manifest, logFn);
|
|
34
|
+
|
|
35
|
+
if (extData) {
|
|
36
|
+
this.validate(extData);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new {@link PluginConfig} instance for a {@link Manifest} instance.
|
|
42
|
+
*
|
|
43
|
+
* @param {Manifest} manifest
|
|
44
|
+
* @param {PluginConfigOptions} [opts]
|
|
45
|
+
* @throws If `manifest` already associated with a `PluginConfig`
|
|
46
|
+
* @returns {PluginConfig}
|
|
47
|
+
*/
|
|
48
|
+
static create (manifest, {extData, logFn} = {}) {
|
|
49
|
+
const instance = new PluginConfig(manifest, {logFn, extData});
|
|
50
|
+
if (PluginConfig.getInstance(manifest)) {
|
|
51
|
+
throw new Error(`Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it.`);
|
|
52
|
+
}
|
|
53
|
+
PluginConfig._instances.set(manifest, instance);
|
|
54
|
+
return instance;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns a PluginConfig associated with a Manifest
|
|
59
|
+
* @param {Manifest} manifest
|
|
60
|
+
* @returns {PluginConfig|undefined}
|
|
61
|
+
*/
|
|
62
|
+
static getInstance (manifest) {
|
|
63
|
+
return PluginConfig._instances.get(manifest);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} pluginName
|
|
68
|
+
* @param {import('../../types/appium-manifest').ExtManifest<PluginType>} pluginData
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
extensionDesc (pluginName, {version}) {
|
|
72
|
+
return `${pluginName}@${version}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* @param {(keyof PluginRecord)[]} 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('../../types/appium-manifest').PluginRecord} [extData] - Extension data
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @typedef {import('../../types/appium-manifest').PluginRecord} PluginRecord
|
|
110
|
+
* @typedef {import('../../types').PluginType} PluginType
|
|
111
|
+
* @typedef {import('../../types/external-manifest').ExtMetadata<PluginType>} PluginMetadata
|
|
112
|
+
* @typedef {import('./manifest').Manifest} Manifest
|
|
113
|
+
*/
|
package/lib/grid-register.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { fs } from 'appium
|
|
2
|
+
import { fs } from '@appium/support';
|
|
3
3
|
import logger from './logger';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
|
|
@@ -9,20 +9,31 @@ const hubUri = (config) => {
|
|
|
9
9
|
return `${protocol}://${config.hubHost}:${config.hubPort}`;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Registers a new node with a selenium 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
|
+
*/
|
|
19
|
+
async function registerNode (data, addr, port, basePath) {
|
|
20
|
+
let configFilePath;
|
|
21
|
+
if (_.isString(data)) {
|
|
22
|
+
configFilePath = data;
|
|
23
|
+
try {
|
|
24
|
+
data = await fs.readFile(data, 'utf-8');
|
|
25
|
+
} catch (err) {
|
|
26
|
+
logger.error(`Unable to load node configuration file ${configFilePath} to register with grid: ${err.message}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
data = JSON.parse(data);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
logger.errorAndThrow(`Syntax error in node configuration file ${configFilePath}: ${err.message}`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
19
35
|
}
|
|
20
36
|
|
|
21
|
-
// Check presence of data before posting it to the selenium grid
|
|
22
|
-
if (!data) {
|
|
23
|
-
logger.error('No data found in the node configuration file to send to the grid');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
37
|
postRequest(data, addr, port, basePath);
|
|
27
38
|
}
|
|
28
39
|
|
|
@@ -39,15 +50,7 @@ async function registerToGrid (postOptions, configHolder) {
|
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
function postRequest (
|
|
43
|
-
// parse json to get hub host and port
|
|
44
|
-
let configHolder;
|
|
45
|
-
try {
|
|
46
|
-
configHolder = JSON.parse(data);
|
|
47
|
-
} catch (err) {
|
|
48
|
-
logger.errorAndThrow(`Syntax error in node configuration file: ${err.message}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
53
|
+
function postRequest (configHolder, addr, port, basePath) {
|
|
51
54
|
// Move Selenium 3 configuration properties to configuration object
|
|
52
55
|
if (!_.has(configHolder, 'configuration')) {
|
|
53
56
|
let configuration = {};
|
package/lib/logger.js
CHANGED
package/lib/logsink.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import npmlog from 'npmlog';
|
|
2
2
|
import { createLogger, format, transports } from 'winston';
|
|
3
|
-
import { fs, logger } from 'appium
|
|
4
|
-
import dateformat from 'dateformat';
|
|
3
|
+
import { fs, logger } from '@appium/support';
|
|
5
4
|
import _ from 'lodash';
|
|
6
5
|
|
|
7
6
|
|
|
@@ -36,16 +35,20 @@ const npmToWinstonLevels = {
|
|
|
36
35
|
};
|
|
37
36
|
|
|
38
37
|
let log = null;
|
|
39
|
-
let
|
|
38
|
+
let useLocalTimeZone = false;
|
|
40
39
|
|
|
41
40
|
// add the timestamp in the correct format to the log info object
|
|
42
41
|
const timestampFormat = format.timestamp({
|
|
43
42
|
format () {
|
|
44
43
|
let date = new Date();
|
|
45
|
-
if (
|
|
46
|
-
date = new Date(date.valueOf()
|
|
44
|
+
if (useLocalTimeZone) {
|
|
45
|
+
date = new Date(date.valueOf() - date.getTimezoneOffset() * 60000);
|
|
47
46
|
}
|
|
48
|
-
|
|
47
|
+
// '2012-11-04T14:51:06.157Z' -> '2012-11-04 14:51:06:157'
|
|
48
|
+
return date.toISOString()
|
|
49
|
+
.replace(/[TZ]/g, ' ')
|
|
50
|
+
.replace(/\./g, ':')
|
|
51
|
+
.trim();
|
|
49
52
|
},
|
|
50
53
|
});
|
|
51
54
|
|
|
@@ -63,6 +66,8 @@ const stripColorFormat = format(function stripColor (info) {
|
|
|
63
66
|
|
|
64
67
|
function createConsoleTransport (args, logLvl) {
|
|
65
68
|
return new (transports.Console)({
|
|
69
|
+
// `name` is unsupported per winston's type declarations
|
|
70
|
+
// @ts-expect-error
|
|
66
71
|
name: 'console',
|
|
67
72
|
handleExceptions: true,
|
|
68
73
|
exitOnError: false,
|
|
@@ -89,6 +94,7 @@ function createConsoleTransport (args, logLvl) {
|
|
|
89
94
|
|
|
90
95
|
function createFileTransport (args, logLvl) {
|
|
91
96
|
return new (transports.File)({
|
|
97
|
+
// @ts-expect-error
|
|
92
98
|
name: 'file',
|
|
93
99
|
filename: args.logFile,
|
|
94
100
|
maxFiles: 1,
|
|
@@ -117,6 +123,7 @@ function createHttpTransport (args, logLvl) {
|
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
return new (transports.Http)({
|
|
126
|
+
// @ts-expect-error
|
|
120
127
|
name: 'http',
|
|
121
128
|
host,
|
|
122
129
|
port,
|
|
@@ -182,7 +189,7 @@ async function createTransports (args) {
|
|
|
182
189
|
|
|
183
190
|
async function init (args) {
|
|
184
191
|
// set de facto param passed to timestamp function
|
|
185
|
-
|
|
192
|
+
useLocalTimeZone = args.localTimezone;
|
|
186
193
|
|
|
187
194
|
// clean up in case we have initiated before since npmlog is a global object
|
|
188
195
|
clear();
|
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,24 @@ async function preflightChecks ({parser, args, driverConfig, pluginConfig, throw
|
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @param {Partial<ParsedArgs>} args
|
|
58
|
+
*/
|
|
53
59
|
function logNonDefaultArgsWarning (args) {
|
|
54
60
|
logger.info('Non-default server args:');
|
|
55
|
-
|
|
61
|
+
inspect(args);
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
function logDefaultCapabilitiesWarning (caps) {
|
|
59
65
|
logger.info('Default capabilities, which will be added to each request ' +
|
|
60
66
|
'unless overridden by desired capabilities:');
|
|
61
|
-
|
|
67
|
+
inspect(caps);
|
|
62
68
|
}
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
/**
|
|
71
|
+
* @param {ParsedArgs} args
|
|
72
|
+
*/
|
|
73
|
+
async function logStartupInfo (args) {
|
|
65
74
|
let welcome = `Welcome to Appium v${APPIUM_VER}`;
|
|
66
75
|
let appiumRev = await getGitRev();
|
|
67
76
|
if (appiumRev) {
|
|
@@ -69,7 +78,7 @@ async function logStartupInfo (parser, args) {
|
|
|
69
78
|
}
|
|
70
79
|
logger.info(welcome);
|
|
71
80
|
|
|
72
|
-
let showArgs =
|
|
81
|
+
let showArgs = getNonDefaultServerArgs(args);
|
|
73
82
|
if (_.size(showArgs)) {
|
|
74
83
|
logNonDefaultArgsWarning(showArgs);
|
|
75
84
|
}
|
|
@@ -83,20 +92,74 @@ async function logStartupInfo (parser, args) {
|
|
|
83
92
|
// }
|
|
84
93
|
}
|
|
85
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Logs the address and port the server is listening on
|
|
97
|
+
* @param {string} address - Address
|
|
98
|
+
* @param {number} port - Port
|
|
99
|
+
* @returns {void}
|
|
100
|
+
*/
|
|
86
101
|
function logServerPort (address, port) {
|
|
87
102
|
let logMessage = `Appium REST http interface listener started on ` +
|
|
88
103
|
`${address}:${port}`;
|
|
89
104
|
logger.info(logMessage);
|
|
90
105
|
}
|
|
91
106
|
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Gets a list of `updateServer` functions from all extensions
|
|
109
|
+
* @param {DriverClass[]} driverClasses
|
|
110
|
+
* @param {PluginClass[]} pluginClasses
|
|
111
|
+
* @returns {import('@appium/base-driver/lib/basedriver/driver').UpdateServerCallback[]}
|
|
112
|
+
*/
|
|
113
|
+
function getServerUpdaters (driverClasses, pluginClasses) {
|
|
114
|
+
return _.compact(_.map([...driverClasses, ...pluginClasses], 'updateServer'));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Makes a big `MethodMap` from all the little `MethodMap`s in the extensions
|
|
119
|
+
* @param {DriverClass[]} driverClasses
|
|
120
|
+
* @param {PluginClass[]} pluginClasses
|
|
121
|
+
* @returns {import('@appium/types').MethodMap}
|
|
122
|
+
*/
|
|
123
|
+
function getExtraMethodMap (driverClasses, pluginClasses) {
|
|
124
|
+
return [...driverClasses, ...pluginClasses].reduce(
|
|
125
|
+
(map, klass) => ({...map, ...klass.newMethodMap}),
|
|
126
|
+
{}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Initializes Appium, but does not start the server.
|
|
132
|
+
*
|
|
133
|
+
* Use this to get at the configuration schema.
|
|
134
|
+
*
|
|
135
|
+
* If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
|
|
136
|
+
*
|
|
137
|
+
* @param {PartialArgs} [args] - Partial args (progammatic usage only)
|
|
138
|
+
* @returns {Promise<ServerInitResult | ExtCommandInitResult>}
|
|
139
|
+
* @example
|
|
140
|
+
* import {init, getSchema} from 'appium';
|
|
141
|
+
* const options = {}; // config object
|
|
142
|
+
* await init(options);
|
|
143
|
+
* const schema = getSchema(); // entire config schema including plugins and drivers
|
|
144
|
+
*/
|
|
145
|
+
async function init (args) {
|
|
146
|
+
const appiumHome = args?.appiumHome ?? await resolveAppiumHome();
|
|
147
|
+
|
|
148
|
+
const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);
|
|
149
|
+
|
|
150
|
+
const parser = getParser();
|
|
94
151
|
let throwInsteadOfExit = false;
|
|
152
|
+
/** @type {ParsedArgs} */
|
|
153
|
+
let preConfigParsedArgs;
|
|
154
|
+
/** @type {ParsedArgs} */
|
|
155
|
+
let parsedArgs;
|
|
156
|
+
/**
|
|
157
|
+
* This is a definition (instead of declaration) because TS can't figure out
|
|
158
|
+
* the value will be defined when it's used.
|
|
159
|
+
* @type {ReturnType<getDefaultsForSchema>}
|
|
160
|
+
*/
|
|
161
|
+
let defaults = {};
|
|
95
162
|
if (args) {
|
|
96
|
-
// a containing package passed in their own args, let's fill them out
|
|
97
|
-
// with defaults
|
|
98
|
-
args = Object.assign({}, getDefaultServerArgs(), args);
|
|
99
|
-
|
|
100
163
|
// if we have a containing package instead of running as a CLI process,
|
|
101
164
|
// that package might not appreciate us calling 'process.exit' willy-
|
|
102
165
|
// nilly, so give it the option to have us throw instead of exit
|
|
@@ -105,80 +168,134 @@ async function main (args = null) {
|
|
|
105
168
|
// but remove it since it's not a real server arg per se
|
|
106
169
|
delete args.throwInsteadOfExit;
|
|
107
170
|
}
|
|
171
|
+
preConfigParsedArgs = /** @type {ParsedArgs} */({...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND});
|
|
108
172
|
} else {
|
|
109
173
|
// otherwise parse from CLI
|
|
110
|
-
|
|
174
|
+
preConfigParsedArgs = parser.parseArgs();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const configResult = await readConfigFile(preConfigParsedArgs.configFile);
|
|
178
|
+
|
|
179
|
+
if (!_.isEmpty(configResult.errors)) {
|
|
180
|
+
throw new Error(`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`);
|
|
111
181
|
}
|
|
112
|
-
|
|
182
|
+
|
|
183
|
+
// merge config and apply defaults.
|
|
184
|
+
// the order of precendece is:
|
|
185
|
+
// 1. command line args
|
|
186
|
+
// 2. config file
|
|
187
|
+
// 3. defaults from config file.
|
|
188
|
+
if (preConfigParsedArgs.subcommand === SERVER_SUBCOMMAND) {
|
|
189
|
+
defaults = getDefaultsForSchema(false);
|
|
190
|
+
|
|
191
|
+
parsedArgs = _.defaultsDeep(
|
|
192
|
+
preConfigParsedArgs,
|
|
193
|
+
configResult.config?.server,
|
|
194
|
+
defaults
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (preConfigParsedArgs.showConfig) {
|
|
198
|
+
showConfig(getNonDefaultServerArgs(preConfigParsedArgs), configResult, defaults, parsedArgs);
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
} else {
|
|
203
|
+
parsedArgs = preConfigParsedArgs;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
await logsinkInit(parsedArgs);
|
|
113
207
|
|
|
114
208
|
// if the user has requested the 'driver' CLI, don't run the normal server,
|
|
115
209
|
// but instead pass control to the driver CLI
|
|
116
|
-
if (
|
|
117
|
-
await runExtensionCommand(
|
|
118
|
-
|
|
210
|
+
if (parsedArgs.subcommand === DRIVER_TYPE) {
|
|
211
|
+
await runExtensionCommand(parsedArgs, driverConfig);
|
|
212
|
+
return {};
|
|
213
|
+
}
|
|
214
|
+
if (parsedArgs.subcommand === PLUGIN_TYPE) {
|
|
215
|
+
await runExtensionCommand(parsedArgs, pluginConfig);
|
|
216
|
+
return {};
|
|
119
217
|
}
|
|
120
218
|
|
|
121
|
-
if (
|
|
122
|
-
const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(
|
|
219
|
+
if (parsedArgs.logFilters) {
|
|
220
|
+
const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(parsedArgs.logFilters);
|
|
123
221
|
if (!_.isEmpty(issues)) {
|
|
124
|
-
throw new Error(`The log filtering rules config '${
|
|
222
|
+
throw new Error(`The log filtering rules config '${parsedArgs.logFilters}' has issues: ` +
|
|
125
223
|
JSON.stringify(issues, null, 2));
|
|
126
224
|
}
|
|
127
225
|
if (_.isEmpty(rules)) {
|
|
128
|
-
logger.warn(`Found no log filtering rules in '${
|
|
226
|
+
logger.warn(`Found no log filtering rules in '${parsedArgs.logFilters}'. Is that expected?`);
|
|
129
227
|
} else {
|
|
130
|
-
logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${
|
|
228
|
+
logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${parsedArgs.logFilters}'`);
|
|
131
229
|
}
|
|
132
230
|
}
|
|
133
231
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const pluginConfig = new PluginConfig(args.appiumHome);
|
|
232
|
+
const appiumDriver = new AppiumDriver(parsedArgs);
|
|
233
|
+
// set the config on the umbrella driver so it can match drivers to caps
|
|
137
234
|
appiumDriver.driverConfig = driverConfig;
|
|
138
|
-
await preflightChecks(
|
|
139
|
-
|
|
235
|
+
await preflightChecks(parsedArgs, throwInsteadOfExit);
|
|
236
|
+
|
|
237
|
+
return /** @type {ServerInitResult} */({appiumDriver, parsedArgs, driverConfig, pluginConfig});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Initializes Appium's config. Starts server if appropriate and resolves the
|
|
242
|
+
* server instance if so; otherwise resolves w/ `undefined`.
|
|
243
|
+
* @param {PartialArgs} [args] - Arguments from CLI or otherwise
|
|
244
|
+
* @returns {Promise<import('http').Server|undefined>}
|
|
245
|
+
*/
|
|
246
|
+
async function main (args) {
|
|
247
|
+
const {appiumDriver, parsedArgs, pluginConfig, driverConfig} = /** @type {ServerInitResult} */(await init(args));
|
|
248
|
+
|
|
249
|
+
if (!appiumDriver || !parsedArgs || !pluginConfig || !driverConfig) {
|
|
250
|
+
// if this branch is taken, we've run a different subcommand, so there's nothing
|
|
251
|
+
// left to do here.
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
|
|
256
|
+
// set the active plugins on the umbrella driver so it can use them for commands
|
|
257
|
+
appiumDriver.pluginClasses = pluginClasses;
|
|
258
|
+
|
|
259
|
+
await logStartupInfo(parsedArgs);
|
|
140
260
|
let routeConfiguringFunction = makeRouter(appiumDriver);
|
|
141
261
|
|
|
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;
|
|
262
|
+
const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
|
|
263
|
+
const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
|
|
264
|
+
const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
|
|
160
265
|
|
|
161
|
-
|
|
266
|
+
const serverOpts = {
|
|
162
267
|
routeConfiguringFunction,
|
|
163
|
-
port:
|
|
164
|
-
hostname:
|
|
165
|
-
allowCors:
|
|
166
|
-
basePath:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
268
|
+
port: parsedArgs.port,
|
|
269
|
+
hostname: parsedArgs.address,
|
|
270
|
+
allowCors: parsedArgs.allowCors,
|
|
271
|
+
basePath: parsedArgs.basePath,
|
|
272
|
+
serverUpdaters,
|
|
273
|
+
extraMethodMap,
|
|
274
|
+
};
|
|
275
|
+
if (parsedArgs.keepAliveTimeout) {
|
|
276
|
+
serverOpts.keepAliveTimeout = parsedArgs.keepAliveTimeout * 1000;
|
|
277
|
+
}
|
|
278
|
+
let server;
|
|
279
|
+
try {
|
|
280
|
+
server = await baseServer(serverOpts);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
logger.error(`Could not configure Appium server. It's possible that a driver or plugin tried ` +
|
|
283
|
+
`to update the server and failed. Original error: ${err.message}`);
|
|
284
|
+
logger.debug(err.stack);
|
|
285
|
+
return process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (parsedArgs.allowCors) {
|
|
170
289
|
logger.warn('You have enabled CORS requests from any host. Be careful not ' +
|
|
171
290
|
'to visit sites which could maliciously try to start Appium ' +
|
|
172
291
|
'sessions on your machine');
|
|
173
292
|
}
|
|
174
293
|
appiumDriver.server = server;
|
|
175
294
|
try {
|
|
176
|
-
// TODO prelaunch if args.launch is set
|
|
177
|
-
// TODO: startAlertSocket(server, appiumServer);
|
|
178
|
-
|
|
179
295
|
// configure as node on grid, if necessary
|
|
180
|
-
|
|
181
|
-
|
|
296
|
+
// falsy values should not cause this to run
|
|
297
|
+
if (parsedArgs.nodeconfig) {
|
|
298
|
+
await registerNode(parsedArgs.nodeconfig, parsedArgs.address, parsedArgs.port, parsedArgs.basePath);
|
|
182
299
|
}
|
|
183
300
|
} catch (err) {
|
|
184
301
|
await server.close();
|
|
@@ -202,15 +319,48 @@ async function main (args = null) {
|
|
|
202
319
|
});
|
|
203
320
|
}
|
|
204
321
|
|
|
205
|
-
logServerPort(
|
|
322
|
+
logServerPort(parsedArgs.address, parsedArgs.port);
|
|
206
323
|
driverConfig.print();
|
|
207
|
-
pluginConfig.print(
|
|
324
|
+
pluginConfig.print(pluginClasses.map((p) => p.pluginName));
|
|
208
325
|
|
|
209
326
|
return server;
|
|
210
327
|
}
|
|
211
328
|
|
|
329
|
+
// NOTE: this is here for backwards compat for any scripts referencing `main.js` directly
|
|
330
|
+
// (more specifically, `build/lib/main.js`)
|
|
331
|
+
// the executable is now `../index.js`, so that module will typically be `require.main`.
|
|
212
332
|
if (require.main === module) {
|
|
213
333
|
asyncify(main);
|
|
214
334
|
}
|
|
215
335
|
|
|
216
|
-
|
|
336
|
+
// everything below here is intended to be a public API.
|
|
337
|
+
export { readConfigFile } from './config-file';
|
|
338
|
+
export { finalizeSchema, getSchema, validate } from './schema/schema';
|
|
339
|
+
export { main, init, resolveAppiumHome };
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @typedef {import('../types/cli').ParsedArgs} ParsedArgs
|
|
343
|
+
*/
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* @typedef {import('../types/cli').PartialArgs} PartialArgs
|
|
347
|
+
* @typedef {import('../types').DriverType} DriverType
|
|
348
|
+
* @typedef {import('../types').PluginType} PluginType
|
|
349
|
+
* @typedef {import('../types/extension').DriverClass} DriverClass
|
|
350
|
+
* @typedef {import('../types/extension').PluginClass} PluginClass
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Literally an empty object
|
|
355
|
+
* @typedef { {} } ExtCommandInitResult
|
|
356
|
+
*/
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* @typedef ServerInitData
|
|
360
|
+
* @property {AppiumDriver} appiumDriver - The Appium driver
|
|
361
|
+
* @property {ParsedArgs} parsedArgs - The parsed arguments
|
|
362
|
+
*/
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @typedef {ServerInitData & import('./extension').ExtensionConfigs} ServerInitResult
|
|
366
|
+
*/
|