appium 2.0.0-beta.25 → 2.0.0-beta.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/build/lib/appium-config.schema.json +278 -0
  2. package/build/lib/appium.js +45 -66
  3. package/build/lib/cli/args.js +19 -39
  4. package/build/lib/cli/driver-command.js +5 -9
  5. package/build/lib/cli/extension-command.js +73 -64
  6. package/build/lib/cli/extension.js +10 -23
  7. package/build/lib/cli/parser.js +9 -19
  8. package/build/lib/cli/plugin-command.js +5 -9
  9. package/build/lib/cli/utils.js +2 -4
  10. package/build/lib/config-file.js +2 -4
  11. package/build/lib/config.js +7 -6
  12. package/build/lib/constants.js +60 -0
  13. package/build/lib/extension/driver-config.js +190 -0
  14. package/build/lib/extension/extension-config.js +297 -0
  15. package/build/lib/extension/index.js +77 -0
  16. package/build/lib/extension/manifest.js +246 -0
  17. package/build/lib/extension/package-changed.js +68 -0
  18. package/build/lib/extension/plugin-config.js +87 -0
  19. package/build/lib/grid-register.js +2 -4
  20. package/build/lib/logger.js +2 -4
  21. package/build/lib/logsink.js +2 -4
  22. package/build/lib/main.js +40 -68
  23. package/build/lib/schema/appium-config-schema.js +2 -4
  24. package/build/lib/schema/arg-spec.js +11 -14
  25. package/build/lib/schema/cli-args.js +2 -4
  26. package/build/lib/schema/cli-transformers.js +2 -4
  27. package/build/lib/schema/index.js +2 -4
  28. package/build/lib/schema/keywords.js +2 -4
  29. package/build/lib/schema/schema.js +55 -37
  30. package/build/lib/utils.js +1 -32
  31. package/lib/appium.js +50 -68
  32. package/lib/cli/args.js +19 -23
  33. package/lib/cli/driver-command.js +10 -2
  34. package/lib/cli/extension-command.js +216 -135
  35. package/lib/cli/extension.js +7 -15
  36. package/lib/cli/parser.js +6 -14
  37. package/lib/cli/plugin-command.js +1 -2
  38. package/lib/config-file.js +3 -3
  39. package/lib/config.js +5 -4
  40. package/lib/constants.js +79 -0
  41. package/lib/extension/driver-config.js +230 -0
  42. package/lib/extension/extension-config.js +459 -0
  43. package/lib/extension/index.js +103 -0
  44. package/lib/extension/manifest.js +590 -0
  45. package/lib/extension/package-changed.js +64 -0
  46. package/lib/extension/plugin-config.js +111 -0
  47. package/lib/grid-register.js +4 -4
  48. package/lib/main.js +51 -88
  49. package/lib/schema/arg-spec.js +2 -2
  50. package/lib/schema/cli-args.js +1 -0
  51. package/lib/schema/keywords.js +1 -1
  52. package/lib/schema/schema.js +60 -28
  53. package/lib/utils.js +2 -32
  54. package/package.json +29 -21
  55. package/{postinstall.js → scripts/postinstall.js} +1 -1
  56. package/types/types.d.ts +70 -31
  57. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  58. package/build/check-npm-pack-files.js +0 -23
  59. package/build/commands-yml/parse.js +0 -319
  60. package/build/commands-yml/validator.js +0 -130
  61. package/build/index.js +0 -19
  62. package/build/lib/cli/npm.js +0 -220
  63. package/build/lib/driver-config.js +0 -100
  64. package/build/lib/drivers.js +0 -100
  65. package/build/lib/ext-config-io.js +0 -165
  66. package/build/lib/extension-config.js +0 -320
  67. package/build/lib/plugin-config.js +0 -69
  68. package/build/lib/plugins.js +0 -18
  69. package/build/postinstall.js +0 -90
  70. package/build/test/cli/cli-e2e-specs.js +0 -221
  71. package/build/test/cli/cli-helpers.js +0 -86
  72. package/build/test/cli/cli-specs.js +0 -71
  73. package/build/test/cli/fixtures/test-driver/package.json +0 -27
  74. package/build/test/cli/schema-args-specs.js +0 -48
  75. package/build/test/cli/schema-e2e-specs.js +0 -47
  76. package/build/test/config-e2e-specs.js +0 -112
  77. package/build/test/config-file-e2e-specs.js +0 -191
  78. package/build/test/config-file-specs.js +0 -281
  79. package/build/test/config-specs.js +0 -258
  80. package/build/test/driver-e2e-specs.js +0 -435
  81. package/build/test/driver-specs.js +0 -386
  82. package/build/test/ext-config-io-specs.js +0 -181
  83. package/build/test/extension-config-specs.js +0 -365
  84. package/build/test/fixtures/allow-feat.txt +0 -5
  85. package/build/test/fixtures/caps.json +0 -3
  86. package/build/test/fixtures/config/allow-insecure.txt +0 -3
  87. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
  88. package/build/test/fixtures/config/appium.config.bad.json +0 -32
  89. package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
  90. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
  91. package/build/test/fixtures/config/appium.config.good.js +0 -40
  92. package/build/test/fixtures/config/appium.config.good.json +0 -33
  93. package/build/test/fixtures/config/appium.config.good.yaml +0 -30
  94. package/build/test/fixtures/config/appium.config.invalid.json +0 -31
  95. package/build/test/fixtures/config/appium.config.security-array.json +0 -5
  96. package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
  97. package/build/test/fixtures/config/appium.config.security-path.json +0 -5
  98. package/build/test/fixtures/config/driver-fake.config.json +0 -8
  99. package/build/test/fixtures/config/nodeconfig.json +0 -3
  100. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  101. package/build/test/fixtures/default-args.js +0 -35
  102. package/build/test/fixtures/deny-feat.txt +0 -5
  103. package/build/test/fixtures/driver.schema.js +0 -20
  104. package/build/test/fixtures/extensions.yaml +0 -27
  105. package/build/test/fixtures/flattened-schema.js +0 -532
  106. package/build/test/fixtures/plugin.schema.js +0 -20
  107. package/build/test/fixtures/schema-with-extensions.js +0 -28
  108. package/build/test/grid-register-specs.js +0 -74
  109. package/build/test/helpers.js +0 -75
  110. package/build/test/logger-specs.js +0 -76
  111. package/build/test/npm-specs.js +0 -20
  112. package/build/test/parser-specs.js +0 -319
  113. package/build/test/plugin-e2e-specs.js +0 -316
  114. package/build/test/schema/arg-spec-specs.js +0 -70
  115. package/build/test/schema/cli-args-specs.js +0 -408
  116. package/build/test/schema/schema-specs.js +0 -407
  117. package/build/test/utils-specs.js +0 -288
  118. package/lib/cli/npm.js +0 -251
  119. package/lib/driver-config.js +0 -101
  120. package/lib/drivers.js +0 -84
  121. package/lib/ext-config-io.js +0 -287
  122. package/lib/extension-config.js +0 -366
  123. package/lib/plugin-config.js +0 -63
  124. package/lib/plugins.js +0 -13
@@ -181,7 +181,7 @@ export function normalizeConfig (config) {
181
181
 
182
182
  /**
183
183
  * Result of calling {@link readConfigFile}.
184
- * @typedef {Object} ReadConfigFileResult
184
+ * @typedef ReadConfigFileResult
185
185
  * @property {import('ajv').ErrorObject[]} [errors] - Validation errors
186
186
  * @property {string} [filepath] - The path to the config file, if found
187
187
  * @property {boolean} [isEmpty] - If `true`, the config file exists but is empty
@@ -191,7 +191,7 @@ export function normalizeConfig (config) {
191
191
 
192
192
  /**
193
193
  * Options for {@link readConfigFile}.
194
- * @typedef {Object} ReadConfigFileOptions
194
+ * @typedef ReadConfigFileOptions
195
195
  * @property {boolean} [pretty=true] If `false`, do not use color and fancy formatting in the `reason` property of the {@link ReadConfigFileResult}. The value of `reason` is then suitable for machine-reading.
196
196
  */
197
197
 
@@ -217,7 +217,7 @@ export function normalizeConfig (config) {
217
217
 
218
218
  /**
219
219
  * Options for {@link formatErrors}.
220
- * @typedef {Object} FormatConfigErrorsOptions
220
+ * @typedef FormatConfigErrorsOptions
221
221
  * @property {import('./config-file').RawJson} [json] - Raw JSON config (as string)
222
222
  * @property {boolean} [pretty=true] - Whether to format errors as a CLI-friendly string
223
223
  * @property {string} [schemaId] - Specific ID of a prop; otherwise entire schema
package/lib/config.js CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  /* eslint-disable no-console */
4
4
  import _ from 'lodash';
5
- import { mkdirp, system, fs } from '@appium/support';
5
+ import { system, fs } from '@appium/support';
6
6
  import axios from 'axios';
7
7
  import { exec } from 'teen_process';
8
- import { rootDir } from './utils';
9
8
  import logger from './logger';
10
9
  import semver from 'semver';
11
10
  import findUp from 'find-up';
@@ -289,17 +288,19 @@ function showConfig (nonDefaultPreConfigParsedArgs, configResult, defaults, pars
289
288
  */
290
289
  async function validateTmpDir (tmpDir) {
291
290
  try {
292
- await mkdirp(tmpDir);
291
+ await fs.mkdirp(tmpDir);
293
292
  } catch (e) {
294
293
  throw new Error(`We could not ensure that the temp dir you specified ` +
295
294
  `(${tmpDir}) exists. Please make sure it's writeable.`);
296
295
  }
297
296
  }
298
297
 
298
+ const rootDir = fs.findRoot(__dirname);
299
+
299
300
  export {
300
301
  getBuildInfo, checkNodeOk, showBuildInfo,
301
302
  warnNodeDeprecations, validateTmpDir, getNonDefaultServerArgs,
302
- getGitRev, APPIUM_VER, updateBuildInfo, showConfig
303
+ getGitRev, APPIUM_VER, updateBuildInfo, showConfig, rootDir
303
304
  };
304
305
 
305
306
  /**
@@ -0,0 +1,79 @@
1
+ // @ts-check
2
+
3
+ import path from 'path';
4
+
5
+ /**
6
+ * The name of the extension type for drivers
7
+ */
8
+ export const DRIVER_TYPE = 'driver';
9
+
10
+ /**
11
+ * The name of the extension type for plugins
12
+ */
13
+ export const PLUGIN_TYPE = 'plugin';
14
+
15
+ /**
16
+ * The `server` command of the `appium` CLI
17
+ */
18
+ export const SERVER_SUBCOMMAND = 'server';
19
+
20
+ /**
21
+ * The value of `--use-plugins` if _all_ plugins should be loaded
22
+ */
23
+ export const USE_ALL_PLUGINS = 'all';
24
+
25
+ // This is a map of plugin names to npm packages representing those plugins.
26
+ // The plugins in this list will be available to the CLI so users can just
27
+ // type 'appium plugin install 'name'', rather than having to specify the full
28
+ // npm package. I.e., these are the officially recognized plugins.
29
+ export const KNOWN_PLUGINS = Object.freeze(
30
+ /** @type {const} */ ({
31
+ images: '@appium/images-plugin',
32
+ 'execute-driver': '@appium/execute-driver-plugin',
33
+ 'relaxed-caps': '@appium/relaxed-caps-plugin',
34
+ }),
35
+ );
36
+
37
+ // This is a map of driver names to npm packages representing those drivers.
38
+ // The drivers in this list will be available to the CLI so users can just
39
+ // type 'appium driver install 'name'', rather than having to specify the full
40
+ // npm package. I.e., these are the officially recognized drivers.
41
+ export const KNOWN_DRIVERS = Object.freeze(
42
+ /** @type {const} */ ({
43
+ uiautomator2: 'appium-uiautomator2-driver',
44
+ xcuitest: 'appium-xcuitest-driver',
45
+ youiengine: 'appium-youiengine-driver',
46
+ windows: 'appium-windows-driver',
47
+ mac: 'appium-mac-driver',
48
+ mac2: 'appium-mac2-driver',
49
+ espresso: 'appium-espresso-driver',
50
+ tizen: 'appium-tizen-driver',
51
+ flutter: 'appium-flutter-driver',
52
+ safari: 'appium-safari-driver',
53
+ gecko: 'appium-geckodriver',
54
+ }),
55
+ );
56
+
57
+ /**
58
+ * Relative path to directory containing any Appium internal files
59
+ */
60
+ export const CACHE_DIR_RELATIVE_PATH = path.join(
61
+ 'node_modules',
62
+ '.cache',
63
+ 'appium',
64
+ );
65
+
66
+ /**
67
+ * Relative path to hashfile (from `APPIUM_HOME`) of consuming project's `package.json` (if it exists)
68
+ */
69
+ export const PKG_HASHFILE_RELATIVE_PATH = path.join(
70
+ CACHE_DIR_RELATIVE_PATH,
71
+ 'package.hash',
72
+ );
73
+
74
+
75
+ export const EXT_SUBCOMMAND_LIST = 'list';
76
+ export const EXT_SUBCOMMAND_INSTALL = 'install';
77
+ export const EXT_SUBCOMMAND_UNINSTALL = 'uninstall';
78
+ export const EXT_SUBCOMMAND_UPDATE = 'update';
79
+ export const EXT_SUBCOMMAND_RUN = 'run';
@@ -0,0 +1,230 @@
1
+ // @ts-check
2
+
3
+ import _ from 'lodash';
4
+ import { DRIVER_TYPE } from '../constants';
5
+ import log from '../logger';
6
+ import { ExtensionConfig } from './extension-config';
7
+
8
+ /**
9
+ * @extends {ExtensionConfig<DriverType>}
10
+ */
11
+ export class DriverConfig extends ExtensionConfig {
12
+
13
+ /**
14
+ * A set of unique automation names used by drivers.
15
+ * @type {Set<string>}
16
+ */
17
+ knownAutomationNames;
18
+
19
+ /**
20
+ * A mapping of {@link Manifest} instances to {@link DriverConfig} instances.
21
+ *
22
+ * `Manifest` and `ExtensionConfig` have a one-to-many relationship; each `Manifest` should be associated with a `DriverConfig` and a `PluginConfig`; no more, no less.
23
+ *
24
+ * This variable tracks the `Manifest`-to-`DriverConfig` portion.
25
+ *
26
+ * @type {WeakMap<Manifest,DriverConfig>}
27
+ * @private
28
+ */
29
+ static _instances = new WeakMap();
30
+
31
+ /**
32
+ * Call {@link DriverConfig.create} instead.
33
+ * @private
34
+ * @param {import('./manifest').Manifest} manifest - Manifest instance
35
+ * @param {DriverConfigOptions} [opts]
36
+ */
37
+ constructor (manifest, {logFn, extData} = {}) {
38
+ super(DRIVER_TYPE, manifest, logFn);
39
+
40
+ this.knownAutomationNames = new Set();
41
+
42
+ if (extData) {
43
+ this.validate(extData);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Creates a new {@link DriverConfig} instance for a {@link Manifest} instance.
49
+ *
50
+ * @param {Manifest} manifest
51
+ * @param {DriverConfigOptions} [opts]
52
+ * @throws If `manifest` already associated with a `DriverConfig`
53
+ * @returns {DriverConfig}
54
+ */
55
+ static create (manifest, {extData, logFn} = {}) {
56
+ const instance = new DriverConfig(manifest, {logFn, extData});
57
+ if (DriverConfig.getInstance(manifest)) {
58
+ throw new Error(`Manifest with APPIUM_HOME ${manifest.appiumHome} already has a DriverConfig; use DriverConfig.getInstance() to retrieve it.`);
59
+ }
60
+ DriverConfig._instances.set(manifest, instance);
61
+ return instance;
62
+ }
63
+
64
+ /**
65
+ * Returns a DriverConfig associated with a Manifest
66
+ * @param {Manifest} manifest
67
+ * @returns {DriverConfig|undefined}
68
+ */
69
+ static getInstance (manifest) {
70
+ return DriverConfig._instances.get(manifest);
71
+ }
72
+
73
+ /**
74
+ * Checks extensions for problems
75
+ * @param {ExtRecord<DriverType>} exts
76
+ */
77
+ validate (exts) {
78
+ this.knownAutomationNames.clear();
79
+ return super.validate(exts);
80
+ }
81
+
82
+ /**
83
+ * @param {ManifestDriverData} extData
84
+ * @returns {import('./extension-config').Problem[]}
85
+ */
86
+ getConfigProblems (extData) {
87
+ const problems = [];
88
+ const {platformNames, automationName} = extData;
89
+
90
+ if (!_.isArray(platformNames)) {
91
+ problems.push({
92
+ err: 'Missing or incorrect supported platformNames list.',
93
+ val: platformNames
94
+ });
95
+ } else {
96
+ if (_.isEmpty(platformNames)) {
97
+ problems.push({
98
+ err: 'Empty platformNames list.',
99
+ val: platformNames
100
+ });
101
+ } else {
102
+ for (const pName of platformNames) {
103
+ if (!_.isString(pName)) {
104
+ problems.push({err: 'Incorrectly formatted platformName.', val: pName});
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ if (!_.isString(automationName)) {
111
+ problems.push({err: 'Missing or incorrect automationName', val: automationName});
112
+ }
113
+
114
+ if (this.knownAutomationNames.has(automationName)) {
115
+ problems.push({
116
+ err: 'Multiple drivers claim support for the same automationName',
117
+ val: automationName
118
+ });
119
+ }
120
+
121
+ // should we retain the name at the end of this function, once we've checked there are no problems?
122
+ this.knownAutomationNames.add(automationName);
123
+
124
+ return problems;
125
+ }
126
+
127
+ /**
128
+ * @param {ExtName<DriverType>} driverName
129
+ * @param {ManifestDriverData} extData
130
+ * @returns {string}
131
+ */
132
+ extensionDesc (driverName, {version, automationName}) {
133
+ return `${driverName}@${version} (automationName '${automationName}')`;
134
+ }
135
+
136
+ /**
137
+ * Given capabilities, find a matching driver within the config. Load its class and return it along with version and driver name.
138
+ * @param { { automationName: string, platformName: string } } caps
139
+ * @returns { { driver: import('./manifest').DriverClass, version: string, driverName: string } }
140
+ */
141
+ findMatchingDriver ({automationName, platformName}) {
142
+ if (!_.isString(platformName)) {
143
+ throw new Error('You must include a platformName capability');
144
+ }
145
+
146
+ if (!_.isString(automationName)) {
147
+ throw new Error('You must include an automationName capability');
148
+ }
149
+
150
+ log.info(`Attempting to find matching driver for automationName ` +
151
+ `'${automationName}' and platformName '${platformName}'`);
152
+
153
+ try {
154
+ const {
155
+ driverName,
156
+ mainClass,
157
+ version,
158
+ } = this._getDriverBySupport(automationName, platformName);
159
+ log.info(`The '${driverName}' driver was installed and matched caps.`);
160
+ log.info(`Will require it at ${this.getInstallPath(driverName)}`);
161
+ const driver = this.require(driverName);
162
+ if (!driver) {
163
+ throw new Error(`Driver '${driverName}' did not export a class with name '${mainClass}'. Contact the author of the driver!`);
164
+ }
165
+ return {driver, version, driverName};
166
+ } catch (err) {
167
+ const msg = `Could not find a driver for automationName ` +
168
+ `'${automationName}' and platformName ${platformName}'. ` +
169
+ `Have you installed a driver that supports those ` +
170
+ `capabilities? Run 'appium driver list --installed' to see. ` +
171
+ `(Lower-level error: ${err.message})`;
172
+ throw new Error(msg);
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Given an automation name and platform name, find a suitable driver and return its extension data.
178
+ * @param {string} matchAutomationName
179
+ * @param {string} matchPlatformName
180
+ * @returns {ManifestDriverData & { driverName: string } }
181
+ */
182
+ _getDriverBySupport (matchAutomationName, matchPlatformName) {
183
+ const drivers = this.installedExtensions;
184
+ for (const [driverName, driverData] of _.toPairs(drivers)) {
185
+ const {automationName, platformNames} = driverData;
186
+ const aNameMatches = automationName.toLowerCase() === matchAutomationName.toLowerCase();
187
+ const pNameMatches = _.includes(platformNames.map(_.toLower),
188
+ matchPlatformName.toLowerCase());
189
+
190
+ if (aNameMatches && pNameMatches) {
191
+ return {driverName, ...driverData};
192
+ }
193
+
194
+ if (aNameMatches) {
195
+ throw new Error(`Driver '${driverName}' supports automationName ` +
196
+ `'${automationName}', but Appium could not find ` +
197
+ `support for platformName '${matchPlatformName}'. Supported ` +
198
+ `platformNames are: ` +
199
+ JSON.stringify(platformNames));
200
+ }
201
+ }
202
+
203
+ throw new Error(`Could not find installed driver to support given caps`);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * @typedef DriverConfigOptions
209
+ * @property {import('./extension-config').ExtensionLogFn} [logFn] - Optional logging function
210
+ * @property {ManifestData['drivers']} [extData] - Extension data
211
+ */
212
+
213
+ /**
214
+ * @typedef {import('./manifest').ExternalData<DriverType>} ExternalDriverData
215
+ * @typedef {import('./manifest').ManifestDriverData} ManifestDriverData
216
+ * @typedef {import('./manifest').ManifestData} ManifestData
217
+ * @typedef {import('./manifest').DriverType} DriverType
218
+ * @typedef {import('./manifest').Manifest} Manifest
219
+ */
220
+
221
+ /**
222
+ * @template T
223
+ * @typedef {import('./extension-config').ExtRecord<T>} ExtRecord
224
+ */
225
+
226
+ /**
227
+ * @template T
228
+ * @typedef {import('./extension-config').ExtName<T>} ExtName
229
+ */
230
+