appium 2.0.0-beta.44 → 2.0.0-beta.46

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 (72) hide show
  1. package/build/lib/appium.d.ts +137 -14
  2. package/build/lib/appium.d.ts.map +1 -1
  3. package/build/lib/appium.js +5 -5
  4. package/build/lib/appium.js.map +1 -0
  5. package/build/lib/cli/args.js +3 -3
  6. package/build/lib/cli/args.js.map +1 -0
  7. package/build/lib/cli/driver-command.js +3 -3
  8. package/build/lib/cli/driver-command.js.map +1 -0
  9. package/build/lib/cli/extension-command.js +3 -3
  10. package/build/lib/cli/extension-command.js.map +1 -0
  11. package/build/lib/cli/extension.d.ts +2 -2
  12. package/build/lib/cli/extension.d.ts.map +1 -1
  13. package/build/lib/cli/extension.js +3 -3
  14. package/build/lib/cli/extension.js.map +1 -0
  15. package/build/lib/cli/parser.js +3 -3
  16. package/build/lib/cli/parser.js.map +1 -0
  17. package/build/lib/cli/plugin-command.js +3 -3
  18. package/build/lib/cli/plugin-command.js.map +1 -0
  19. package/build/lib/cli/utils.js +3 -3
  20. package/build/lib/cli/utils.js.map +1 -0
  21. package/build/lib/config-file.js +3 -3
  22. package/build/lib/config-file.js.map +1 -0
  23. package/build/lib/config.js +3 -3
  24. package/build/lib/config.js.map +1 -0
  25. package/build/lib/constants.js +3 -3
  26. package/build/lib/constants.js.map +1 -0
  27. package/build/lib/extension/driver-config.d.ts +3 -2
  28. package/build/lib/extension/driver-config.d.ts.map +1 -1
  29. package/build/lib/extension/driver-config.js +3 -3
  30. package/build/lib/extension/driver-config.js.map +1 -0
  31. package/build/lib/extension/extension-config.js +3 -3
  32. package/build/lib/extension/extension-config.js.map +1 -0
  33. package/build/lib/extension/index.js +3 -3
  34. package/build/lib/extension/index.js.map +1 -0
  35. package/build/lib/extension/manifest.d.ts +1 -2
  36. package/build/lib/extension/manifest.d.ts.map +1 -1
  37. package/build/lib/extension/manifest.js +35 -30
  38. package/build/lib/extension/manifest.js.map +1 -0
  39. package/build/lib/extension/package-changed.js +3 -3
  40. package/build/lib/extension/package-changed.js.map +1 -0
  41. package/build/lib/extension/plugin-config.js +3 -3
  42. package/build/lib/extension/plugin-config.js.map +1 -0
  43. package/build/lib/grid-register.js +3 -3
  44. package/build/lib/grid-register.js.map +1 -0
  45. package/build/lib/logger.js.map +1 -0
  46. package/build/lib/logsink.js +3 -3
  47. package/build/lib/logsink.js.map +1 -0
  48. package/build/lib/main.js +3 -3
  49. package/build/lib/main.js.map +1 -0
  50. package/build/lib/schema/arg-spec.js +3 -3
  51. package/build/lib/schema/arg-spec.js.map +1 -0
  52. package/build/lib/schema/cli-args.js +3 -3
  53. package/build/lib/schema/cli-args.js.map +1 -0
  54. package/build/lib/schema/cli-transformers.d.ts +1 -1
  55. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  56. package/build/lib/schema/cli-transformers.js +23 -18
  57. package/build/lib/schema/cli-transformers.js.map +1 -0
  58. package/build/lib/schema/index.js.map +1 -0
  59. package/build/lib/schema/keywords.js.map +1 -0
  60. package/build/lib/schema/schema.js +3 -3
  61. package/build/lib/schema/schema.js.map +1 -0
  62. package/build/lib/utils.d.ts +288 -27
  63. package/build/lib/utils.d.ts.map +1 -1
  64. package/build/lib/utils.js +7 -35
  65. package/build/lib/utils.js.map +1 -0
  66. package/build/tsconfig.tsbuildinfo +1 -1
  67. package/lib/appium.js +27 -18
  68. package/lib/extension/driver-config.js +2 -1
  69. package/lib/extension/manifest.js +49 -32
  70. package/lib/schema/cli-transformers.js +27 -24
  71. package/lib/utils.js +87 -66
  72. package/package.json +16 -15
package/lib/appium.js CHANGED
@@ -14,13 +14,9 @@ import AsyncLock from 'async-lock';
14
14
  import {parseCapsForInnerDriver, pullSettings} from './utils';
15
15
  import {util, node, logger} from '@appium/support';
16
16
  import {getDefaultsForExtension} from './schema';
17
- import {DRIVER_TYPE, PLUGIN_TYPE} from './constants';
17
+ import {DRIVER_TYPE} from './constants';
18
18
 
19
- /**
20
- * Invariant set of base constraints
21
- * @type {Readonly<Constraints>}
22
- */
23
- const desiredCapabilityConstraints = Object.freeze({
19
+ const desiredCapabilityConstraints = /** @type {const} */ ({
24
20
  automationName: {
25
21
  presence: true,
26
22
  isString: true,
@@ -30,6 +26,9 @@ const desiredCapabilityConstraints = Object.freeze({
30
26
  isString: true,
31
27
  },
32
28
  });
29
+ /**
30
+ * @typedef {typeof desiredCapabilityConstraints} AppiumDriverConstraints
31
+ */
33
32
 
34
33
  const sessionsListGuard = new AsyncLock();
35
34
  const pendingDriversGuard = new AsyncLock();
@@ -181,10 +180,10 @@ class AppiumDriver extends DriverCore {
181
180
  /**
182
181
  * Retrieves all CLI arguments for a specific plugin.
183
182
  * @param {string} extName - Plugin name
184
- * @returns {Record<string,unknown>} Arguments object. If none, an empty object.
183
+ * @returns {StringRecord} Arguments object. If none, an empty object.
185
184
  */
186
185
  getCliArgsForPlugin(extName) {
187
- return /** @type {Record<string,unknown>} */ (this.args.plugin?.[extName] ?? {});
186
+ return /** @type {StringRecord} */ (this.args.plugin?.[extName] ?? {});
188
187
  }
189
188
 
190
189
  /**
@@ -194,12 +193,10 @@ class AppiumDriver extends DriverCore {
194
193
  *
195
194
  * _Note that this behavior currently (May 18 2022) differs from how plugins are handled_ (see {@linkcode AppiumDriver.getCliArgsForPlugin}).
196
195
  * @param {string} extName - Driver name
197
- * @returns {Record<string,unknown>|undefined} Arguments object. If none, `undefined`
196
+ * @returns {StringRecord|undefined} Arguments object. If none, `undefined`
198
197
  */
199
198
  getCliArgsForDriver(extName) {
200
- const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */ (
201
- this.args.driver?.[extName]
202
- );
199
+ const allCliArgsForExt = /** @type {StringRecord|undefined} */ (this.args.driver?.[extName]);
203
200
 
204
201
  if (!_.isEmpty(allCliArgsForExt)) {
205
202
  const defaults = getDefaultsForExtension(DRIVER_TYPE, extName);
@@ -214,9 +211,9 @@ class AppiumDriver extends DriverCore {
214
211
 
215
212
  /**
216
213
  * Create a new session
217
- * @param {W3CCapabilities} jsonwpCaps JSONWP formatted desired capabilities
218
- * @param {W3CCapabilities} reqCaps Required capabilities (JSONWP standard)
219
- * @param {W3CCapabilities} w3cCapabilities W3C capabilities
214
+ * @param {W3CCapabilities<AppiumDriverConstraints>} jsonwpCaps JSONWP formatted desired capabilities
215
+ * @param {W3CCapabilities<AppiumDriverConstraints>} reqCaps Required capabilities (JSONWP standard)
216
+ * @param {W3CCapabilities<AppiumDriverConstraints>} w3cCapabilities W3C capabilities
220
217
  * @param {DriverData[]} [driverData]
221
218
  */
222
219
  async createSession(jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
@@ -249,9 +246,11 @@ class AppiumDriver extends DriverCore {
249
246
  );
250
247
 
251
248
  const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} =
252
- /** @type {import('./utils').ParsedDriverCaps} */ (parsedCaps);
249
+ /** @type {import('./utils').ParsedDriverCaps<AppiumDriverConstraints>} */ (parsedCaps);
253
250
  protocol = parsedCaps.protocol;
254
- const error = /** @type {import('./utils').InvalidCaps} */ (parsedCaps).error;
251
+ const error = /** @type {import('./utils').InvalidCaps<AppiumDriverConstraints>} */ (
252
+ parsedCaps
253
+ ).error;
255
254
  // If the parsing of the caps produced an error, throw it in here
256
255
  if (error) {
257
256
  throw error;
@@ -831,7 +830,6 @@ export {AppiumDriver};
831
830
  * @typedef {import('@appium/types').ExternalDriver} ExternalDriver
832
831
  * @typedef {import('@appium/types').Driver} Driver
833
832
  * @typedef {import('@appium/types').DriverClass} DriverClass
834
- * @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
835
833
  * @typedef {import('@appium/types').DriverData} DriverData
836
834
  * @typedef {import('@appium/types').ServerArgs} DriverOpts
837
835
  * @typedef {import('@appium/types').Constraints} Constraints
@@ -842,6 +840,7 @@ export {AppiumDriver};
842
840
  * @typedef {import('@appium/types').PluginClass} PluginClass
843
841
  * @typedef {import('@appium/types').PluginType} PluginType
844
842
  * @typedef {import('@appium/types').DriverType} DriverType
843
+ * @typedef {import('@appium/types').StringRecord} StringRecord
845
844
  * @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
846
845
  */
847
846
 
@@ -854,3 +853,13 @@ export {AppiumDriver};
854
853
  * @property {Error} [error]
855
854
  * @property {string} [protocol]
856
855
  */
856
+
857
+ /**
858
+ * @template {Constraints} C
859
+ * @typedef {import('@appium/types').W3CCapabilities<C>} W3CCapabilities
860
+ */
861
+
862
+ /**
863
+ * @template {Constraints} C
864
+ * @typedef {import('@appium/types').Capabilities<C>} Capabilities
865
+ */
@@ -133,7 +133,8 @@ export class DriverConfig extends ExtensionConfig {
133
133
 
134
134
  /**
135
135
  * Given capabilities, find a matching driver within the config. Load its class and return it along with version and driver name.
136
- * @param {Capabilities} caps
136
+ * @template {import('@appium/types').StringRecord} C
137
+ * @param {C} caps
137
138
  * @returns {MatchedDriver}
138
139
  */
139
140
  findMatchingDriver({automationName, platformName}) {
@@ -2,6 +2,8 @@
2
2
  * Module containing {@link Manifest} which handles reading & writing of extension config files.
3
3
  */
4
4
 
5
+ import B from 'bluebird';
6
+ import glob from 'glob';
5
7
  import {env, fs} from '@appium/support';
6
8
  import _ from 'lodash';
7
9
  import path from 'path';
@@ -11,23 +13,6 @@ import log from '../logger';
11
13
  import {INSTALL_TYPE_NPM} from './extension-config';
12
14
  import {packageDidChange} from './package-changed';
13
15
 
14
- /**
15
- * Default depth to search in directory tree for whatever it is we're looking for.
16
- *
17
- * It's 4 because smaller numbers didn't work.
18
- */
19
- const DEFAULT_SEARCH_DEPTH = 4;
20
-
21
- /**
22
- * Default options for {@link findExtensions}.
23
- * @type {Readonly<import('klaw').Options>}
24
- */
25
- const DEFAULT_FIND_EXTENSIONS_OPTS = Object.freeze({
26
- depthLimit: DEFAULT_SEARCH_DEPTH,
27
- /* istanbul ignore next */
28
- filter: (filepath) => !path.basename(filepath).startsWith('.'),
29
- });
30
-
31
16
  /**
32
17
  * Current configuration schema revision!
33
18
  */
@@ -175,26 +160,58 @@ export class Manifest {
175
160
 
176
161
  /**
177
162
  * Searches `APPIUM_HOME` for installed extensions and adds them to the manifest.
178
- * @param {SyncWithInstalledExtensionsOpts} opts
179
163
  * @returns {Promise<boolean>} `true` if any extensions were added, `false` otherwise.
180
164
  */
181
- async syncWithInstalledExtensions({depthLimit = DEFAULT_SEARCH_DEPTH} = {}) {
182
- const walkOpts = _.defaults({depthLimit}, DEFAULT_FIND_EXTENSIONS_OPTS);
165
+ async syncWithInstalledExtensions() {
183
166
  // this could be parallelized, but we can't use fs.walk as an async iterator
184
167
  let didChange = false;
185
- for await (const {stats, path: filepath} of fs.walk(this._appiumHome, walkOpts)) {
186
- if (filepath !== this._appiumHome && stats.isDirectory()) {
187
- try {
188
- const pkg = await env.readPackageInDir(filepath);
189
- if (pkg && isExtension(pkg)) {
190
- // it's possible that this extension already exists in the manifest,
191
- // so only update `didChange` if it's new.
192
- const added = this.addExtensionFromPackage(pkg, path.join(filepath, 'package.json'));
193
- didChange = didChange || added;
168
+
169
+ /**
170
+ * Listener for the `match` event of a `glob` instance
171
+ * @param {string} filepath - Path to a `package.json`
172
+ * @returns {Promise<void>}
173
+ */
174
+ const onMatch = async (filepath) => {
175
+ try {
176
+ const pkg = JSON.parse(await fs.readFile(filepath, 'utf8'));
177
+ if (isDriver(pkg) || isPlugin(pkg)) {
178
+ const changed = this.addExtensionFromPackage(pkg, filepath);
179
+ didChange = didChange || changed;
180
+ }
181
+ } catch {}
182
+ };
183
+
184
+ /**
185
+ * A list of `Promise`s which read `package.json` files looking for Appium extensions.
186
+ * @type {Promise<void>[]}
187
+ */
188
+ const queue = [
189
+ // look at `package.json` in `APPIUM_HOME` only
190
+ onMatch(path.join(this._appiumHome, 'package.json')),
191
+ ];
192
+
193
+ // add dependencies to the queue
194
+ await new B((resolve, reject) => {
195
+ glob(
196
+ 'node_modules/{*,@*/*}/package.json',
197
+ {cwd: this._appiumHome, silent: true, absolute: true},
198
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
199
+ (err) => {
200
+ if (err) {
201
+ reject(err);
194
202
  }
195
- } catch {}
196
- }
197
- }
203
+ resolve();
204
+ }
205
+ )
206
+ .on('error', reject)
207
+ .on('match', (filepath) => {
208
+ queue.push(onMatch(filepath));
209
+ });
210
+ });
211
+
212
+ // wait for everything to finish
213
+ await B.all(queue);
214
+
198
215
  return didChange;
199
216
  }
200
217
 
@@ -1,5 +1,5 @@
1
1
  import {ArgumentTypeError} from 'argparse';
2
- import {readFileSync} from 'fs';
2
+ import {readFileSync, existsSync} from 'fs';
3
3
  import _ from 'lodash';
4
4
 
5
5
  /**
@@ -55,25 +55,30 @@ export const transformers = {
55
55
  /**
56
56
  * Given a CSV-style string or pathname, parse it into an array.
57
57
  * The file can also be split on newlines.
58
- * @param {string} value
58
+ * @param {string} csvOrPath
59
59
  * @returns {string[]}
60
60
  */
61
- csv: (value) => {
62
- let body;
61
+ csv: (csvOrPath) => {
62
+ let csv = csvOrPath;
63
+ let loadedFromFile = false;
63
64
  // since this value could be a single string (no commas) _or_ a pathname, we will need
64
65
  // to attempt to parse it as a file _first_.
65
- try {
66
- body = readFileSync(value, 'utf8');
67
- } catch (err) {
68
- if (err.code !== 'ENOENT') {
69
- throw new ArgumentTypeError(`Could not read file ${body}: ${err.message}`);
66
+ if (existsSync(csvOrPath)) {
67
+ try {
68
+ csv = readFileSync(csvOrPath, 'utf8');
69
+ } catch (err) {
70
+ throw new ArgumentTypeError(`Could not read file '${csvOrPath}': ${err.message}`);
70
71
  }
72
+ loadedFromFile = true;
71
73
  }
72
74
 
73
75
  try {
74
- return body ? parseCsvFile(body) : parseCsvLine(value);
76
+ return loadedFromFile ? parseCsvFile(csv) : parseCsvLine(csv);
75
77
  } catch (err) {
76
- throw new ArgumentTypeError('Must be a comma-delimited string, e.g., "foo,bar,baz"');
78
+ const msg = loadedFromFile
79
+ ? `The provided value of '${csvOrPath}' must be a valid CSV`
80
+ : `Must be a comma-delimited string, e.g., "foo,bar,baz"`;
81
+ throw new TypeError(`${msg}. Original error: ${err.message}`);
77
82
  }
78
83
  },
79
84
 
@@ -85,20 +90,18 @@ export const transformers = {
85
90
  json: (jsonOrPath) => {
86
91
  let json = jsonOrPath;
87
92
  let loadedFromFile = false;
88
- try {
89
- // use synchronous file access, as `argparse` provides no way of either
90
- // awaiting or using callbacks. This step happens in startup, in what is
91
- // effectively command-line code, so nothing is blocked in terms of
92
- // sessions, so holding up the event loop does not incur the usual
93
- // drawbacks.
94
- json = readFileSync(jsonOrPath, 'utf8');
95
- loadedFromFile = true;
96
- } catch (err) {
97
- // unreadable files don't count.
98
- // also `ENAMETOOLONG` can happen if we try to open a file that's a huge JSON string.
99
- if (err.code !== 'ENOENT' && err.code !== 'ENAMETOOLONG') {
100
- throw err;
93
+ if (existsSync(jsonOrPath)) {
94
+ try {
95
+ // use synchronous file access, as `argparse` provides no way of either
96
+ // awaiting or using callbacks. This step happens in startup, in what is
97
+ // effectively command-line code, so nothing is blocked in terms of
98
+ // sessions, so holding up the event loop does not incur the usual
99
+ // drawbacks.
100
+ json = readFileSync(jsonOrPath, 'utf8');
101
+ } catch (err) {
102
+ throw new ArgumentTypeError(`Could not read file '${jsonOrPath}': ${err.message}`);
101
103
  }
104
+ loadedFromFile = true;
102
105
  }
103
106
  try {
104
107
  const result = JSON.parse(json);
package/lib/utils.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import _ from 'lodash';
2
2
  import logger from './logger';
3
- import {processCapabilities, PROTOCOLS} from '@appium/base-driver';
3
+ import {processCapabilities, PROTOCOLS, STANDARD_CAPS} from '@appium/base-driver';
4
4
  import {inspect as dump} from 'util';
5
5
  import {node} from '@appium/support';
6
6
  import path from 'path';
7
7
 
8
8
  const W3C_APPIUM_PREFIX = 'appium';
9
+ const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
9
10
 
10
11
  /**
11
12
  *
@@ -35,16 +36,18 @@ const inspect = _.flow(
35
36
  * Takes the caps that were provided in the request and translates them
36
37
  * into caps that can be used by the inner drivers.
37
38
  *
38
- * @param {any} jsonwpCapabilities
39
- * @param {W3CCapabilities} w3cCapabilities
40
- * @param {import('@appium/types').Constraints} constraints
41
- * @param {import('@appium/types').DefaultCapabilitiesConfig} [defaultCapabilities]
42
- * @returns {ParsedDriverCaps|InvalidCaps}
39
+ * @template {Constraints} C
40
+ * @template [J=any]
41
+ * @param {J} jsonwpCapabilities
42
+ * @param {W3CCapabilities<C>} w3cCapabilities
43
+ * @param {C} constraints
44
+ * @param {NSCapabilities<C>} [defaultCapabilities]
45
+ * @returns {ParsedDriverCaps<C,J>|InvalidCaps<C,J>}
43
46
  */
44
47
  function parseCapsForInnerDriver(
45
48
  jsonwpCapabilities,
46
49
  w3cCapabilities,
47
- constraints = {},
50
+ constraints = /** @type {C} */ ({}),
48
51
  defaultCapabilities = {}
49
52
  ) {
50
53
  // Check if the caller sent JSONWP caps, W3C caps, or both
@@ -52,14 +55,14 @@ function parseCapsForInnerDriver(
52
55
  _.isPlainObject(w3cCapabilities) &&
53
56
  (_.has(w3cCapabilities, 'alwaysMatch') || _.has(w3cCapabilities, 'firstMatch'));
54
57
  const hasJSONWPCaps = _.isPlainObject(jsonwpCapabilities);
55
- let desiredCaps = /** @type {ParsedDriverCaps['desiredCaps']} */ ({});
56
- /** @type {ParsedDriverCaps['processedW3CCapabilities']} */
58
+ let desiredCaps = /** @type {ParsedDriverCaps<C>['desiredCaps']} */ ({});
59
+ /** @type {ParsedDriverCaps<C>['processedW3CCapabilities']} */
57
60
  let processedW3CCapabilities;
58
- /** @type {ParsedDriverCaps['processedJsonwpCapabilities']} */
61
+ /** @type {ParsedDriverCaps<C>['processedJsonwpCapabilities']} */
59
62
  let processedJsonwpCapabilities;
60
63
 
61
64
  if (!hasW3CCaps) {
62
- return /** @type {InvalidCaps} */ ({
65
+ return /** @type {InvalidCaps<C>} */ ({
63
66
  protocol: PROTOCOLS.W3C,
64
67
  error: new Error('W3C capabilities should be provided'),
65
68
  });
@@ -78,7 +81,7 @@ function parseCapsForInnerDriver(
78
81
  for (const [defaultCapKey, defaultCapValue] of _.toPairs(defaultCapabilities)) {
79
82
  let isCapAlreadySet = false;
80
83
  // Check if the key is already present in firstMatch entries
81
- for (const firstMatchEntry of w3cCapabilities.firstMatch || []) {
84
+ for (const firstMatchEntry of w3cCapabilities.firstMatch ?? []) {
82
85
  if (
83
86
  _.isPlainObject(firstMatchEntry) &&
84
87
  _.has(removeAppiumPrefixes(firstMatchEntry), removeAppiumPrefix(defaultCapKey))
@@ -102,7 +105,9 @@ function parseCapsForInnerDriver(
102
105
 
103
106
  // Only add the default capability if it is not overridden
104
107
  if (_.isEmpty(w3cCapabilities.firstMatch)) {
105
- w3cCapabilities.firstMatch = [{[defaultCapKey]: defaultCapValue}];
108
+ w3cCapabilities.firstMatch = /** @type {W3CCapabilities<C>['firstMatch']} */ ([
109
+ {[defaultCapKey]: defaultCapValue},
110
+ ]);
106
111
  } else {
107
112
  w3cCapabilities.firstMatch[0][defaultCapKey] = defaultCapValue;
108
113
  }
@@ -129,7 +134,7 @@ function parseCapsForInnerDriver(
129
134
  desiredCaps = processCapabilities(w3cCapabilities, constraints, true);
130
135
  } catch (error) {
131
136
  logger.info(`Could not parse W3C capabilities: ${error.message}`);
132
- return /** @type {InvalidCaps} */ ({
137
+ return /** @type {InvalidCaps<C,J>} */ ({
133
138
  desiredCaps,
134
139
  processedJsonwpCapabilities,
135
140
  processedW3CCapabilities,
@@ -145,7 +150,7 @@ function parseCapsForInnerDriver(
145
150
  };
146
151
  }
147
152
 
148
- return /** @type {ParsedDriverCaps} */ ({
153
+ return /** @type {ParsedDriverCaps<C,J>} */ ({
149
154
  desiredCaps,
150
155
  processedJsonwpCapabilities,
151
156
  processedW3CCapabilities,
@@ -155,57 +160,43 @@ function parseCapsForInnerDriver(
155
160
 
156
161
  /**
157
162
  * Takes a capabilities objects and prefixes capabilities with `appium:`
158
- * @param {Capabilities} caps Desired capabilities object
159
- * @returns {AppiumW3CCapabilities}
163
+ * @template {Constraints} [C={}]
164
+ * @param {Capabilities<C>} caps - Desired capabilities object
165
+ * @returns {NSCapabilities<C>}
160
166
  */
161
167
  function insertAppiumPrefixes(caps) {
162
- // Standard, non-prefixed capabilities (see https://www.w3.org/TR/webdriver/#dfn-table-of-standard-capabilities)
163
- const STANDARD_CAPS = [
164
- 'browserName',
165
- 'browserVersion',
166
- 'platformName',
167
- 'acceptInsecureCerts',
168
- 'pageLoadStrategy',
169
- 'proxy',
170
- 'setWindowRect',
171
- 'timeouts',
172
- 'unhandledPromptBehavior',
173
- ];
174
-
175
- let prefixedCaps = {};
176
- for (let [name, value] of _.toPairs(caps)) {
177
- if (STANDARD_CAPS.includes(name) || name.includes(':')) {
178
- prefixedCaps[name] = value;
179
- } else {
180
- prefixedCaps[`${W3C_APPIUM_PREFIX}:${name}`] = value;
181
- }
182
- }
183
- return prefixedCaps;
168
+ return /** @type {NSCapabilities<C>} */ (
169
+ _.mapKeys(caps, (_, key) =>
170
+ STANDARD_CAPS_LOWERCASE.has(key.toLowerCase()) || key.includes(':')
171
+ ? key
172
+ : `${W3C_APPIUM_PREFIX}:${key}`
173
+ )
174
+ );
184
175
  }
185
176
 
186
177
  /**
187
- *
188
- * @param {AppiumW3CCapabilities} caps
189
- * @returns {Capabilities}
178
+ * @template {Constraints} [C={}]
179
+ * @param {NSCapabilities<C>} caps
180
+ * @returns {Capabilities<C>}
190
181
  */
191
182
  function removeAppiumPrefixes(caps) {
192
- if (!_.isPlainObject(caps)) {
193
- return caps;
194
- }
195
-
196
- /** @type {Capabilities} */
197
- const fixedCaps = {};
198
- for (let [name, value] of _.toPairs(caps)) {
199
- fixedCaps[removeAppiumPrefix(name)] = value;
200
- }
201
- return fixedCaps;
183
+ return /** @type {Capabilities<C>} */ (_.mapKeys(caps, (_, key) => removeAppiumPrefix(key)));
202
184
  }
203
185
 
186
+ /**
187
+ * @param {string} key
188
+ * @returns {string}
189
+ */
204
190
  function removeAppiumPrefix(key) {
205
191
  const prefix = `${W3C_APPIUM_PREFIX}:`;
206
192
  return _.startsWith(key, prefix) ? key.substring(prefix.length) : key;
207
193
  }
208
194
 
195
+ /**
196
+ *
197
+ * @param {string} pkgName
198
+ * @returns {string|undefined}
199
+ */
209
200
  function getPackageVersion(pkgName) {
210
201
  const pkgInfo = require(`${pkgName}/package.json`) || {};
211
202
  return pkgInfo.version;
@@ -235,7 +226,6 @@ function adjustNodePath() {
235
226
  require('module').Module._initPaths();
236
227
  return true;
237
228
  } catch (e) {
238
- logger.info(`Module init paths cannot be refreshed. Original error: ${e.message}`);
239
229
  return false;
240
230
  }
241
231
  };
@@ -243,7 +233,6 @@ function adjustNodePath() {
243
233
  if (!process.env.NODE_PATH) {
244
234
  process.env.NODE_PATH = nodeModulesRoot;
245
235
  if (refreshRequirePaths()) {
246
- logger.info(`Setting NODE_PATH to '${nodeModulesRoot}'`);
247
236
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
248
237
  } else {
249
238
  delete process.env.NODE_PATH;
@@ -253,7 +242,6 @@ function adjustNodePath() {
253
242
 
254
243
  const nodePathParts = process.env.NODE_PATH.split(path.delimiter);
255
244
  if (nodePathParts.includes(nodeModulesRoot)) {
256
- logger.info(`NODE_PATH already includes '${nodeModulesRoot}'`);
257
245
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
258
246
  return;
259
247
  }
@@ -261,7 +249,6 @@ function adjustNodePath() {
261
249
  nodePathParts.push(nodeModulesRoot);
262
250
  process.env.NODE_PATH = nodePathParts.join(path.delimiter);
263
251
  if (refreshRequirePaths()) {
264
- logger.info(`Adding '${nodeModulesRoot}' to NODE_PATH`);
265
252
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
266
253
  } else {
267
254
  process.env.NODE_PATH = _.without(nodePathParts, nodeModulesRoot).join(path.delimiter);
@@ -313,26 +300,60 @@ export {
313
300
  };
314
301
 
315
302
  /**
316
- * @todo protocol is more specific
303
+ * @typedef {import('@appium/types').StringRecord} StringRecord
304
+ * @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
305
+ */
306
+
307
+ /**
308
+ * @template {Constraints} [C=BaseDriverCapConstraints]
309
+ * @template [J=any]
317
310
  * @typedef ParsedDriverCaps
318
- * @property {Capabilities} desiredCaps
311
+ * @property {Capabilities<C>} desiredCaps
319
312
  * @property {string} protocol
320
- * @property {any} [processedJsonwpCapabilities]
321
- * @property {W3CCapabilities} [processedW3CCapabilities]
313
+ * @property {J} [processedJsonwpCapabilities]
314
+ * @property {W3CCapabilities<C>} [processedW3CCapabilities]
322
315
  */
323
316
 
324
317
  /**
325
318
  * @todo protocol is more specific
319
+ * @template {Constraints} [C=BaseDriverCapConstraints]
320
+ * @template [J=any]
326
321
  * @typedef InvalidCaps
327
322
  * @property {Error} error
328
323
  * @property {string} protocol
329
- * @property {Capabilities} [desiredCaps]
330
- * @property {any} [processedJsonwpCapabilities]
331
- * @property {W3CCapabilities} [processedW3CCapabilities]
324
+ * @property {Capabilities<C>} [desiredCaps]
325
+ * @property {J} [processedJsonwpCapabilities]
326
+ * @property {W3CCapabilities<C>} [processedW3CCapabilities]
327
+ */
328
+
329
+ /**
330
+ * @template {Constraints} [C=BaseDriverCapConstraints]
331
+ * @template {StringRecord|void} [Extra=void]
332
+ * @typedef {import('@appium/types').Capabilities<C, Extra>} Capabilities
333
+ */
334
+
335
+ /**
336
+ * @template {Constraints} [C=BaseDriverCapConstraints]
337
+ * @template {StringRecord|void} [Extra=void]
338
+ * @typedef {import('@appium/types').W3CCapabilities<C, Extra>} W3CCapabilities
339
+ */
340
+
341
+ /**
342
+ * @template {Constraints} [C=BaseDriverCapConstraints]
343
+ * @template {StringRecord|void} [Extra=void]
344
+ * @typedef {import('@appium/types').NSCapabilities<C, Extra>} NSCapabilities
345
+ */
346
+
347
+ /**
348
+ * @template {Constraints} C
349
+ * @typedef {import('@appium/types').ConstraintsToCaps<C>} ConstraintsToCaps
350
+ */
351
+
352
+ /**
353
+ * @template T
354
+ * @typedef {import('type-fest').StringKeyOf<T>} StringKeyOf
332
355
  */
333
356
 
334
357
  /**
335
- * @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
336
- * @typedef {import('@appium/types').Capabilities} Capabilities
337
- * @typedef {import('@appium/types').AppiumW3CCapabilities} AppiumW3CCapabilities
358
+ * @typedef {import('@appium/types').Constraints} Constraints
338
359
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium",
3
- "version": "2.0.0-beta.44",
3
+ "version": "2.0.0-beta.46",
4
4
  "description": "Automation for Apps.",
5
5
  "keywords": [
6
6
  "automation",
@@ -43,6 +43,7 @@
43
43
  "scripts": {
44
44
  "build": "babel lib --root-mode=upward --out-dir=build/lib",
45
45
  "build:docs": "node docs/scripts/build-docs.js",
46
+ "build:docs:cli": "node docs/scripts/gen-cli-args-docs.js",
46
47
  "build:docs:assets": "node docs/scripts/copy-assets.js",
47
48
  "dev": "npm run build -- --watch",
48
49
  "dev:docs": "npm run build:docs:assets && npm run dev:docs:en",
@@ -60,16 +61,15 @@
60
61
  "test:unit": "mocha \"./test/unit/**/*.spec.js\""
61
62
  },
62
63
  "dependencies": {
63
- "@appium/base-driver": "^8.7.1",
64
- "@appium/base-plugin": "^1.10.3",
65
- "@appium/docutils": "^0.0.11",
64
+ "@appium/base-driver": "^8.7.3",
65
+ "@appium/base-plugin": "^1.10.5",
66
+ "@appium/docutils": "^0.0.13",
66
67
  "@appium/schema": "^0.0.9",
67
- "@appium/support": "^2.60.0",
68
- "@appium/types": "^0.4.1",
69
- "@babel/runtime": "7.19.0",
70
- "@sidvind/better-ajv-errors": "2.0.0",
68
+ "@appium/support": "^2.61.1",
69
+ "@appium/types": "^0.5.0",
70
+ "@sidvind/better-ajv-errors": "2.1.0",
71
71
  "@types/argparse": "2.0.10",
72
- "@types/bluebird": "3.5.36",
72
+ "@types/bluebird": "3.5.37",
73
73
  "@types/fancy-log": "2.0.0",
74
74
  "@types/semver": "7.3.12",
75
75
  "@types/teen_process": "1.16.1",
@@ -83,6 +83,7 @@
83
83
  "bluebird": "3.7.2",
84
84
  "cross-env": "7.0.3",
85
85
  "find-up": "5.0.0",
86
+ "glob": "8.0.3",
86
87
  "lilconfig": "2.0.6",
87
88
  "lodash": "4.17.21",
88
89
  "longjohn": "0.2.12",
@@ -90,13 +91,13 @@
90
91
  "ora": "5.4.1",
91
92
  "package-changed": "1.9.0",
92
93
  "resolve-from": "5.0.0",
93
- "semver": "7.3.7",
94
+ "semver": "7.3.8",
94
95
  "source-map-support": "0.5.21",
95
- "teen_process": "1.16.0",
96
- "type-fest": "2.19.0",
97
- "winston": "3.8.1",
96
+ "teen_process": "2.0.2",
97
+ "type-fest": "3.1.0",
98
+ "winston": "3.8.2",
98
99
  "wrap-ansi": "7.0.0",
99
- "yaml": "2.1.1"
100
+ "yaml": "2.1.3"
100
101
  },
101
102
  "engines": {
102
103
  "node": ">=14",
@@ -106,5 +107,5 @@
106
107
  "access": "public",
107
108
  "tag": "next"
108
109
  },
109
- "gitHead": "c26af8f85230ac65cbc19f08f763942f74b0eb0c"
110
+ "gitHead": "6b3cc1a8743f78c1f50320364f25f3011d2b2136"
110
111
  }