appium 2.0.0-beta.35 → 2.0.0-beta.37

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 (122) hide show
  1. package/build/lib/appium.d.ts +41 -52
  2. package/build/lib/appium.d.ts.map +1 -1
  3. package/build/lib/appium.js +32 -15
  4. package/build/lib/cli/args.d.ts +1 -1
  5. package/build/lib/cli/args.d.ts.map +1 -1
  6. package/build/lib/cli/args.js +1 -1
  7. package/build/lib/cli/driver-command.d.ts +3 -3
  8. package/build/lib/cli/driver-command.d.ts.map +1 -1
  9. package/build/lib/cli/driver-command.js +1 -1
  10. package/build/lib/cli/extension-command.d.ts +60 -38
  11. package/build/lib/cli/extension-command.d.ts.map +1 -1
  12. package/build/lib/cli/extension-command.js +115 -59
  13. package/build/lib/cli/extension.d.ts +9 -5
  14. package/build/lib/cli/extension.d.ts.map +1 -1
  15. package/build/lib/cli/extension.js +5 -7
  16. package/build/lib/cli/parser.d.ts +3 -3
  17. package/build/lib/cli/parser.d.ts.map +1 -1
  18. package/build/lib/cli/parser.js +1 -1
  19. package/build/lib/cli/plugin-command.d.ts +1 -1
  20. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  21. package/build/lib/cli/plugin-command.js +1 -1
  22. package/build/lib/cli/utils.js +1 -1
  23. package/build/lib/config-file.d.ts.map +1 -1
  24. package/build/lib/config-file.js +1 -1
  25. package/build/lib/config.d.ts +4 -4
  26. package/build/lib/config.d.ts.map +1 -1
  27. package/build/lib/config.js +1 -1
  28. package/build/lib/constants.d.ts.map +1 -1
  29. package/build/lib/constants.js +1 -1
  30. package/build/lib/extension/driver-config.d.ts +29 -32
  31. package/build/lib/extension/driver-config.d.ts.map +1 -1
  32. package/build/lib/extension/driver-config.js +7 -20
  33. package/build/lib/extension/extension-config.d.ts +108 -36
  34. package/build/lib/extension/extension-config.d.ts.map +1 -1
  35. package/build/lib/extension/extension-config.js +199 -60
  36. package/build/lib/extension/index.d.ts +16 -7
  37. package/build/lib/extension/index.d.ts.map +1 -1
  38. package/build/lib/extension/index.js +15 -18
  39. package/build/lib/extension/manifest.d.ts +12 -12
  40. package/build/lib/extension/manifest.d.ts.map +1 -1
  41. package/build/lib/extension/manifest.js +13 -3
  42. package/build/lib/extension/package-changed.d.ts.map +1 -1
  43. package/build/lib/extension/package-changed.js +1 -1
  44. package/build/lib/extension/plugin-config.d.ts +19 -24
  45. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  46. package/build/lib/extension/plugin-config.js +9 -18
  47. package/build/lib/grid-register.d.ts.map +1 -1
  48. package/build/lib/grid-register.js +1 -1
  49. package/build/lib/logger.d.ts +1 -1
  50. package/build/lib/logger.d.ts.map +1 -1
  51. package/build/lib/logger.js +1 -1
  52. package/build/lib/logsink.d.ts.map +1 -1
  53. package/build/lib/logsink.js +3 -2
  54. package/build/lib/main.d.ts +13 -12
  55. package/build/lib/main.d.ts.map +1 -1
  56. package/build/lib/main.js +4 -4
  57. package/build/lib/schema/arg-spec.d.ts +4 -4
  58. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  59. package/build/lib/schema/arg-spec.js +1 -1
  60. package/build/lib/schema/cli-args.d.ts.map +1 -1
  61. package/build/lib/schema/cli-args.js +1 -1
  62. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  63. package/build/lib/schema/cli-transformers.js +1 -1
  64. package/build/lib/schema/keywords.d.ts.map +1 -1
  65. package/build/lib/schema/keywords.js +1 -1
  66. package/build/lib/schema/schema.d.ts +2 -2
  67. package/build/lib/schema/schema.d.ts.map +1 -1
  68. package/build/lib/schema/schema.js +1 -1
  69. package/build/lib/utils.d.ts.map +1 -1
  70. package/build/lib/utils.js +1 -1
  71. package/build/tsconfig.tsbuildinfo +1 -1
  72. package/build/types/appium-manifest.d.ts +23 -4
  73. package/build/types/appium-manifest.d.ts.map +1 -1
  74. package/build/types/cli.d.ts.map +1 -1
  75. package/build/types/{external-manifest.d.ts → extension-manifest.d.ts} +15 -7
  76. package/build/types/extension-manifest.d.ts.map +1 -0
  77. package/build/types/index.d.ts +6 -5
  78. package/build/types/index.d.ts.map +1 -1
  79. package/driver.d.ts +1 -0
  80. package/driver.js +14 -0
  81. package/lib/appium.js +208 -124
  82. package/lib/cli/args.js +143 -93
  83. package/lib/cli/driver-command.js +10 -15
  84. package/lib/cli/extension-command.js +226 -175
  85. package/lib/cli/extension.js +15 -19
  86. package/lib/cli/parser.js +19 -31
  87. package/lib/cli/plugin-command.js +8 -8
  88. package/lib/cli/utils.js +8 -14
  89. package/lib/config-file.js +21 -25
  90. package/lib/config.js +82 -64
  91. package/lib/constants.js +4 -13
  92. package/lib/extension/driver-config.js +171 -171
  93. package/lib/extension/extension-config.js +347 -126
  94. package/lib/extension/index.js +72 -58
  95. package/lib/extension/manifest.js +48 -57
  96. package/lib/extension/package-changed.js +9 -8
  97. package/lib/extension/plugin-config.js +62 -62
  98. package/lib/grid-register.js +29 -18
  99. package/lib/logger.js +1 -2
  100. package/lib/logsink.js +29 -31
  101. package/lib/main.js +111 -73
  102. package/lib/schema/arg-spec.js +10 -13
  103. package/lib/schema/cli-args.js +14 -37
  104. package/lib/schema/cli-transformers.js +7 -14
  105. package/lib/schema/keywords.js +15 -13
  106. package/lib/schema/schema.js +58 -75
  107. package/lib/utils.js +50 -25
  108. package/package.json +25 -18
  109. package/plugin.d.ts +1 -0
  110. package/plugin.js +13 -0
  111. package/scripts/autoinstall-extensions.js +177 -0
  112. package/support.d.ts +1 -0
  113. package/support.js +13 -0
  114. package/types/appium-manifest.ts +27 -15
  115. package/types/cli.ts +2 -9
  116. package/types/{external-manifest.ts → extension-manifest.ts} +21 -15
  117. package/types/index.ts +12 -5
  118. package/build/types/extension.d.ts +0 -43
  119. package/build/types/extension.d.ts.map +0 -1
  120. package/build/types/external-manifest.d.ts.map +0 -1
  121. package/scripts/postinstall.js +0 -71
  122. package/types/extension.ts +0 -56
package/lib/appium.js CHANGED
@@ -1,13 +1,20 @@
1
1
  /* eslint-disable no-unused-vars */
2
2
  import _ from 'lodash';
3
- import { getBuildInfo, updateBuildInfo, APPIUM_VER } from './config';
4
- import { BaseDriver, DriverCore, errors, isSessionCommand,
5
- CREATE_SESSION_COMMAND, DELETE_SESSION_COMMAND, GET_STATUS_COMMAND
3
+ import {getBuildInfo, updateBuildInfo, APPIUM_VER} from './config';
4
+ import {
5
+ BaseDriver,
6
+ DriverCore,
7
+ errors,
8
+ isSessionCommand,
9
+ CREATE_SESSION_COMMAND,
10
+ DELETE_SESSION_COMMAND,
11
+ GET_STATUS_COMMAND,
6
12
  } from '@appium/base-driver';
7
13
  import AsyncLock from 'async-lock';
8
- import { parseCapsForInnerDriver, pullSettings } from './utils';
9
- import { util, node, logger } from '@appium/support';
10
- import { getDefaultsForExtension } from './schema';
14
+ import {parseCapsForInnerDriver, pullSettings} from './utils';
15
+ import {util, node, logger} from '@appium/support';
16
+ import {getDefaultsForExtension} from './schema';
17
+ import {DRIVER_TYPE, PLUGIN_TYPE} from './constants';
11
18
 
12
19
  /**
13
20
  * Invariant set of base constraints
@@ -56,9 +63,9 @@ class AppiumDriver extends DriverCore {
56
63
 
57
64
  /**
58
65
  * List of active plugins
59
- * @type {PluginClass[]}
66
+ * @type {Map<PluginClass,string>}
60
67
  */
61
- pluginClasses = [];
68
+ pluginClasses;
62
69
 
63
70
  /**
64
71
  * map of sessions to actual plugin instances per session
@@ -70,7 +77,7 @@ class AppiumDriver extends DriverCore {
70
77
  * some commands are sessionless, so we need a set of plugins for them
71
78
  * @type {InstanceType<PluginClass>[]}
72
79
  */
73
- sessionlessPlugins = [];;
80
+ sessionlessPlugins = [];
74
81
 
75
82
  /** @type {DriverConfig} */
76
83
  driverConfig;
@@ -78,10 +85,15 @@ class AppiumDriver extends DriverCore {
78
85
  /** @type {AppiumServer} */
79
86
  server;
80
87
 
88
+ desiredCapConstraints = desiredCapabilityConstraints;
89
+
90
+ /** @type {DriverOpts} */
91
+ args;
92
+
81
93
  /**
82
94
  * @param {DriverOpts} opts
83
95
  */
84
- constructor (opts) {
96
+ constructor(opts) {
85
97
  // It is necessary to set `--tmp` here since it should be set to
86
98
  // process.env.APPIUM_TMP_DIR once at an initial point in the Appium lifecycle.
87
99
  // The process argument will be referenced by BaseDriver.
@@ -92,8 +104,6 @@ class AppiumDriver extends DriverCore {
92
104
 
93
105
  super(opts);
94
106
 
95
- this.desiredCapConstraints = desiredCapabilityConstraints;
96
-
97
107
  this.args = {...opts};
98
108
 
99
109
  // allow this to happen in the background, so no `await`
@@ -107,7 +117,7 @@ class AppiumDriver extends DriverCore {
107
117
  /**
108
118
  * Retrieves logger instance for the current umbrella driver instance
109
119
  */
110
- get log () {
120
+ get log() {
111
121
  if (!this._log) {
112
122
  const instanceName = `${this.constructor.name}@${node.getObjectId(this).substring(0, 4)}`;
113
123
  this._log = logger.getLogger(instanceName);
@@ -118,65 +128,83 @@ class AppiumDriver extends DriverCore {
118
128
  /**
119
129
  * Cancel commands queueing for the umbrella Appium driver
120
130
  */
121
- get isCommandsQueueEnabled () {
131
+ get isCommandsQueueEnabled() {
122
132
  return false;
123
133
  }
124
134
 
125
- sessionExists (sessionId) {
135
+ sessionExists(sessionId) {
126
136
  const dstSession = this.sessions[sessionId];
127
137
  return dstSession && dstSession.sessionId !== null;
128
138
  }
129
139
 
130
- driverForSession (sessionId) {
140
+ driverForSession(sessionId) {
131
141
  return this.sessions[sessionId];
132
142
  }
133
143
 
134
- async getStatus () { // eslint-disable-line require-await
144
+ // eslint-disable-next-line require-await
145
+ async getStatus() {
135
146
  return {
136
147
  build: _.clone(getBuildInfo()),
137
148
  };
138
149
  }
139
150
 
140
- async getSessions () { // eslint-disable-line require-await
141
- return _.toPairs(this.sessions)
142
- .map(([id, driver]) => ({id, capabilities: driver.caps}));
151
+ // eslint-disable-next-line require-await
152
+ async getSessions() {
153
+ return _.toPairs(this.sessions).map(([id, driver]) => ({
154
+ id,
155
+ capabilities: driver.caps,
156
+ }));
143
157
  }
144
158
 
145
- printNewSessionAnnouncement (driverName, driverVersion, driverBaseVersion) {
146
- this.log.info(driverVersion
147
- ? `Appium v${APPIUM_VER} creating new ${driverName} (v${driverVersion}) session`
148
- : `Appium v${APPIUM_VER} creating new ${driverName} session`
159
+ printNewSessionAnnouncement(driverName, driverVersion, driverBaseVersion) {
160
+ this.log.info(
161
+ driverVersion
162
+ ? `Appium v${APPIUM_VER} creating new ${driverName} (v${driverVersion}) session`
163
+ : `Appium v${APPIUM_VER} creating new ${driverName} session`
149
164
  );
150
165
  this.log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
151
- this.log.info(AppiumDriver.baseVersion
152
- ? `Appium's BaseDriver version is ${AppiumDriver.baseVersion}`
153
- : `Could not determine Appium's BaseDriver version`
166
+ this.log.info(
167
+ AppiumDriver.baseVersion
168
+ ? `Appium's BaseDriver version is ${AppiumDriver.baseVersion}`
169
+ : `Could not determine Appium's BaseDriver version`
154
170
  );
155
- this.log.info(driverBaseVersion
156
- ? `${driverName}'s BaseDriver version is ${driverBaseVersion}`
157
- : `Could not determine ${driverName}'s BaseDriver version`
171
+ this.log.info(
172
+ driverBaseVersion
173
+ ? `${driverName}'s BaseDriver version is ${driverBaseVersion}`
174
+ : `Could not determine ${driverName}'s BaseDriver version`
158
175
  );
159
176
  }
160
177
 
161
178
  /**
162
- * Validate and assign CLI args for a driver or plugin
179
+ * Retrieves all CLI arguments for a specific plugin.
180
+ * @param {string} extName - Plugin name
181
+ * @returns {Record<string,unknown>} Arguments object. If none, an empty object.
182
+ */
183
+ getCliArgsForPlugin(extName) {
184
+ return /** @type {Record<string,unknown>} */ (this.args.plugin?.[extName] ?? {});
185
+ }
186
+
187
+ /**
188
+ * Retrieves CLI args for a specific driver.
163
189
  *
164
- * If the extension has provided a schema, validation has already happened.
190
+ * _Any arg which is equal to its default value will not be present in the returned object._
165
191
  *
166
- * Any arg which is equal to its default value will not be assigned to the extension.
167
- * @param {ExtensionType} extType 'driver' or 'plugin'
168
- * @param {string} extName the name of the extension
169
- * @param {Object} extInstance the driver or plugin instance
192
+ * _Note that this behavior currently (May 18 2022) differs from how plugins are handled_ (see {@linkcode AppiumDriver.getCliArgsForPlugin}).
193
+ * @param {string} extName - Driver name
194
+ * @returns {Record<string,unknown>|undefined} Arguments object. If none, `undefined`
170
195
  */
171
- assignCliArgsToExtension (extType, extName, extInstance) {
172
- const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */(this.args[extType]?.[extName]);
196
+ getCliArgsForDriver(extName) {
197
+ const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */ (
198
+ this.args.driver?.[extName]
199
+ );
200
+
173
201
  if (!_.isEmpty(allCliArgsForExt)) {
174
- const defaults = getDefaultsForExtension(extType, extName);
202
+ const defaults = getDefaultsForExtension(DRIVER_TYPE, extName);
175
203
  const cliArgs = _.isEmpty(defaults)
176
204
  ? allCliArgsForExt
177
205
  : _.omitBy(allCliArgsForExt, (value, key) => _.isEqual(defaults[key], value));
178
206
  if (!_.isEmpty(cliArgs)) {
179
- extInstance.cliArgs = cliArgs;
207
+ return cliArgs;
180
208
  }
181
209
  }
182
210
  }
@@ -186,9 +214,9 @@ class AppiumDriver extends DriverCore {
186
214
  * @param {W3CCapabilities} jsonwpCaps JSONWP formatted desired capabilities
187
215
  * @param {W3CCapabilities} reqCaps Required capabilities (JSONWP standard)
188
216
  * @param {W3CCapabilities} w3cCapabilities W3C capabilities
189
- * @param {import('@appium/types').DriverData[]} [driverData]
217
+ * @param {DriverData[]} [driverData]
190
218
  */
191
- async createSession (jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
219
+ async createSession(jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
192
220
  const defaultCapabilities = _.cloneDeep(this.args.defaultCapabilities);
193
221
  const defaultSettings = pullSettings(defaultCapabilities);
194
222
  jsonwpCaps = _.cloneDeep(jsonwpCaps);
@@ -200,9 +228,9 @@ class AppiumDriver extends DriverCore {
200
228
  // JSONWP caps to W3C caps
201
229
  const w3cSettings = {
202
230
  ...jwpSettings,
203
- ...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {})
231
+ ...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {}),
204
232
  };
205
- for (const firstMatchEntry of ((w3cCapabilities ?? {}).firstMatch ?? [])) {
233
+ for (const firstMatchEntry of (w3cCapabilities ?? {}).firstMatch ?? []) {
206
234
  Object.assign(w3cSettings, pullSettings(firstMatchEntry));
207
235
  }
208
236
 
@@ -217,9 +245,10 @@ class AppiumDriver extends DriverCore {
217
245
  defaultCapabilities
218
246
  );
219
247
 
220
- const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = /** @type {import('./utils').ParsedDriverCaps} */(parsedCaps);
248
+ const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} =
249
+ /** @type {import('./utils').ParsedDriverCaps} */ (parsedCaps);
221
250
  protocol = parsedCaps.protocol;
222
- const error = /** @type {import('./utils').InvalidCaps} */(parsedCaps).error;
251
+ const error = /** @type {import('./utils').InvalidCaps} */ (parsedCaps).error;
223
252
  // If the parsing of the caps produced an error, throw it in here
224
253
  if (error) {
225
254
  throw error;
@@ -228,7 +257,7 @@ class AppiumDriver extends DriverCore {
228
257
  const {
229
258
  driver: InnerDriver,
230
259
  version: driverVersion,
231
- driverName
260
+ driverName,
232
261
  } = this.driverConfig.findMatchingDriver(desiredCaps);
233
262
  this.printNewSessionAnnouncement(InnerDriver.name, driverVersion, InnerDriver.baseVersion);
234
263
 
@@ -252,9 +281,11 @@ class AppiumDriver extends DriverCore {
252
281
  // could have been set by a malicious user via capabilities, whereas we
253
282
  // want a guarantee the values were set by the appium server admin
254
283
  if (this.args.relaxedSecurityEnabled) {
255
- this.log.info(`Applying relaxed security to '${InnerDriver.name}' as per ` +
256
- `server command line argument. All insecure features will be ` +
257
- `enabled unless explicitly disabled by --deny-insecure`);
284
+ this.log.info(
285
+ `Applying relaxed security to '${InnerDriver.name}' as per ` +
286
+ `server command line argument. All insecure features will be ` +
287
+ `enabled unless explicitly disabled by --deny-insecure`
288
+ );
258
289
  driverInstance.relaxedSecurityEnabled = true;
259
290
  }
260
291
 
@@ -272,7 +303,10 @@ class AppiumDriver extends DriverCore {
272
303
 
273
304
  // Likewise, any driver-specific CLI args that were passed in should be assigned directly to
274
305
  // the driver so that they cannot be mimicked by a malicious user sending in capabilities
275
- this.assignCliArgsToExtension('driver', driverName, driverInstance);
306
+ const cliArgs = this.getCliArgsForDriver(driverName);
307
+ if (!_.isEmpty(cliArgs)) {
308
+ driverInstance.cliArgs = cliArgs;
309
+ }
276
310
 
277
311
  // This assignment is required for correct web sockets functionality inside the driver
278
312
  // Drivers/plugins might also want to know where they are hosted
@@ -284,13 +318,15 @@ class AppiumDriver extends DriverCore {
284
318
  driverInstance.serverPath = this.args.basePath;
285
319
 
286
320
  try {
287
- runningDriversData = await this.curSessionDataForDriver(InnerDriver) ?? [];
321
+ runningDriversData = (await this.curSessionDataForDriver(InnerDriver)) ?? [];
288
322
  } catch (e) {
289
323
  throw new errors.SessionNotCreatedError(e.message);
290
324
  }
291
325
  await pendingDriversGuard.acquire(AppiumDriver.name, () => {
292
326
  this.pendingDrivers[InnerDriver.name] = this.pendingDrivers[InnerDriver.name] || [];
293
- otherPendingDriversData = _.compact(this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData));
327
+ otherPendingDriversData = _.compact(
328
+ this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData)
329
+ );
294
330
  this.pendingDrivers[InnerDriver.name].push(driverInstance);
295
331
  });
296
332
 
@@ -311,20 +347,26 @@ class AppiumDriver extends DriverCore {
311
347
 
312
348
  this.attachUnexpectedShutdownHandler(driverInstance, innerSessionId);
313
349
 
314
- this.log.info(`New ${InnerDriver.name} session created successfully, session ` +
315
- `${innerSessionId} added to master session list`);
350
+ this.log.info(
351
+ `New ${InnerDriver.name} session created successfully, session ` +
352
+ `${innerSessionId} added to master session list`
353
+ );
316
354
 
317
355
  // set the New Command Timeout for the inner driver
318
356
  driverInstance.startNewCommandTimeout();
319
357
 
320
358
  // apply initial values to Appium settings (if provided)
321
359
  if (driverInstance.isW3CProtocol() && !_.isEmpty(w3cSettings)) {
322
- this.log.info(`Applying the initial values to Appium settings parsed from W3C caps: ` +
323
- JSON.stringify(w3cSettings));
360
+ this.log.info(
361
+ `Applying the initial values to Appium settings parsed from W3C caps: ` +
362
+ JSON.stringify(w3cSettings)
363
+ );
324
364
  await driverInstance.updateSettings(w3cSettings);
325
365
  } else if (driverInstance.isMjsonwpProtocol() && !_.isEmpty(jwpSettings)) {
326
- this.log.info(`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
327
- JSON.stringify(jwpSettings));
366
+ this.log.info(
367
+ `Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
368
+ JSON.stringify(jwpSettings)
369
+ );
328
370
  await driverInstance.updateSettings(jwpSettings);
329
371
  }
330
372
  } catch (error) {
@@ -336,22 +378,31 @@ class AppiumDriver extends DriverCore {
336
378
 
337
379
  return {
338
380
  protocol,
339
- value: [innerSessionId, dCaps, protocol]
381
+ value: [innerSessionId, dCaps, protocol],
340
382
  };
341
383
  }
342
384
 
343
- attachUnexpectedShutdownHandler (driver, innerSessionId) {
385
+ /**
386
+ *
387
+ * @param {Driver} driver
388
+ * @param {string} innerSessionId
389
+ */
390
+ attachUnexpectedShutdownHandler(driver, innerSessionId) {
344
391
  const onShutdown = (cause = new Error('Unknown error')) => {
345
392
  this.log.warn(`Ending session, cause was '${cause.message}'`);
346
393
 
347
394
  if (this.sessionPlugins[innerSessionId]) {
348
395
  for (const plugin of this.sessionPlugins[innerSessionId]) {
349
396
  if (_.isFunction(plugin.onUnexpectedShutdown)) {
350
- this.log.debug(`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`);
397
+ this.log.debug(
398
+ `Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`
399
+ );
351
400
  try {
352
401
  plugin.onUnexpectedShutdown(driver, cause);
353
402
  } catch (e) {
354
- this.log.warn(`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`);
403
+ this.log.warn(
404
+ `Got an error when running plugin ${plugin.name} shutdown handler: ${e}`
405
+ );
355
406
  }
356
407
  } else {
357
408
  this.log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
@@ -367,24 +418,31 @@ class AppiumDriver extends DriverCore {
367
418
  if (_.isFunction(driver.onUnexpectedShutdown)) {
368
419
  driver.onUnexpectedShutdown(onShutdown);
369
420
  } else {
370
- this.log.warn(`Failed to attach the unexpected shutdown listener. ` +
371
- `Is 'onUnexpectedShutdown' method available for '${driver.constructor.name}'?`);
421
+ this.log.warn(
422
+ `Failed to attach the unexpected shutdown listener. ` +
423
+ `Is 'onUnexpectedShutdown' method available for '${driver.constructor.name}'?`
424
+ );
372
425
  }
373
426
  }
374
427
 
375
428
  /**
376
429
  *
377
- * @param {import('../types/extension').DriverClass} InnerDriver
430
+ * @param {DriverClass} InnerDriver
378
431
  * @returns {Promise<DriverData[]>}}
379
432
  */
380
- async curSessionDataForDriver (InnerDriver) { // eslint-disable-line require-await
381
- const data = _.compact(_.values(this.sessions)
382
- .filter((s) => s.constructor.name === InnerDriver.name)
383
- .map((s) => s.driverData));
433
+ // eslint-disable-next-line require-await
434
+ async curSessionDataForDriver(InnerDriver) {
435
+ const data = _.compact(
436
+ _.values(this.sessions)
437
+ .filter((s) => s.constructor.name === InnerDriver.name)
438
+ .map((s) => s.driverData)
439
+ );
384
440
  for (const datum of data) {
385
441
  if (!datum) {
386
- throw new Error(`Problem getting session data for driver type ` +
387
- `${InnerDriver.name}; does it implement 'get driverData'?`);
442
+ throw new Error(
443
+ `Problem getting session data for driver type ` +
444
+ `${InnerDriver.name}; does it implement 'get driverData'?`
445
+ );
388
446
  }
389
447
  }
390
448
  return data;
@@ -393,7 +451,7 @@ class AppiumDriver extends DriverCore {
393
451
  /**
394
452
  * @param {string} sessionId
395
453
  */
396
- async deleteSession (sessionId) {
454
+ async deleteSession(sessionId) {
397
455
  let protocol;
398
456
  try {
399
457
  let otherSessionsData;
@@ -403,8 +461,10 @@ class AppiumDriver extends DriverCore {
403
461
  }
404
462
  const curConstructorName = this.sessions[sessionId].constructor.name;
405
463
  otherSessionsData = _.toPairs(this.sessions)
406
- .filter(([key, value]) => value.constructor.name === curConstructorName && key !== sessionId)
407
- .map(([, value]) => value.driverData);
464
+ .filter(
465
+ ([key, value]) => value.constructor.name === curConstructorName && key !== sessionId
466
+ )
467
+ .map(([, value]) => value.driverData);
408
468
  const dstSession = this.sessions[sessionId];
409
469
  protocol = dstSession.protocol;
410
470
  this.log.info(`Removing session ${sessionId} from our master session list`);
@@ -433,20 +493,19 @@ class AppiumDriver extends DriverCore {
433
493
  }
434
494
  }
435
495
 
436
- async deleteAllSessions (opts = {}) {
496
+ async deleteAllSessions(opts = {}) {
437
497
  const sessionsCount = _.size(this.sessions);
438
498
  if (0 === sessionsCount) {
439
499
  this.log.debug('There are no active sessions for cleanup');
440
500
  return;
441
501
  }
442
502
 
443
- const {
444
- force = false,
445
- reason,
446
- } = opts;
503
+ const {force = false, reason} = opts;
447
504
  this.log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
448
505
  const cleanupPromises = force
449
- ? _.values(this.sessions).map((drv) => drv.startUnexpectedShutdown(reason && new Error(reason)))
506
+ ? _.values(this.sessions).map((drv) =>
507
+ drv.startUnexpectedShutdown(reason && new Error(reason))
508
+ )
450
509
  : _.keys(this.sessions).map((id) => this.deleteSession(id));
451
510
  for (const cleanupPromise of cleanupPromises) {
452
511
  try {
@@ -463,7 +522,7 @@ class AppiumDriver extends DriverCore {
463
522
  * @param {?string} sessionId - the sessionId (or null) to use to find plugins
464
523
  * @returns {Array} - array of plugin instances
465
524
  */
466
- pluginsForSession (sessionId = null) {
525
+ pluginsForSession(sessionId = null) {
467
526
  if (sessionId) {
468
527
  if (!this.sessionPlugins[sessionId]) {
469
528
  this.sessionPlugins[sessionId] = this.createPluginInstances();
@@ -487,29 +546,36 @@ class AppiumDriver extends DriverCore {
487
546
  * @param {?string} sessionId - the particular session for which to find a plugin, or null if
488
547
  * sessionless
489
548
  */
490
- pluginsToHandleCmd (cmd, sessionId = null) {
549
+ pluginsToHandleCmd(cmd, sessionId = null) {
491
550
  // to handle a given command, a plugin should either implement that command as a plugin
492
551
  // instance method or it should implement a generic 'handle' method
493
- return this.pluginsForSession(sessionId)
494
- .filter((p) => _.isFunction(p[cmd]) || _.isFunction(p.handle));
552
+ return this.pluginsForSession(sessionId).filter(
553
+ (p) => _.isFunction(p[cmd]) || _.isFunction(p.handle)
554
+ );
495
555
  }
496
556
 
497
- createPluginInstances () {
498
- return this.pluginClasses.map((PluginClass) => {
499
- const name = PluginClass.pluginName;
500
- const plugin = new PluginClass(name);
501
- this.assignCliArgsToExtension('plugin', name, plugin);
502
- return plugin;
503
- });
557
+ /**
558
+ * Creates instances of all of the enabled Plugin classes
559
+ * @returns {Plugin[]}
560
+ */
561
+ createPluginInstances() {
562
+ /** @type {Plugin[]} */
563
+ const pluginInstances = [];
564
+ for (const [PluginClass, name] of this.pluginClasses.entries()) {
565
+ const cliArgs = this.getCliArgsForPlugin(name);
566
+ const plugin = new PluginClass(name, cliArgs);
567
+ pluginInstances.push(plugin);
568
+ }
569
+ return pluginInstances;
504
570
  }
505
571
 
506
572
  /**
507
573
  *
508
574
  * @param {string} cmd
509
575
  * @param {...any} args
510
- * @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<import('@appium/types').Driver['executeCommand']>>}
576
+ * @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<Driver['executeCommand']>>}
511
577
  */
512
- async executeCommand (cmd, ...args) {
578
+ async executeCommand(cmd, ...args) {
513
579
  // We have basically three cases for how to handle commands:
514
580
  // 1. handle getStatus (we do this as a special out of band case so it doesn't get added to an
515
581
  // execution queue, and can be called while e.g. createSession is in progress)
@@ -531,7 +597,6 @@ class AppiumDriver extends DriverCore {
531
597
  args.pop();
532
598
  }
533
599
 
534
-
535
600
  // first do some error checking. If we're requesting a session command execution, then make
536
601
  // sure that session actually exists on the session driver, and set the session driver itself
537
602
  let sessionId = null;
@@ -584,8 +649,11 @@ class AppiumDriver extends DriverCore {
584
649
  if (!dstSession.proxyCommand) {
585
650
  throw new NoDriverProxyCommandError();
586
651
  }
587
- return await dstSession.proxyCommand(reqForProxy.originalUrl, reqForProxy.method,
588
- reqForProxy.body);
652
+ return await dstSession.proxyCommand(
653
+ reqForProxy.originalUrl,
654
+ reqForProxy.method,
655
+ reqForProxy.body
656
+ );
589
657
  }
590
658
 
591
659
  if (isGetStatus) {
@@ -604,7 +672,12 @@ class AppiumDriver extends DriverCore {
604
672
 
605
673
  // now take our default behavior, wrap it with any number of plugin behaviors, and run it
606
674
  const wrappedCmd = this.wrapCommandWithPlugins({
607
- driver, cmd, args, plugins, cmdHandledBy, next: defaultBehavior
675
+ driver,
676
+ cmd,
677
+ args,
678
+ plugins,
679
+ cmdHandledBy,
680
+ next: defaultBehavior,
608
681
  });
609
682
  const res = await this.executeWrappedCommand({wrappedCmd, protocol});
610
683
 
@@ -617,8 +690,10 @@ class AppiumDriver extends DriverCore {
617
690
  // their createSession method and other instance methods
618
691
  if (cmd === CREATE_SESSION_COMMAND && this.sessionlessPlugins.length && !res.error) {
619
692
  const sessionId = _.first(res.value);
620
- this.log.info(`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
621
- `to session ID ${sessionId}`);
693
+ this.log.info(
694
+ `Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
695
+ `to session ID ${sessionId}`
696
+ );
622
697
  this.sessionPlugins[sessionId] = this.sessionlessPlugins;
623
698
  this.sessionlessPlugins = [];
624
699
  }
@@ -626,8 +701,9 @@ class AppiumDriver extends DriverCore {
626
701
  return res;
627
702
  }
628
703
 
629
- wrapCommandWithPlugins ({driver, cmd, args, next, cmdHandledBy, plugins}) {
630
- plugins.length && this.log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
704
+ wrapCommandWithPlugins({driver, cmd, args, next, cmdHandledBy, plugins}) {
705
+ plugins.length &&
706
+ this.log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
631
707
 
632
708
  // now we can go through each plugin and wrap `next` around its own handler, passing the *old*
633
709
  // next in so that it can call it if it wants to
@@ -651,7 +727,7 @@ class AppiumDriver extends DriverCore {
651
727
  return next;
652
728
  }
653
729
 
654
- logPluginHandlerReport (plugins, {cmd, cmdHandledBy}) {
730
+ logPluginHandlerReport(plugins, {cmd, cmdHandledBy}) {
655
731
  if (!plugins.length) {
656
732
  return;
657
733
  }
@@ -665,14 +741,18 @@ class AppiumDriver extends DriverCore {
665
741
  const didHandle = Object.keys(cmdHandledBy).filter((k) => cmdHandledBy[k]);
666
742
  const didntHandle = Object.keys(cmdHandledBy).filter((k) => !cmdHandledBy[k]);
667
743
  if (didntHandle.length > 0) {
668
- this.log.info(`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
669
- `though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
670
- `command *was* handled by these: ${JSON.stringify(didHandle)}.`);
744
+ this.log.info(
745
+ `Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
746
+ `though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
747
+ `command *was* handled by these: ${JSON.stringify(didHandle)}.`
748
+ );
671
749
  }
672
750
  }
673
751
 
674
- async executeWrappedCommand ({wrappedCmd, protocol}) {
675
- let cmdRes, cmdErr, res = {};
752
+ async executeWrappedCommand({wrappedCmd, protocol}) {
753
+ let cmdRes,
754
+ cmdErr,
755
+ res = {};
676
756
  try {
677
757
  // At this point, `wrappedCmd` defines a whole sequence of plugin handlers, culminating in
678
758
  // our default handler. Whatever it returns is what we're going to want to send back to the
@@ -695,17 +775,17 @@ class AppiumDriver extends DriverCore {
695
775
  return res;
696
776
  }
697
777
 
698
- proxyActive (sessionId) {
778
+ proxyActive(sessionId) {
699
779
  const dstSession = this.sessions[sessionId];
700
780
  return dstSession && _.isFunction(dstSession.proxyActive) && dstSession.proxyActive(sessionId);
701
781
  }
702
782
 
703
- getProxyAvoidList (sessionId) {
783
+ getProxyAvoidList(sessionId) {
704
784
  const dstSession = this.sessions[sessionId];
705
785
  return dstSession ? dstSession.getProxyAvoidList() : [];
706
786
  }
707
787
 
708
- canProxy (sessionId) {
788
+ canProxy(sessionId) {
709
789
  const dstSession = this.sessions[sessionId];
710
790
  return dstSession && dstSession.canProxy(sessionId);
711
791
  }
@@ -713,7 +793,7 @@ class AppiumDriver extends DriverCore {
713
793
 
714
794
  // help decide which commands should be proxied to sub-drivers and which
715
795
  // should be handled by this, our umbrella driver
716
- function isAppiumDriverCommand (cmd) {
796
+ function isAppiumDriverCommand(cmd) {
717
797
  return !isSessionCommand(cmd) || cmd === DELETE_SESSION_COMMAND;
718
798
  }
719
799
 
@@ -727,26 +807,34 @@ export class NoDriverProxyCommandError extends Error {
727
807
  */
728
808
  code = 'APPIUMERR_NO_DRIVER_PROXYCOMMAND';
729
809
 
730
- constructor () {
731
- super(`The default behavior for this command was to proxy, but the driver ` +
732
- `did not have the 'proxyCommand' method defined. To fully support ` +
733
- `plugins, drivers should have 'proxyCommand' set to a jwpProxy object's ` +
734
- `'command()' method, in addition to the normal 'proxyReqRes'`);
810
+ constructor() {
811
+ super(
812
+ `The default behavior for this command was to proxy, but the driver ` +
813
+ `did not have the 'proxyCommand' method defined. To fully support ` +
814
+ `plugins, drivers should have 'proxyCommand' set to a jwpProxy object's ` +
815
+ `'command()' method, in addition to the normal 'proxyReqRes'`
816
+ );
735
817
  }
736
818
  }
737
819
 
738
- export { AppiumDriver };
820
+ export {AppiumDriver};
739
821
 
740
822
  /**
741
823
  * @typedef {import('@appium/types').ExternalDriver} ExternalDriver
824
+ * @typedef {import('@appium/types').Driver} Driver
825
+ * @typedef {import('@appium/types').DriverClass} DriverClass
742
826
  * @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
743
827
  * @typedef {import('@appium/types').DriverData} DriverData
744
828
  * @typedef {import('@appium/types').ServerArgs} DriverOpts
745
829
  * @typedef {import('@appium/types').Constraints} Constraints
746
830
  * @typedef {import('@appium/types').AppiumServer} AppiumServer
747
- * @typedef {import('../types').ExtensionType} ExtensionType
748
- * @typedef {import('../types/extension').PluginClass} PluginClass
831
+ * @typedef {import('@appium/types').ExtensionType} ExtensionType
749
832
  * @typedef {import('./extension/driver-config').DriverConfig} DriverConfig
833
+ * @typedef {import('@appium/types').Plugin} Plugin
834
+ * @typedef {import('@appium/types').PluginClass} PluginClass
835
+ * @typedef {import('@appium/types').PluginType} PluginType
836
+ * @typedef {import('@appium/types').DriverType} DriverType
837
+ * @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
750
838
  */
751
839
 
752
840
  /**
@@ -758,7 +846,3 @@ export { AppiumDriver };
758
846
  * @property {Error} [error]
759
847
  * @property {string} [protocol]
760
848
  */
761
-
762
- /**
763
- * @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
764
- */