appium 2.0.0-beta.25 → 2.0.0-beta.28

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 (191) hide show
  1. package/build/lib/appium.d.ts +215 -0
  2. package/build/lib/appium.d.ts.map +1 -0
  3. package/build/lib/appium.js +94 -101
  4. package/build/lib/cli/args.d.ts +20 -0
  5. package/build/lib/cli/args.d.ts.map +1 -0
  6. package/build/lib/cli/args.js +19 -39
  7. package/build/lib/cli/driver-command.d.ts +36 -0
  8. package/build/lib/cli/driver-command.d.ts.map +1 -0
  9. package/build/lib/cli/driver-command.js +10 -13
  10. package/build/lib/cli/extension-command.d.ts +345 -0
  11. package/build/lib/cli/extension-command.d.ts.map +1 -0
  12. package/build/lib/cli/extension-command.js +117 -94
  13. package/build/lib/cli/extension.d.ts +14 -0
  14. package/build/lib/cli/extension.d.ts.map +1 -0
  15. package/build/lib/cli/extension.js +14 -22
  16. package/build/lib/cli/parser.d.ts +79 -0
  17. package/build/lib/cli/parser.d.ts.map +1 -0
  18. package/build/lib/cli/parser.js +9 -19
  19. package/build/lib/cli/plugin-command.d.ts +39 -0
  20. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  21. package/build/lib/cli/plugin-command.js +9 -14
  22. package/build/lib/cli/utils.d.ts +29 -0
  23. package/build/lib/cli/utils.d.ts.map +1 -0
  24. package/build/lib/cli/utils.js +2 -4
  25. package/build/lib/config-file.d.ts +100 -0
  26. package/build/lib/config-file.d.ts.map +1 -0
  27. package/build/lib/config-file.js +2 -4
  28. package/build/lib/config.d.ts +40 -0
  29. package/build/lib/config.d.ts.map +1 -0
  30. package/build/lib/config.js +8 -7
  31. package/build/lib/constants.d.ts +48 -0
  32. package/build/lib/constants.d.ts.map +1 -0
  33. package/build/lib/constants.js +60 -0
  34. package/build/lib/extension/driver-config.d.ts +84 -0
  35. package/build/lib/extension/driver-config.d.ts.map +1 -0
  36. package/build/lib/extension/driver-config.js +190 -0
  37. package/build/lib/extension/extension-config.d.ts +170 -0
  38. package/build/lib/extension/extension-config.d.ts.map +1 -0
  39. package/build/lib/extension/extension-config.js +297 -0
  40. package/build/lib/extension/index.d.ts +39 -0
  41. package/build/lib/extension/index.d.ts.map +1 -0
  42. package/build/lib/extension/index.js +77 -0
  43. package/build/lib/extension/manifest.d.ts +174 -0
  44. package/build/lib/extension/manifest.d.ts.map +1 -0
  45. package/build/lib/extension/manifest.js +246 -0
  46. package/build/lib/extension/package-changed.d.ts +11 -0
  47. package/build/lib/extension/package-changed.d.ts.map +1 -0
  48. package/build/lib/extension/package-changed.js +68 -0
  49. package/build/lib/extension/plugin-config.d.ts +62 -0
  50. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  51. package/build/lib/extension/plugin-config.js +87 -0
  52. package/build/lib/grid-register.d.ts +10 -0
  53. package/build/lib/grid-register.d.ts.map +1 -0
  54. package/build/lib/grid-register.js +2 -4
  55. package/build/lib/logger.d.ts +3 -0
  56. package/build/lib/logger.d.ts.map +1 -0
  57. package/build/lib/logger.js +2 -4
  58. package/build/lib/logsink.d.ts +4 -0
  59. package/build/lib/logsink.d.ts.map +1 -0
  60. package/build/lib/logsink.js +2 -4
  61. package/build/lib/main.d.ts +51 -0
  62. package/build/lib/main.d.ts.map +1 -0
  63. package/build/lib/main.js +40 -68
  64. package/build/lib/schema/arg-spec.d.ts +143 -0
  65. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  66. package/build/lib/schema/arg-spec.js +11 -14
  67. package/build/lib/schema/cli-args.d.ts +19 -0
  68. package/build/lib/schema/cli-args.d.ts.map +1 -0
  69. package/build/lib/schema/cli-args.js +2 -4
  70. package/build/lib/schema/cli-transformers.d.ts +5 -0
  71. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  72. package/build/lib/schema/cli-transformers.js +2 -4
  73. package/build/lib/schema/index.d.ts +3 -0
  74. package/build/lib/schema/index.d.ts.map +1 -0
  75. package/build/lib/schema/index.js +2 -4
  76. package/build/lib/schema/keywords.d.ts +24 -0
  77. package/build/lib/schema/keywords.d.ts.map +1 -0
  78. package/build/lib/schema/keywords.js +2 -4
  79. package/build/lib/schema/schema.d.ts +259 -0
  80. package/build/lib/schema/schema.d.ts.map +1 -0
  81. package/build/lib/schema/schema.js +57 -39
  82. package/build/lib/utils.d.ts +66 -0
  83. package/build/lib/utils.d.ts.map +1 -0
  84. package/build/lib/utils.js +6 -35
  85. package/build/tsconfig.tsbuildinfo +1 -0
  86. package/lib/appium.js +188 -117
  87. package/lib/cli/args.js +19 -24
  88. package/lib/cli/driver-command.js +19 -8
  89. package/lib/cli/extension-command.js +314 -184
  90. package/lib/cli/extension.js +18 -16
  91. package/lib/cli/parser.js +7 -16
  92. package/lib/cli/plugin-command.js +16 -7
  93. package/lib/cli/utils.js +1 -1
  94. package/lib/config-file.js +6 -7
  95. package/lib/config.js +17 -12
  96. package/lib/constants.js +78 -0
  97. package/lib/extension/driver-config.js +249 -0
  98. package/lib/extension/extension-config.js +458 -0
  99. package/lib/extension/index.js +102 -0
  100. package/lib/extension/manifest.js +486 -0
  101. package/lib/extension/package-changed.js +63 -0
  102. package/lib/extension/plugin-config.js +113 -0
  103. package/lib/grid-register.js +4 -4
  104. package/lib/logsink.js +4 -0
  105. package/lib/main.js +54 -92
  106. package/lib/schema/arg-spec.js +11 -7
  107. package/lib/schema/cli-args.js +1 -1
  108. package/lib/schema/cli-transformers.js +0 -1
  109. package/lib/schema/keywords.js +1 -2
  110. package/lib/schema/schema.js +62 -31
  111. package/lib/utils.js +48 -45
  112. package/package.json +30 -24
  113. package/{postinstall.js → scripts/postinstall.js} +1 -1
  114. package/types/appium-manifest.d.ts +61 -0
  115. package/types/cli.d.ts +134 -0
  116. package/types/extension.d.ts +56 -0
  117. package/types/external-manifest.d.ts +58 -0
  118. package/types/index.d.ts +7 -0
  119. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  120. package/build/check-npm-pack-files.js +0 -23
  121. package/build/commands-yml/parse.js +0 -319
  122. package/build/commands-yml/validator.js +0 -130
  123. package/build/index.js +0 -19
  124. package/build/lib/appium-config.schema.json +0 -0
  125. package/build/lib/cli/npm.js +0 -220
  126. package/build/lib/driver-config.js +0 -100
  127. package/build/lib/drivers.js +0 -100
  128. package/build/lib/ext-config-io.js +0 -165
  129. package/build/lib/extension-config.js +0 -320
  130. package/build/lib/plugin-config.js +0 -69
  131. package/build/lib/plugins.js +0 -18
  132. package/build/lib/schema/appium-config-schema.js +0 -253
  133. package/build/postinstall.js +0 -90
  134. package/build/test/cli/cli-e2e-specs.js +0 -221
  135. package/build/test/cli/cli-helpers.js +0 -86
  136. package/build/test/cli/cli-specs.js +0 -71
  137. package/build/test/cli/fixtures/test-driver/package.json +0 -27
  138. package/build/test/cli/schema-args-specs.js +0 -48
  139. package/build/test/cli/schema-e2e-specs.js +0 -47
  140. package/build/test/config-e2e-specs.js +0 -112
  141. package/build/test/config-file-e2e-specs.js +0 -191
  142. package/build/test/config-file-specs.js +0 -281
  143. package/build/test/config-specs.js +0 -258
  144. package/build/test/driver-e2e-specs.js +0 -435
  145. package/build/test/driver-specs.js +0 -386
  146. package/build/test/ext-config-io-specs.js +0 -181
  147. package/build/test/extension-config-specs.js +0 -365
  148. package/build/test/fixtures/allow-feat.txt +0 -5
  149. package/build/test/fixtures/caps.json +0 -3
  150. package/build/test/fixtures/config/allow-insecure.txt +0 -3
  151. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
  152. package/build/test/fixtures/config/appium.config.bad.json +0 -32
  153. package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
  154. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
  155. package/build/test/fixtures/config/appium.config.good.js +0 -40
  156. package/build/test/fixtures/config/appium.config.good.json +0 -33
  157. package/build/test/fixtures/config/appium.config.good.yaml +0 -30
  158. package/build/test/fixtures/config/appium.config.invalid.json +0 -31
  159. package/build/test/fixtures/config/appium.config.security-array.json +0 -5
  160. package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
  161. package/build/test/fixtures/config/appium.config.security-path.json +0 -5
  162. package/build/test/fixtures/config/driver-fake.config.json +0 -8
  163. package/build/test/fixtures/config/nodeconfig.json +0 -3
  164. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  165. package/build/test/fixtures/default-args.js +0 -35
  166. package/build/test/fixtures/deny-feat.txt +0 -5
  167. package/build/test/fixtures/driver.schema.js +0 -20
  168. package/build/test/fixtures/extensions.yaml +0 -27
  169. package/build/test/fixtures/flattened-schema.js +0 -532
  170. package/build/test/fixtures/plugin.schema.js +0 -20
  171. package/build/test/fixtures/schema-with-extensions.js +0 -28
  172. package/build/test/grid-register-specs.js +0 -74
  173. package/build/test/helpers.js +0 -75
  174. package/build/test/logger-specs.js +0 -76
  175. package/build/test/npm-specs.js +0 -20
  176. package/build/test/parser-specs.js +0 -319
  177. package/build/test/plugin-e2e-specs.js +0 -316
  178. package/build/test/schema/arg-spec-specs.js +0 -70
  179. package/build/test/schema/cli-args-specs.js +0 -408
  180. package/build/test/schema/schema-specs.js +0 -407
  181. package/build/test/utils-specs.js +0 -288
  182. package/lib/cli/npm.js +0 -251
  183. package/lib/driver-config.js +0 -101
  184. package/lib/drivers.js +0 -84
  185. package/lib/ext-config-io.js +0 -287
  186. package/lib/extension-config.js +0 -366
  187. package/lib/plugin-config.js +0 -63
  188. package/lib/plugins.js +0 -13
  189. package/lib/schema/appium-config-schema.js +0 -287
  190. package/types/appium-config.d.ts +0 -197
  191. package/types/types.d.ts +0 -206
package/lib/appium.js CHANGED
@@ -1,16 +1,19 @@
1
+ /* eslint-disable no-unused-vars */
1
2
  import _ from 'lodash';
2
- import log from './logger';
3
3
  import { getBuildInfo, updateBuildInfo, APPIUM_VER } from './config';
4
- import { findMatchingDriver } from './drivers';
5
- import { BaseDriver, errors, isSessionCommand,
4
+ import { BaseDriver, DriverCore, errors, isSessionCommand,
6
5
  CREATE_SESSION_COMMAND, DELETE_SESSION_COMMAND, GET_STATUS_COMMAND
7
6
  } from '@appium/base-driver';
8
7
  import AsyncLock from 'async-lock';
9
8
  import { parseCapsForInnerDriver, pullSettings } from './utils';
10
- import { util } from '@appium/support';
9
+ import { util, node, logger } from '@appium/support';
11
10
  import { getDefaultsForExtension } from './schema';
12
11
 
13
- const desiredCapabilityConstraints = {
12
+ /**
13
+ * Invariant set of base constraints
14
+ * @type {Readonly<Constraints>}
15
+ */
16
+ const desiredCapabilityConstraints = Object.freeze({
14
17
  automationName: {
15
18
  presence: true,
16
19
  isString: true,
@@ -19,54 +22,99 @@ const desiredCapabilityConstraints = {
19
22
  presence: true,
20
23
  isString: true,
21
24
  },
22
- };
25
+ });
23
26
 
24
27
  const sessionsListGuard = new AsyncLock();
25
28
  const pendingDriversGuard = new AsyncLock();
26
29
 
27
- class AppiumDriver extends BaseDriver {
28
- constructor (args) {
30
+ /**
31
+ * @implements {SessionHandler}
32
+ */
33
+ class AppiumDriver extends DriverCore {
34
+ /**
35
+ * Access to sessions list must be guarded with a Semaphore, because
36
+ * it might be changed by other async calls at any time
37
+ * It is not recommended to access this property directly from the outside
38
+ * @type {Record<string,ExternalDriver>}
39
+ */
40
+ sessions = {};
41
+
42
+ /**
43
+ * Access to pending drivers list must be guarded with a Semaphore, because
44
+ * it might be changed by other async calls at any time
45
+ * It is not recommended to access this property directly from the outside
46
+ * @type {Record<string,ExternalDriver[]>}
47
+ */
48
+ pendingDrivers = {};
49
+
50
+ /**
51
+ * Note that {@linkcode AppiumDriver} has no `newCommandTimeout` method.
52
+ * `AppiumDriver` does not set and observe its own timeouts; individual
53
+ * sessions (managed drivers) do instead.
54
+ */
55
+ newCommandTimeoutMs = 0;
56
+
57
+ /**
58
+ * List of active plugins
59
+ * @type {PluginClass[]}
60
+ */
61
+ pluginClasses = [];
62
+
63
+ /**
64
+ * map of sessions to actual plugin instances per session
65
+ * @type {Record<string,InstanceType<PluginClass>[]>}
66
+ */
67
+ sessionPlugins = {};
68
+
69
+ /**
70
+ * some commands are sessionless, so we need a set of plugins for them
71
+ * @type {InstanceType<PluginClass>[]}
72
+ */
73
+ sessionlessPlugins = [];;
74
+
75
+ /** @type {DriverConfig} */
76
+ driverConfig;
77
+
78
+ /** @type {AppiumServer} */
79
+ server;
80
+
81
+ /**
82
+ * @param {DriverOpts} opts
83
+ */
84
+ constructor (opts) {
29
85
  // It is necessary to set `--tmp` here since it should be set to
30
86
  // process.env.APPIUM_TMP_DIR once at an initial point in the Appium lifecycle.
31
87
  // The process argument will be referenced by BaseDriver.
32
88
  // Please call @appium/support.tempDir module to apply this benefit.
33
- if (args.tmpDir) {
34
- process.env.APPIUM_TMP_DIR = args.tmpDir;
89
+ if (opts.tmpDir) {
90
+ process.env.APPIUM_TMP_DIR = opts.tmpDir;
35
91
  }
36
92
 
37
- super(args);
93
+ super(opts);
38
94
 
39
95
  this.desiredCapConstraints = desiredCapabilityConstraints;
40
96
 
41
- // the main Appium Driver has no new command timeout
42
- this.newCommandTimeoutMs = 0;
43
-
44
- this.args = {...args};
45
-
46
- // Access to sessions list must be guarded with a Semaphore, because
47
- // it might be changed by other async calls at any time
48
- // It is not recommended to access this property directly from the outside
49
- this.sessions = {};
50
-
51
- // Access to pending drivers list must be guarded with a Semaphore, because
52
- // it might be changed by other async calls at any time
53
- // It is not recommended to access this property directly from the outside
54
- this.pendingDrivers = {};
55
-
56
- /** @type {PluginExtensionClass[]} */
57
- this.pluginClasses = []; // list of which plugins are active
58
- this.sessionPlugins = {}; // map of sessions to actual plugin instances per session
59
- this.sessionlessPlugins = []; // some commands are sessionless, so we need a set of plugins for them
97
+ this.args = {...opts};
60
98
 
61
99
  // allow this to happen in the background, so no `await`
62
- updateBuildInfo();
100
+ // catch this to avoid an unhandled rejection
101
+ // eslint-disable-next-line promise/prefer-await-to-then,promise/prefer-await-to-callbacks
102
+ updateBuildInfo().catch((err) => {
103
+ this.log.debug(err);
104
+ });
63
105
  }
64
106
 
65
- /** @type {import('./driver-config').default|undefined} */
66
- driverConfig;
107
+ /**
108
+ * Retrieves logger instance for the current umbrella driver instance
109
+ */
110
+ get log () {
111
+ if (!this._log) {
112
+ const instanceName = `${this.constructor.name}@${node.getObjectId(this).substring(0, 4)}`;
113
+ this._log = logger.getLogger(instanceName);
114
+ }
115
+ return this._log;
116
+ }
67
117
 
68
- /** @type {import('express').Express|undefined} */
69
- server;
70
118
 
71
119
  /**
72
120
  * Cancel commands queueing for the umbrella Appium driver
@@ -97,41 +145,33 @@ class AppiumDriver extends BaseDriver {
97
145
  }
98
146
 
99
147
  printNewSessionAnnouncement (driverName, driverVersion, driverBaseVersion) {
100
- log.info(driverVersion
148
+ this.log.info(driverVersion
101
149
  ? `Appium v${APPIUM_VER} creating new ${driverName} (v${driverVersion}) session`
102
150
  : `Appium v${APPIUM_VER} creating new ${driverName} session`
103
151
  );
104
- log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
105
- log.info(AppiumDriver.baseVersion
152
+ this.log.info(`Checking BaseDriver versions for Appium and ${driverName}`);
153
+ this.log.info(AppiumDriver.baseVersion
106
154
  ? `Appium's BaseDriver version is ${AppiumDriver.baseVersion}`
107
155
  : `Could not determine Appium's BaseDriver version`
108
156
  );
109
- log.info(driverBaseVersion
157
+ this.log.info(driverBaseVersion
110
158
  ? `${driverName}'s BaseDriver version is ${driverBaseVersion}`
111
159
  : `Could not determine ${driverName}'s BaseDriver version`
112
160
  );
113
161
  }
114
162
 
115
- /**
116
- * This is just an alias for driver.js's method, which is necessary for
117
- * mocking in the test suite
118
- */
119
- _findMatchingDriver (...args) {
120
- return findMatchingDriver(...args);
121
- }
122
-
123
163
  /**
124
164
  * Validate and assign CLI args for a driver or plugin
125
165
  *
126
166
  * If the extension has provided a schema, validation has already happened.
127
167
  *
128
168
  * Any arg which is equal to its default value will not be assigned to the extension.
129
- * @param {import('./ext-config-io').ExtensionType} extType 'driver' or 'plugin'
169
+ * @param {ExtensionType} extType 'driver' or 'plugin'
130
170
  * @param {string} extName the name of the extension
131
171
  * @param {Object} extInstance the driver or plugin instance
132
172
  */
133
173
  assignCliArgsToExtension (extType, extName, extInstance) {
134
- const allCliArgsForExt = this.args[extType]?.[extName];
174
+ const allCliArgsForExt = /** @type {Record<string,unknown>|undefined} */(this.args[extType]?.[extName]);
135
175
  if (!_.isEmpty(allCliArgsForExt)) {
136
176
  const defaults = getDefaultsForExtension(extType, extName);
137
177
  const cliArgs = _.isEmpty(defaults)
@@ -145,24 +185,26 @@ class AppiumDriver extends BaseDriver {
145
185
 
146
186
  /**
147
187
  * Create a new session
148
- * @param {Object} jsonwpCaps JSONWP formatted desired capabilities
149
- * @param {Object} reqCaps Required capabilities (JSONWP standard)
150
- * @param {Object} w3cCapabilities W3C capabilities
151
- * @return {Array} Unique session ID and capabilities
188
+ * @param {W3CCapabilities} jsonwpCaps JSONWP formatted desired capabilities
189
+ * @param {W3CCapabilities} reqCaps Required capabilities (JSONWP standard)
190
+ * @param {W3CCapabilities} w3cCapabilities W3C capabilities
191
+ * @param {import('@appium/types').DriverData[]} [driverData]
152
192
  */
153
- async createSession (jsonwpCaps, reqCaps, w3cCapabilities) {
193
+ async createSession (jsonwpCaps, reqCaps, w3cCapabilities, driverData) {
154
194
  const defaultCapabilities = _.cloneDeep(this.args.defaultCapabilities);
155
195
  const defaultSettings = pullSettings(defaultCapabilities);
156
196
  jsonwpCaps = _.cloneDeep(jsonwpCaps);
157
- const jwpSettings = Object.assign({}, defaultSettings, pullSettings(jsonwpCaps));
197
+ const jwpSettings = {...defaultSettings, ...pullSettings(jsonwpCaps)};
158
198
  w3cCapabilities = _.cloneDeep(w3cCapabilities);
159
199
  // It is possible that the client only provides caps using JSONWP standard,
160
200
  // although firstMatch/alwaysMatch properties are still present.
161
201
  // In such case we assume the client understands W3C protocol and merge the given
162
202
  // JSONWP caps to W3C caps
163
- const w3cSettings = Object.assign({}, jwpSettings);
164
- Object.assign(w3cSettings, pullSettings((w3cCapabilities || {}).alwaysMatch || {}));
165
- for (const firstMatchEntry of ((w3cCapabilities || {}).firstMatch || [])) {
203
+ const w3cSettings = {
204
+ ...jwpSettings,
205
+ ...pullSettings((w3cCapabilities ?? {}).alwaysMatch ?? {})
206
+ };
207
+ for (const firstMatchEntry of ((w3cCapabilities ?? {}).firstMatch ?? [])) {
166
208
  Object.assign(w3cSettings, pullSettings(firstMatchEntry));
167
209
  }
168
210
 
@@ -177,9 +219,9 @@ class AppiumDriver extends BaseDriver {
177
219
  defaultCapabilities
178
220
  );
179
221
 
180
- const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities, error} = parsedCaps;
222
+ const {desiredCaps, processedJsonwpCapabilities, processedW3CCapabilities} = /** @type {import('./utils').ParsedDriverCaps} */(parsedCaps);
181
223
  protocol = parsedCaps.protocol;
182
-
224
+ const error = /** @type {import('./utils').InvalidCaps} */(parsedCaps).error;
183
225
  // If the parsing of the caps produced an error, throw it in here
184
226
  if (error) {
185
227
  throw error;
@@ -189,14 +231,21 @@ class AppiumDriver extends BaseDriver {
189
231
  driver: InnerDriver,
190
232
  version: driverVersion,
191
233
  driverName
192
- } = this._findMatchingDriver(this.driverConfig, desiredCaps);
234
+ } = this.driverConfig.findMatchingDriver(desiredCaps);
193
235
  this.printNewSessionAnnouncement(InnerDriver.name, driverVersion, InnerDriver.baseVersion);
194
236
 
195
237
  if (this.args.sessionOverride) {
196
238
  await this.deleteAllSessions();
197
239
  }
198
240
 
199
- let runningDriversData, otherPendingDriversData;
241
+ /**
242
+ * @type {DriverData[]}
243
+ */
244
+ let runningDriversData = [];
245
+ /**
246
+ * @type {DriverData[]}
247
+ */
248
+ let otherPendingDriversData = [];
200
249
 
201
250
  const driverInstance = new InnerDriver(this.args, true);
202
251
 
@@ -205,21 +254,21 @@ class AppiumDriver extends BaseDriver {
205
254
  // could have been set by a malicious user via capabilities, whereas we
206
255
  // want a guarantee the values were set by the appium server admin
207
256
  if (this.args.relaxedSecurityEnabled) {
208
- log.info(`Applying relaxed security to '${InnerDriver.name}' as per ` +
209
- `server command line argument. All insecure features will be ` +
210
- `enabled unless explicitly disabled by --deny-insecure`);
257
+ this.log.info(`Applying relaxed security to '${InnerDriver.name}' as per ` +
258
+ `server command line argument. All insecure features will be ` +
259
+ `enabled unless explicitly disabled by --deny-insecure`);
211
260
  driverInstance.relaxedSecurityEnabled = true;
212
261
  }
213
262
 
214
263
  if (!_.isEmpty(this.args.denyInsecure)) {
215
- log.info('Explicitly preventing use of insecure features:');
216
- this.args.denyInsecure.map((a) => log.info(` ${a}`));
264
+ this.log.info('Explicitly preventing use of insecure features:');
265
+ this.args.denyInsecure.map((a) => this.log.info(` ${a}`));
217
266
  driverInstance.denyInsecure = this.args.denyInsecure;
218
267
  }
219
268
 
220
269
  if (!_.isEmpty(this.args.allowInsecure)) {
221
- log.info('Explicitly enabling use of insecure features:');
222
- this.args.allowInsecure.map((a) => log.info(` ${a}`));
270
+ this.log.info('Explicitly enabling use of insecure features:');
271
+ this.args.allowInsecure.map((a) => this.log.info(` ${a}`));
223
272
  driverInstance.allowInsecure = this.args.allowInsecure;
224
273
  }
225
274
 
@@ -229,21 +278,17 @@ class AppiumDriver extends BaseDriver {
229
278
 
230
279
 
231
280
  // This assignment is required for correct web sockets functionality inside the driver
232
- driverInstance.server = this.server;
233
-
234
281
  // Drivers/plugins might also want to know where they are hosted
235
- driverInstance.serverHost = this.args.address;
236
- driverInstance.serverPort = this.args.port;
237
- driverInstance.serverPath = this.args.basePath;
282
+ driverInstance.assignServer(this.server, this.args.address, this.args.port, this.args.basePath);
238
283
 
239
284
  try {
240
- runningDriversData = await this.curSessionDataForDriver(InnerDriver);
285
+ runningDriversData = await this.curSessionDataForDriver(InnerDriver) ?? [];
241
286
  } catch (e) {
242
287
  throw new errors.SessionNotCreatedError(e.message);
243
288
  }
244
289
  await pendingDriversGuard.acquire(AppiumDriver.name, () => {
245
290
  this.pendingDrivers[InnerDriver.name] = this.pendingDrivers[InnerDriver.name] || [];
246
- otherPendingDriversData = this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData);
291
+ otherPendingDriversData = _.compact(this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData));
247
292
  this.pendingDrivers[InnerDriver.name].push(driverInstance);
248
293
  });
249
294
 
@@ -266,19 +311,19 @@ class AppiumDriver extends BaseDriver {
266
311
 
267
312
  this.attachUnexpectedShutdownHandler(driverInstance, innerSessionId);
268
313
 
269
- log.info(`New ${InnerDriver.name} session created successfully, session ` +
270
- `${innerSessionId} added to master session list`);
314
+ this.log.info(`New ${InnerDriver.name} session created successfully, session ` +
315
+ `${innerSessionId} added to master session list`);
271
316
 
272
317
  // set the New Command Timeout for the inner driver
273
318
  driverInstance.startNewCommandTimeout();
274
319
 
275
320
  // apply initial values to Appium settings (if provided)
276
321
  if (driverInstance.isW3CProtocol() && !_.isEmpty(w3cSettings)) {
277
- log.info(`Applying the initial values to Appium settings parsed from W3C caps: ` +
322
+ this.log.info(`Applying the initial values to Appium settings parsed from W3C caps: ` +
278
323
  JSON.stringify(w3cSettings));
279
324
  await driverInstance.updateSettings(w3cSettings);
280
325
  } else if (driverInstance.isMjsonwpProtocol() && !_.isEmpty(jwpSettings)) {
281
- log.info(`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
326
+ this.log.info(`Applying the initial values to Appium settings parsed from MJSONWP caps: ` +
282
327
  JSON.stringify(jwpSettings));
283
328
  await driverInstance.updateSettings(jwpSettings);
284
329
  }
@@ -297,24 +342,24 @@ class AppiumDriver extends BaseDriver {
297
342
 
298
343
  attachUnexpectedShutdownHandler (driver, innerSessionId) {
299
344
  const onShutdown = (cause = new Error('Unknown error')) => {
300
- log.warn(`Ending session, cause was '${cause.message}'`);
345
+ this.log.warn(`Ending session, cause was '${cause.message}'`);
301
346
 
302
347
  if (this.sessionPlugins[innerSessionId]) {
303
348
  for (const plugin of this.sessionPlugins[innerSessionId]) {
304
349
  if (_.isFunction(plugin.onUnexpectedShutdown)) {
305
- log.debug(`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`);
350
+ this.log.debug(`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`);
306
351
  try {
307
352
  plugin.onUnexpectedShutdown(driver, cause);
308
353
  } catch (e) {
309
- log.warn(`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`);
354
+ this.log.warn(`Got an error when running plugin ${plugin.name} shutdown handler: ${e}`);
310
355
  }
311
356
  } else {
312
- log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
357
+ this.log.debug(`Plugin ${plugin.name} does not define an unexpected shutdown handler`);
313
358
  }
314
359
  }
315
360
  }
316
361
 
317
- log.info(`Removing session '${innerSessionId}' from our master session list`);
362
+ this.log.info(`Removing session '${innerSessionId}' from our master session list`);
318
363
  delete this.sessions[innerSessionId];
319
364
  delete this.sessionPlugins[innerSessionId];
320
365
  };
@@ -322,16 +367,21 @@ class AppiumDriver extends BaseDriver {
322
367
  if (_.isFunction(driver.onUnexpectedShutdown)) {
323
368
  driver.onUnexpectedShutdown(onShutdown);
324
369
  } else {
325
- log.warn(`Failed to attach the unexpected shutdown listener. ` +
370
+ this.log.warn(`Failed to attach the unexpected shutdown listener. ` +
326
371
  `Is 'onUnexpectedShutdown' method available for '${driver.constructor.name}'?`);
327
372
  }
328
373
  }
329
374
 
375
+ /**
376
+ *
377
+ * @param {import('../types/extension').DriverClass} InnerDriver
378
+ * @returns {Promise<DriverData[]>}}
379
+ */
330
380
  async curSessionDataForDriver (InnerDriver) {
331
381
  const sessions = await sessionsListGuard.acquire(AppiumDriver.name, () => this.sessions);
332
- const data = _.values(sessions)
382
+ const data = _.compact(_.values(sessions)
333
383
  .filter((s) => s.constructor.name === InnerDriver.name)
334
- .map((s) => s.driverData);
384
+ .map((s) => s.driverData));
335
385
  for (let datum of data) {
336
386
  if (!datum) {
337
387
  throw new Error(`Problem getting session data for driver type ` +
@@ -342,12 +392,14 @@ class AppiumDriver extends BaseDriver {
342
392
  return data;
343
393
  }
344
394
 
395
+ /**
396
+ * @param {string} sessionId
397
+ */
345
398
  async deleteSession (sessionId) {
346
399
  let protocol;
347
400
  try {
348
- let otherSessionsData = null;
349
- let dstSession = null;
350
- await sessionsListGuard.acquire(AppiumDriver.name, () => {
401
+ let otherSessionsData;
402
+ const dstSession = await sessionsListGuard.acquire(AppiumDriver.name, () => {
351
403
  if (!this.sessions[sessionId]) {
352
404
  return;
353
405
  }
@@ -355,21 +407,27 @@ class AppiumDriver extends BaseDriver {
355
407
  otherSessionsData = _.toPairs(this.sessions)
356
408
  .filter(([key, value]) => value.constructor.name === curConstructorName && key !== sessionId)
357
409
  .map(([, value]) => value.driverData);
358
- dstSession = this.sessions[sessionId];
410
+ const dstSession = this.sessions[sessionId];
359
411
  protocol = dstSession.protocol;
360
- log.info(`Removing session ${sessionId} from our master session list`);
412
+ this.log.info(`Removing session ${sessionId} from our master session list`);
361
413
  // regardless of whether the deleteSession completes successfully or not
362
414
  // make the session unavailable, because who knows what state it might
363
415
  // be in otherwise
364
416
  delete this.sessions[sessionId];
365
417
  delete this.sessionPlugins[sessionId];
418
+ return dstSession;
366
419
  });
420
+ // this may not be correct, but if `dstSession` was falsy, the call to `deleteSession()` would
421
+ // throw anyway.
422
+ if (!dstSession) {
423
+ throw new Error('Session not found');
424
+ }
367
425
  return {
368
426
  protocol,
369
427
  value: await dstSession.deleteSession(sessionId, otherSessionsData),
370
428
  };
371
429
  } catch (e) {
372
- log.error(`Had trouble ending session ${sessionId}: ${e.message}`);
430
+ this.log.error(`Had trouble ending session ${sessionId}: ${e.message}`);
373
431
  return {
374
432
  protocol,
375
433
  error: e,
@@ -380,7 +438,7 @@ class AppiumDriver extends BaseDriver {
380
438
  async deleteAllSessions (opts = {}) {
381
439
  const sessionsCount = _.size(this.sessions);
382
440
  if (0 === sessionsCount) {
383
- log.debug('There are no active sessions for cleanup');
441
+ this.log.debug('There are no active sessions for cleanup');
384
442
  return;
385
443
  }
386
444
 
@@ -388,7 +446,7 @@ class AppiumDriver extends BaseDriver {
388
446
  force = false,
389
447
  reason,
390
448
  } = opts;
391
- log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
449
+ this.log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
392
450
  const cleanupPromises = force
393
451
  ? _.values(this.sessions).map((drv) => drv.startUnexpectedShutdown(reason && new Error(reason)))
394
452
  : _.keys(this.sessions).map((id) => this.deleteSession(id));
@@ -396,7 +454,7 @@ class AppiumDriver extends BaseDriver {
396
454
  try {
397
455
  await cleanupPromise;
398
456
  } catch (e) {
399
- log.debug(e);
457
+ this.log.debug(e);
400
458
  }
401
459
  }
402
460
  }
@@ -447,6 +505,12 @@ class AppiumDriver extends BaseDriver {
447
505
  });
448
506
  }
449
507
 
508
+ /**
509
+ *
510
+ * @param {string} cmd
511
+ * @param {...any} args
512
+ * @returns {Promise<{value: any, error?: Error, protocol: string} | import('type-fest').AsyncReturnType<import('@appium/types').Driver['executeCommand']>>}
513
+ */
450
514
  async executeCommand (cmd, ...args) {
451
515
  // We have basically three cases for how to handle commands:
452
516
  // 1. handle getStatus (we do this as a special out of band case so it doesn't get added to an
@@ -476,6 +540,7 @@ class AppiumDriver extends BaseDriver {
476
540
  let sessionId = null;
477
541
  let dstSession = null;
478
542
  let protocol = null;
543
+ /** @type {this | ExternalDriver} */
479
544
  let driver = this;
480
545
  if (isSessionCmd) {
481
546
  sessionId = _.last(args);
@@ -509,7 +574,7 @@ class AppiumDriver extends BaseDriver {
509
574
  // if we're running with plugins, make sure we log that the default behavior is actually
510
575
  // happening so we can tell when the plugin call chain is unwrapping to the default behavior
511
576
  // if that's what happens
512
- plugins.length && log.info(`Executing default handling behavior for command '${cmd}'`);
577
+ plugins.length && this.log.info(`Executing default handling behavior for command '${cmd}'`);
513
578
 
514
579
  // if we make it here, we know that the default behavior is handled
515
580
  cmdHandledBy.default = true;
@@ -533,7 +598,7 @@ class AppiumDriver extends BaseDriver {
533
598
  if (isUmbrellaCmd) {
534
599
  // some commands, like deleteSession, we want to make sure to handle on *this* driver,
535
600
  // not the platform driver
536
- return await super.executeCommand(cmd, ...args);
601
+ return await BaseDriver.prototype.executeCommand.call(this, cmd, ...args);
537
602
  }
538
603
 
539
604
  // here we know that we are executing a session command, and have a valid session driver
@@ -555,8 +620,8 @@ class AppiumDriver extends BaseDriver {
555
620
  // their createSession method and other instance methods
556
621
  if (cmd === CREATE_SESSION_COMMAND && this.sessionlessPlugins.length && !res.error) {
557
622
  const sessionId = _.first(res.value);
558
- log.info(`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
559
- `to session ID ${sessionId}`);
623
+ this.log.info(`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
624
+ `to session ID ${sessionId}`);
560
625
  this.sessionPlugins[sessionId] = this.sessionlessPlugins;
561
626
  this.sessionlessPlugins = [];
562
627
  }
@@ -565,7 +630,7 @@ class AppiumDriver extends BaseDriver {
565
630
  }
566
631
 
567
632
  wrapCommandWithPlugins ({driver, cmd, args, next, cmdHandledBy, plugins}) {
568
- plugins.length && log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
633
+ plugins.length && this.log.info(`Plugins which can handle cmd '${cmd}': ${plugins.map((p) => p.name)}`);
569
634
 
570
635
  // now we can go through each plugin and wrap `next` around its own handler, passing the *old*
571
636
  // next in so that it can call it if it wants to
@@ -575,7 +640,7 @@ class AppiumDriver extends BaseDriver {
575
640
  // evaluated, otherwise we end up with infinite recursion of the last `next` to be defined.
576
641
  cmdHandledBy[plugin.name] = false; // we see a new plugin, so add it to the 'cmdHandledBy' object
577
642
  next = ((_next) => async () => {
578
- log.info(`Plugin ${plugin.name} is now handling cmd '${cmd}'`);
643
+ this.log.info(`Plugin ${plugin.name} is now handling cmd '${cmd}'`);
579
644
  cmdHandledBy[plugin.name] = true; // if we make it here, this plugin has attempted to handle cmd
580
645
  // first attempt to handle the command via a command-specific handler on the plugin
581
646
  if (plugin[cmd]) {
@@ -603,9 +668,9 @@ class AppiumDriver extends BaseDriver {
603
668
  const didHandle = Object.keys(cmdHandledBy).filter((k) => cmdHandledBy[k]);
604
669
  const didntHandle = Object.keys(cmdHandledBy).filter((k) => !cmdHandledBy[k]);
605
670
  if (didntHandle.length > 0) {
606
- log.info(`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
607
- `though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
608
- `command *was* handled by these: ${JSON.stringify(didHandle)}.`);
671
+ this.log.info(`Command '${cmd}' was *not* handled by the following behaviours or plugins, even ` +
672
+ `though they were registered to handle it: ${JSON.stringify(didntHandle)}. The ` +
673
+ `command *was* handled by these: ${JSON.stringify(didHandle)}.`);
609
674
  }
610
675
  }
611
676
 
@@ -675,22 +740,28 @@ export class NoDriverProxyCommandError extends Error {
675
740
 
676
741
  export { AppiumDriver };
677
742
 
678
-
679
- /**
680
- * @typedef {Object} StaticExtMembers
681
- * @property {(app: import('express').Express, httpServer: import('http').Server) => import('type-fest').Promisable<void>} [updateServer]
682
- * @property {import('@appium/base-driver').MethodMap} [newMethodMap]
683
- */
684
-
685
743
  /**
686
- * @typedef {Object} StaticPluginMembers
687
- * @property {string} pluginName
744
+ * @typedef {import('@appium/types').ExternalDriver} ExternalDriver
745
+ * @typedef {import('@appium/types').W3CCapabilities} W3CCapabilities
746
+ * @typedef {import('@appium/types').DriverData} DriverData
747
+ * @typedef {import('@appium/types').DriverOpts} DriverOpts
748
+ * @typedef {import('@appium/types').Constraints} Constraints
749
+ * @typedef {import('@appium/types').AppiumServer} AppiumServer
750
+ * @typedef {import('../types').ExtensionType} ExtensionType
751
+ * @typedef {import('../types/extension').PluginClass} PluginClass
752
+ * @typedef {import('./extension/driver-config').DriverConfig} DriverConfig
688
753
  */
689
754
 
690
755
  /**
691
- * @typedef {import('type-fest').Class<unknown> & StaticPluginMembers & StaticExtMembers} PluginExtensionClass
756
+ * Used by {@linkcode AppiumDriver.createSession} and {@linkcode AppiumDriver.deleteSession} to describe
757
+ * result.
758
+ * @template V
759
+ * @typedef SessionHandlerResult
760
+ * @property {V} [value]
761
+ * @property {Error} [error]
762
+ * @property {string} [protocol]
692
763
  */
693
764
 
694
765
  /**
695
- * @typedef {import('type-fest').Class<unknown> & StaticExtMembers} DriverExtensionClass
766
+ * @typedef {import('@appium/types').SessionHandler<SessionHandlerResult<any[]>,SessionHandlerResult<void>>} SessionHandler
696
767
  */