@appium/base-driver 10.5.2 → 10.7.0

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 (189) hide show
  1. package/build/lib/basedriver/capabilities.d.ts +1 -1
  2. package/build/lib/basedriver/capabilities.d.ts.map +1 -1
  3. package/build/lib/basedriver/capabilities.js +58 -50
  4. package/build/lib/basedriver/capabilities.js.map +1 -1
  5. package/build/lib/basedriver/commands/bidi.d.ts.map +1 -1
  6. package/build/lib/basedriver/commands/bidi.js +10 -14
  7. package/build/lib/basedriver/commands/bidi.js.map +1 -1
  8. package/build/lib/basedriver/commands/event.d.ts.map +1 -1
  9. package/build/lib/basedriver/commands/event.js +4 -7
  10. package/build/lib/basedriver/commands/event.js.map +1 -1
  11. package/build/lib/basedriver/commands/execute.js +3 -6
  12. package/build/lib/basedriver/commands/execute.js.map +1 -1
  13. package/build/lib/basedriver/commands/find.d.ts.map +1 -1
  14. package/build/lib/basedriver/commands/find.js +2 -1
  15. package/build/lib/basedriver/commands/find.js.map +1 -1
  16. package/build/lib/basedriver/commands/log.d.ts.map +1 -1
  17. package/build/lib/basedriver/commands/log.js +1 -5
  18. package/build/lib/basedriver/commands/log.js.map +1 -1
  19. package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
  20. package/build/lib/basedriver/commands/timeout.js +9 -13
  21. package/build/lib/basedriver/commands/timeout.js.map +1 -1
  22. package/build/lib/basedriver/core.d.ts.map +1 -1
  23. package/build/lib/basedriver/core.js +17 -14
  24. package/build/lib/basedriver/core.js.map +1 -1
  25. package/build/lib/basedriver/device-settings.d.ts.map +1 -1
  26. package/build/lib/basedriver/device-settings.js +3 -7
  27. package/build/lib/basedriver/device-settings.js.map +1 -1
  28. package/build/lib/basedriver/driver.d.ts.map +1 -1
  29. package/build/lib/basedriver/driver.js +34 -38
  30. package/build/lib/basedriver/driver.js.map +1 -1
  31. package/build/lib/basedriver/extension-core.d.ts +4 -1
  32. package/build/lib/basedriver/extension-core.d.ts.map +1 -1
  33. package/build/lib/basedriver/extension-core.js +37 -13
  34. package/build/lib/basedriver/extension-core.js.map +1 -1
  35. package/build/lib/basedriver/helpers.d.ts.map +1 -1
  36. package/build/lib/basedriver/helpers.js +47 -33
  37. package/build/lib/basedriver/helpers.js.map +1 -1
  38. package/build/lib/basedriver/ipc.d.ts +36 -0
  39. package/build/lib/basedriver/ipc.d.ts.map +1 -0
  40. package/build/lib/basedriver/ipc.js +157 -0
  41. package/build/lib/basedriver/ipc.js.map +1 -0
  42. package/build/lib/basedriver/validation.d.ts.map +1 -1
  43. package/build/lib/basedriver/validation.js +27 -29
  44. package/build/lib/basedriver/validation.js.map +1 -1
  45. package/build/lib/express/express-logging.d.ts +0 -1
  46. package/build/lib/express/express-logging.d.ts.map +1 -1
  47. package/build/lib/express/express-logging.js +11 -11
  48. package/build/lib/express/express-logging.js.map +1 -1
  49. package/build/lib/express/idempotency.js +3 -6
  50. package/build/lib/express/idempotency.js.map +1 -1
  51. package/build/lib/express/middleware.d.ts.map +1 -1
  52. package/build/lib/express/middleware.js +6 -10
  53. package/build/lib/express/middleware.js.map +1 -1
  54. package/build/lib/express/server.d.ts +1 -1
  55. package/build/lib/express/server.d.ts.map +1 -1
  56. package/build/lib/express/server.js +82 -73
  57. package/build/lib/express/server.js.map +1 -1
  58. package/build/lib/express/websocket.d.ts.map +1 -1
  59. package/build/lib/express/websocket.js +6 -9
  60. package/build/lib/express/websocket.js.map +1 -1
  61. package/build/lib/helpers/capabilities.d.ts.map +1 -1
  62. package/build/lib/helpers/capabilities.js +14 -17
  63. package/build/lib/helpers/capabilities.js.map +1 -1
  64. package/build/lib/helpers/extension-command-name.js +2 -5
  65. package/build/lib/helpers/extension-command-name.js.map +1 -1
  66. package/build/lib/helpers/levenshtein-match.d.ts.map +1 -1
  67. package/build/lib/helpers/levenshtein-match.js +6 -7
  68. package/build/lib/helpers/levenshtein-match.js.map +1 -1
  69. package/build/lib/index.d.ts +2 -1
  70. package/build/lib/index.d.ts.map +1 -1
  71. package/build/lib/index.js +6 -16
  72. package/build/lib/index.js.map +1 -1
  73. package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
  74. package/build/lib/jsonwp-proxy/protocol-converter.js +21 -18
  75. package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
  76. package/build/lib/jsonwp-proxy/proxy-request.d.ts +2 -2
  77. package/build/lib/jsonwp-proxy/proxy-request.d.ts.map +1 -1
  78. package/build/lib/jsonwp-proxy/proxy-request.js +25 -21
  79. package/build/lib/jsonwp-proxy/proxy-request.js.map +1 -1
  80. package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
  81. package/build/lib/jsonwp-proxy/proxy.js +45 -36
  82. package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
  83. package/build/lib/protocol/errors.d.ts.map +1 -1
  84. package/build/lib/protocol/errors.js +33 -37
  85. package/build/lib/protocol/errors.js.map +1 -1
  86. package/build/lib/protocol/helpers.d.ts.map +1 -1
  87. package/build/lib/protocol/helpers.js +9 -8
  88. package/build/lib/protocol/helpers.js.map +1 -1
  89. package/build/lib/protocol/protocol.d.ts +1 -1
  90. package/build/lib/protocol/protocol.d.ts.map +1 -1
  91. package/build/lib/protocol/protocol.js +73 -61
  92. package/build/lib/protocol/protocol.js.map +1 -1
  93. package/build/lib/protocol/routes.d.ts +1 -1
  94. package/build/lib/protocol/routes.d.ts.map +1 -1
  95. package/build/lib/protocol/routes.js +16 -17
  96. package/build/lib/protocol/routes.js.map +1 -1
  97. package/build/lib/protocol/validators.d.ts.map +1 -1
  98. package/build/lib/protocol/validators.js +1 -5
  99. package/build/lib/protocol/validators.js.map +1 -1
  100. package/build/lib/test-pages/crash.d.ts.map +1 -0
  101. package/build/lib/test-pages/crash.js.map +1 -0
  102. package/build/lib/test-pages/env.d.ts +5 -0
  103. package/build/lib/test-pages/env.d.ts.map +1 -0
  104. package/build/lib/test-pages/env.js +12 -0
  105. package/build/lib/test-pages/env.js.map +1 -0
  106. package/build/lib/{express/static.d.ts → test-pages/handlers.d.ts} +1 -2
  107. package/build/lib/test-pages/handlers.d.ts.map +1 -0
  108. package/build/lib/{express/static.js → test-pages/handlers.js} +9 -12
  109. package/build/lib/test-pages/handlers.js.map +1 -0
  110. package/build/lib/test-pages/index.d.ts +6 -0
  111. package/build/lib/test-pages/index.d.ts.map +1 -0
  112. package/build/lib/test-pages/index.js +35 -0
  113. package/build/lib/test-pages/index.js.map +1 -0
  114. package/build/lib/test-pages/static-dir.d.ts +8 -0
  115. package/build/lib/test-pages/static-dir.d.ts.map +1 -0
  116. package/build/lib/test-pages/static-dir.js +24 -0
  117. package/build/lib/test-pages/static-dir.js.map +1 -0
  118. package/build/lib/test-pages/template.d.ts +3 -0
  119. package/build/lib/test-pages/template.d.ts.map +1 -0
  120. package/build/lib/test-pages/template.js +19 -0
  121. package/build/lib/test-pages/template.js.map +1 -0
  122. package/build/lib/utils.d.ts +14 -0
  123. package/build/lib/utils.d.ts.map +1 -0
  124. package/build/lib/utils.js +55 -0
  125. package/build/lib/utils.js.map +1 -0
  126. package/lib/basedriver/capabilities.ts +126 -115
  127. package/lib/basedriver/commands/bidi.ts +11 -11
  128. package/lib/basedriver/commands/event.ts +17 -11
  129. package/lib/basedriver/commands/execute.ts +15 -12
  130. package/lib/basedriver/commands/find.ts +20 -12
  131. package/lib/basedriver/commands/log.ts +4 -3
  132. package/lib/basedriver/commands/timeout.ts +22 -14
  133. package/lib/basedriver/core.ts +26 -26
  134. package/lib/basedriver/device-settings.ts +7 -12
  135. package/lib/basedriver/driver.ts +62 -50
  136. package/lib/basedriver/extension-core.ts +60 -18
  137. package/lib/basedriver/helpers.ts +81 -52
  138. package/lib/basedriver/ipc.ts +198 -0
  139. package/lib/basedriver/validation.ts +37 -30
  140. package/lib/express/express-logging.ts +16 -20
  141. package/lib/express/idempotency.ts +9 -9
  142. package/lib/express/middleware.ts +14 -18
  143. package/lib/express/server.ts +118 -120
  144. package/lib/express/websocket.ts +11 -15
  145. package/lib/helpers/capabilities.ts +21 -16
  146. package/lib/helpers/extension-command-name.ts +3 -3
  147. package/lib/helpers/levenshtein-match.ts +20 -14
  148. package/lib/index.js +3 -12
  149. package/lib/jsonwp-proxy/protocol-converter.ts +58 -35
  150. package/lib/jsonwp-proxy/proxy-request.ts +26 -26
  151. package/lib/jsonwp-proxy/proxy.ts +74 -75
  152. package/lib/protocol/errors.ts +69 -88
  153. package/lib/protocol/helpers.ts +9 -5
  154. package/lib/protocol/protocol.ts +149 -107
  155. package/lib/protocol/routes.ts +17 -17
  156. package/lib/protocol/validators.ts +1 -3
  157. package/lib/test-pages/env.ts +9 -0
  158. package/lib/{express/static.ts → test-pages/handlers.ts} +10 -22
  159. package/lib/test-pages/index.ts +34 -0
  160. package/lib/test-pages/static-dir.ts +19 -0
  161. package/lib/test-pages/template.ts +17 -0
  162. package/lib/utils.ts +65 -0
  163. package/package.json +10 -13
  164. package/tsconfig.json +1 -0
  165. package/build/lib/express/crash.d.ts.map +0 -1
  166. package/build/lib/express/crash.js.map +0 -1
  167. package/build/lib/express/static.d.ts.map +0 -1
  168. package/build/lib/express/static.js.map +0 -1
  169. /package/build/lib/{express → test-pages}/crash.d.ts +0 -0
  170. /package/build/lib/{express → test-pages}/crash.js +0 -0
  171. /package/lib/{express → test-pages}/crash.ts +0 -0
  172. /package/{static → test-fixtures/static}/appium.png +0 -0
  173. /package/{static → test-fixtures/static}/favicon.ico +0 -0
  174. /package/{static → test-fixtures/static}/js/jquery.min.js +0 -0
  175. /package/{static → test-fixtures/static}/test/frameset.html +0 -0
  176. /package/{static → test-fixtures/static}/test/guinea-pig-app-banner.html +0 -0
  177. /package/{static → test-fixtures/static}/test/guinea-pig-scrollable.html +0 -0
  178. /package/{static → test-fixtures/static}/test/guinea-pig.html +0 -0
  179. /package/{static → test-fixtures/static}/test/guinea-pig2.html +0 -0
  180. /package/{static → test-fixtures/static}/test/guinea-pig3.html +0 -0
  181. /package/{static → test-fixtures/static}/test/guinea-pig4.html +0 -0
  182. /package/{static → test-fixtures/static}/test/guinea-pig5.html +0 -0
  183. /package/{static → test-fixtures/static}/test/iframes.html +0 -0
  184. /package/{static → test-fixtures/static}/test/shadow-dom.html +0 -0
  185. /package/{static → test-fixtures/static}/test/subframe1.html +0 -0
  186. /package/{static → test-fixtures/static}/test/subframe2.html +0 -0
  187. /package/{static → test-fixtures/static}/test/subframe3.html +0 -0
  188. /package/{static → test-fixtures/static}/test/touch.html +0 -0
  189. /package/{static → test-fixtures/static}/test/welcome.html +0 -0
@@ -5,13 +5,10 @@ import type {
5
5
  W3CCapabilities,
6
6
  StandardCapabilities,
7
7
  } from '@appium/types';
8
- import type {
9
- KeyAsString,
10
- MergeExclusive,
11
- } from 'type-fest';
12
- import _ from 'lodash';
8
+ import type {KeyAsString, MergeExclusive} from 'type-fest';
13
9
  import {validator} from './validation';
14
10
  import {util} from '@appium/support';
11
+ import {omit, pickBy} from '../utils';
15
12
  import {log} from './logger';
16
13
  import {errors} from '../protocol/errors';
17
14
 
@@ -39,22 +36,22 @@ export function mergeCaps<
39
36
  T extends Constraints,
40
37
  U extends Constraints,
41
38
  Primary extends Capabilities<T>,
42
- Secondary extends Capabilities<U>
39
+ Secondary extends Capabilities<U>,
43
40
  >(
44
41
  primary: Primary | undefined = {} as Primary,
45
- secondary: Secondary | undefined = {} as Secondary
42
+ secondary: Secondary | undefined = {} as Secondary,
46
43
  ): MergeExclusive<Primary, Secondary> {
47
- const result = ({
44
+ const result = {
48
45
  ...primary,
49
- }) as MergeExclusive<Primary, Secondary>;
46
+ } as MergeExclusive<Primary, Secondary>;
50
47
 
51
48
  for (const [name, value] of Object.entries(secondary)) {
52
49
  // Overwriting is not allowed. Primary and secondary must have different properties (w3c rule 4.4)
53
- if (!_.isUndefined(primary[name])) {
50
+ if (primary[name] !== undefined) {
54
51
  throw new errors.InvalidArgumentError(
55
52
  `property '${name}' should not exist on both primary (${JSON.stringify(
56
- primary
57
- )}) and secondary (${JSON.stringify(secondary)}) object`
53
+ primary,
54
+ )}) and secondary (${JSON.stringify(secondary)}) object`,
58
55
  );
59
56
  }
60
57
  result[name as keyof typeof result] = value;
@@ -69,37 +66,42 @@ export function mergeCaps<
69
66
  export function validateCaps<C extends Constraints>(
70
67
  caps: Capabilities<C>,
71
68
  constraints: C | undefined = {} as C,
72
- opts: ValidateCapsOpts | undefined = {}
69
+ opts: ValidateCapsOpts | undefined = {},
73
70
  ): Capabilities<C> {
74
71
  const {skipPresenceConstraint} = opts;
75
72
 
76
- if (!_.isPlainObject(caps)) {
73
+ if (!util.isPlainObject(caps)) {
77
74
  throw new errors.InvalidArgumentError(`must be a JSON object`);
78
75
  }
79
76
 
80
77
  // Remove the 'presence' constraint if we're not checking for it
81
- constraints = (
82
- _.mapValues(
83
- constraints,
84
- skipPresenceConstraint
85
- ? /** @param {Constraint} constraint */
86
- (constraint) => _.omit(constraint, 'presence')
87
- : /** @param {Constraint} constraint */
88
- (constraint) => {
89
- if (constraint.presence === true) {
90
- return {..._.omit(constraint, 'presence'), presence: {allowEmpty: false}};
91
- }
92
- return constraint;
93
- }
94
- )
78
+ constraints = Object.fromEntries(
79
+ Object.entries(constraints ?? {}).map(([key, constraint]) => {
80
+ if (skipPresenceConstraint) {
81
+ return [key, omit(constraint as Record<string, unknown>, 'presence')];
82
+ }
83
+ if ((constraint as {presence?: unknown}).presence === true) {
84
+ return [
85
+ key,
86
+ {
87
+ ...omit(constraint as Record<string, unknown>, 'presence'),
88
+ presence: {allowEmpty: false},
89
+ },
90
+ ];
91
+ }
92
+ return [key, constraint];
93
+ }),
95
94
  ) as C;
96
95
 
97
- const validationErrors = validator.validate(_.pickBy(caps, util.hasValue), constraints);
96
+ const validationErrors = validator.validate(
97
+ pickBy(caps, (value) => util.hasValue(value)),
98
+ constraints,
99
+ );
98
100
 
99
101
  if (validationErrors) {
100
102
  const message: string[] = [];
101
- for (const [attribute, reasons] of _.toPairs(validationErrors)) {
102
- for (const reason of (reasons as string[])) {
103
+ for (const [attribute, reasons] of Object.entries(validationErrors)) {
104
+ for (const reason of reasons as string[]) {
103
105
  message.push(`'${attribute}' ${reason}`);
104
106
  }
105
107
  }
@@ -115,22 +117,20 @@ export function validateCaps<C extends Constraints>(
115
117
  * @see https://www.w3.org/TR/webdriver2/#dfn-table-of-standard-capabilities)
116
118
  */
117
119
  export const STANDARD_CAPS = Object.freeze(
118
- new Set(
119
- ([
120
- 'browserName',
121
- 'browserVersion',
122
- 'platformName',
123
- 'acceptInsecureCerts',
124
- 'pageLoadStrategy',
125
- 'proxy',
126
- 'setWindowRect',
127
- 'timeouts',
128
- 'strictFileInteractability',
129
- 'unhandledPromptBehavior',
130
- 'userAgent',
131
- 'webSocketUrl',
132
- ]) as KeyAsString<StandardCapabilities>[]
133
- )
120
+ new Set([
121
+ 'browserName',
122
+ 'browserVersion',
123
+ 'platformName',
124
+ 'acceptInsecureCerts',
125
+ 'pageLoadStrategy',
126
+ 'proxy',
127
+ 'setWindowRect',
128
+ 'timeouts',
129
+ 'strictFileInteractability',
130
+ 'unhandledPromptBehavior',
131
+ 'userAgent',
132
+ 'webSocketUrl',
133
+ ] as KeyAsString<StandardCapabilities>[]),
134
134
  );
135
135
 
136
136
  const STANDARD_CAPS_LOWER = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
@@ -148,34 +148,40 @@ export function isStandardCap(cap: string): boolean {
148
148
  * @see https://www.w3.org/TR/webdriver/#dfn-extension-capabilities
149
149
  * @internal
150
150
  */
151
- export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<C>): Capabilities<C> {
151
+ export function stripAppiumPrefixes<C extends Constraints>(
152
+ caps: NSCapabilities<C>,
153
+ ): Capabilities<C> {
152
154
  // split into prefixed and non-prefixed.
153
155
  // non-prefixed should be standard caps at this point
154
- const [prefixedCaps, nonPrefixedCaps] = _.partition(_.keys(caps), (cap) =>
155
- String(cap).startsWith(APPIUM_VENDOR_PREFIX)
156
- );
156
+ const capKeys = Object.keys(caps);
157
+ const prefixedCaps = capKeys.filter((cap) => String(cap).startsWith(APPIUM_VENDOR_PREFIX));
158
+ const nonPrefixedCaps = capKeys.filter((cap) => !String(cap).startsWith(APPIUM_VENDOR_PREFIX));
157
159
 
158
160
  // initialize this with the k/v pairs of the non-prefixed caps
159
- const strippedCaps = (_.pick(caps, nonPrefixedCaps)) as Capabilities<C>;
161
+ const strippedCaps: Record<string, unknown> = Object.fromEntries(
162
+ nonPrefixedCaps.map((cap) => [cap, caps[cap as keyof typeof caps]]),
163
+ ) as Capabilities<C>;
160
164
  const badPrefixedCaps: string[] = [];
161
165
 
162
166
  // Strip out the 'appium:' prefix
163
167
  for (const prefixedCap of prefixedCaps) {
164
- const strippedCapName = prefixedCap.substring(APPIUM_VENDOR_PREFIX.length) as KeyAsString<Capabilities<C>>;
168
+ const strippedCapName = prefixedCap.substring(APPIUM_VENDOR_PREFIX.length) as KeyAsString<
169
+ Capabilities<C>
170
+ >;
165
171
 
166
172
  // If it's standard capability that was prefixed, add it to an array of incorrectly prefixed capabilities
167
173
  if (isStandardCap(strippedCapName)) {
168
174
  badPrefixedCaps.push(strippedCapName);
169
- if (_.isNil(strippedCaps[strippedCapName])) {
170
- strippedCaps[strippedCapName] = caps[prefixedCap];
175
+ if (strippedCaps[strippedCapName] == null) {
176
+ strippedCaps[strippedCapName] = caps[prefixedCap as keyof typeof caps];
171
177
  } else {
172
178
  log.warn(
173
- `Ignoring capability '${prefixedCap}=${caps[prefixedCap]}' and ` +
174
- `using capability '${strippedCapName}=${strippedCaps[strippedCapName]}'`
179
+ `Ignoring capability '${prefixedCap}=${caps[prefixedCap as keyof typeof caps]}' and ` +
180
+ `using capability '${strippedCapName}=${strippedCaps[strippedCapName]}'`,
175
181
  );
176
182
  }
177
183
  } else {
178
- strippedCaps[strippedCapName] = caps[prefixedCap];
184
+ strippedCaps[strippedCapName] = caps[prefixedCap as keyof typeof caps];
179
185
  }
180
186
  }
181
187
 
@@ -183,32 +189,29 @@ export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<
183
189
  if (badPrefixedCaps.length > 0) {
184
190
  log.warn(
185
191
  `The capabilities ${JSON.stringify(
186
- badPrefixedCaps
187
- )} are standard capabilities and do not require "appium:" prefix`
192
+ badPrefixedCaps,
193
+ )} are standard capabilities and do not require "appium:" prefix`,
188
194
  );
189
195
  }
190
- return strippedCaps;
196
+ return strippedCaps as Capabilities<C>;
191
197
  }
192
198
 
193
199
  /**
194
200
  * Get an array of all the unprefixed caps that are being used in 'alwaysMatch' and all of the 'firstMatch' object
195
201
  */
196
- export function findNonPrefixedCaps<C extends Constraints>(
197
- {
198
- alwaysMatch = {},
199
- firstMatch = []
200
- }: W3CCapabilities<C>
201
- ): string[] {
202
- return _.chain([alwaysMatch, ...firstMatch])
203
- .reduce(
202
+ export function findNonPrefixedCaps<C extends Constraints>({
203
+ alwaysMatch = {},
204
+ firstMatch = [],
205
+ }: W3CCapabilities<C>): string[] {
206
+ return util.uniq(
207
+ [alwaysMatch, ...firstMatch].reduce<string[]>(
204
208
  (unprefixedCaps, caps) => [
205
209
  ...unprefixedCaps,
206
210
  ...Object.keys(caps).filter((cap) => !cap.includes(':') && !isStandardCap(cap)),
207
211
  ],
208
- []
209
- )
210
- .uniq()
211
- .value();
212
+ [],
213
+ ),
214
+ );
212
215
  }
213
216
 
214
217
  /**
@@ -218,12 +221,12 @@ export function findNonPrefixedCaps<C extends Constraints>(
218
221
  export function parseCaps<C extends Constraints>(
219
222
  caps: W3CCapabilities<C>,
220
223
  constraints: C | undefined = {} as C,
221
- shouldValidateCaps: boolean | undefined = true
224
+ shouldValidateCaps: boolean | undefined = true,
222
225
  ): ParsedCaps<C> {
223
226
  // If capabilities request is not an object, return error (#1.1)
224
- if (!_.isPlainObject(caps)) {
227
+ if (!util.isPlainObject(caps)) {
225
228
  throw new errors.InvalidArgumentError(
226
- 'The capabilities argument was not valid for the following reason(s): "capabilities" must be a JSON object.'
229
+ 'The capabilities argument was not valid for the following reason(s): "capabilities" must be a JSON object.',
227
230
  );
228
231
  }
229
232
 
@@ -235,9 +238,9 @@ export function parseCaps<C extends Constraints>(
235
238
  } = caps;
236
239
 
237
240
  // Reject 'firstMatch' argument if it's not an array (#3.2)
238
- if (!_.isArray(allFirstMatchCaps)) {
241
+ if (!Array.isArray(allFirstMatchCaps)) {
239
242
  throw new errors.InvalidArgumentError(
240
- 'The capabilities.firstMatch argument was not valid for the following reason(s): "capabilities.firstMatch" must be a JSON array or undefined'
243
+ 'The capabilities.firstMatch argument was not valid for the following reason(s): "capabilities.firstMatch" must be a JSON array or undefined',
241
244
  );
242
245
  }
243
246
 
@@ -246,16 +249,16 @@ export function parseCaps<C extends Constraints>(
246
249
  if (allFirstMatchCaps.length === 0) {
247
250
  log.warn(
248
251
  `The firstMatch array in the given capabilities has no entries. Adding an empty entry for now, ` +
249
- `but it will require one or more entries as W3C spec.`
252
+ `but it will require one or more entries as W3C spec.`,
250
253
  );
251
254
  allFirstMatchCaps.push({});
252
255
  }
253
256
 
254
257
  // Check for non-prefixed, non-standard capabilities and log warnings if they are found
255
258
  const nonPrefixedCaps = findNonPrefixedCaps(caps);
256
- if (!_.isEmpty(nonPrefixedCaps)) {
259
+ if (!util.isEmpty(nonPrefixedCaps)) {
257
260
  throw new errors.InvalidArgumentError(
258
- `All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: ${nonPrefixedCaps}`
261
+ `All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: ${nonPrefixedCaps}`,
259
262
  );
260
263
  }
261
264
 
@@ -271,22 +274,24 @@ export function parseCaps<C extends Constraints>(
271
274
  }
272
275
  // Remove the 'presence' constraint for any keys that are already present in 'requiredCaps'
273
276
  // since we know that this constraint has already passed
274
- const filteredConstraints = _.omitBy(constraints, (_, key) => key in strippedRequiredCaps) as C;
277
+ const filteredConstraints = Object.fromEntries(
278
+ Object.entries(constraints ?? {}).filter(([key]) => !(key in strippedRequiredCaps)),
279
+ ) as C;
275
280
 
276
281
  // Validate all of the first match capabilities and return an array with only the valid caps (see spec #5)
277
282
  const validationErrors: string[] = [];
278
- const validatedFirstMatchCaps = _.compact(
279
- strippedAllFirstMatchCaps.map((firstMatchCaps) => {
283
+ const validatedFirstMatchCaps = strippedAllFirstMatchCaps
284
+ .map((firstMatchCaps) => {
280
285
  try {
281
286
  // Validate firstMatch caps
282
287
  return shouldValidateCaps
283
288
  ? validateCaps(firstMatchCaps, filteredConstraints)
284
289
  : firstMatchCaps;
285
290
  } catch (e) {
286
- validationErrors.push(e.message);
291
+ validationErrors.push((e as Error).message);
287
292
  }
288
293
  })
289
- ) as Capabilities<C>[];
294
+ .filter(Boolean) as Capabilities<C>[];
290
295
 
291
296
  /**
292
297
  * Try to merge requiredCaps with first match capabilities, break once it finds its first match
@@ -300,8 +305,8 @@ export function parseCaps<C extends Constraints>(
300
305
  break;
301
306
  }
302
307
  } catch (err) {
303
- log.warn(err.message);
304
- validationErrors.push(err.message);
308
+ log.warn((err as Error).message);
309
+ validationErrors.push((err as Error).message);
305
310
  }
306
311
  }
307
312
 
@@ -318,24 +323,21 @@ export function parseCaps<C extends Constraints>(
318
323
  /**
319
324
  * Calls parseCaps and just returns the matchedCaps variable
320
325
  */
321
- export function processCapabilities<
322
- C extends Constraints,
323
- W3CCaps extends W3CCapabilities<C>
324
- >(
326
+ export function processCapabilities<C extends Constraints, W3CCaps extends W3CCapabilities<C>>(
325
327
  w3cCaps: W3CCaps,
326
328
  constraints: C | undefined = {} as C,
327
- shouldValidateCaps: boolean | undefined = true
329
+ shouldValidateCaps: boolean | undefined = true,
328
330
  ): Capabilities<C> {
329
331
  const {matchedCaps, validationErrors} = parseCaps(w3cCaps, constraints, shouldValidateCaps);
330
332
 
331
333
  // If we found an error throw an exception
332
334
  if (!util.hasValue(matchedCaps)) {
333
- if (_.isArray(w3cCaps.firstMatch) && w3cCaps.firstMatch.length > 1) {
335
+ if (Array.isArray(w3cCaps.firstMatch) && w3cCaps.firstMatch.length > 1) {
334
336
  // If there was more than one 'firstMatch' cap, indicate that we couldn't find a matching capabilities set and show all the errors
335
337
  throw new errors.InvalidArgumentError(
336
338
  `Could not find matching capabilities from ${JSON.stringify(
337
- w3cCaps
338
- )}:\n ${validationErrors.join('\n')}`
339
+ w3cCaps,
340
+ )}:\n ${validationErrors.join('\n')}`,
339
341
  );
340
342
  } else {
341
343
  // Otherwise, just show the singular error message
@@ -350,23 +352,25 @@ export function processCapabilities<
350
352
  * Return a copy of a "bare" (single-level, non-W3C) capabilities object which has taken everything
351
353
  * within the 'appium:options' capability and promoted it to the top level.
352
354
  */
353
- export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapabilities<C>): NSCapabilities<C> {
355
+ export function promoteAppiumOptionsForObject<C extends Constraints>(
356
+ obj: NSCapabilities<C>,
357
+ ): NSCapabilities<C> {
354
358
  const appiumOptions = obj[PREFIXED_APPIUM_OPTS_CAP];
355
359
  if (!appiumOptions) {
356
360
  return obj;
357
361
  }
358
362
 
359
- if (!_.isPlainObject(appiumOptions)) {
363
+ if (!util.isPlainObject(appiumOptions)) {
360
364
  throw new errors.SessionNotCreatedError(
361
- `The ${PREFIXED_APPIUM_OPTS_CAP} capability must be an object`
365
+ `The ${PREFIXED_APPIUM_OPTS_CAP} capability must be an object`,
362
366
  );
363
367
  }
364
- if (_.isEmpty(appiumOptions)) {
368
+ if (util.isEmpty(appiumOptions)) {
365
369
  return obj;
366
370
  }
367
371
 
368
372
  log.debug(
369
- `Found ${PREFIXED_APPIUM_OPTS_CAP} capability present; will promote items inside to caps`
373
+ `Found ${PREFIXED_APPIUM_OPTS_CAP} capability present; will promote items inside to caps`,
370
374
  );
371
375
 
372
376
  /**
@@ -374,32 +378,37 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
374
378
  */
375
379
  const shouldAddVendorPrefix = (capName: string) => !capName.startsWith(APPIUM_VENDOR_PREFIX);
376
380
  const verifyIfAcceptable = (capName: string) => {
377
- if (!_.isString(capName)) {
381
+ if (typeof capName !== 'string') {
378
382
  throw new errors.SessionNotCreatedError(
379
- `Capability names in ${PREFIXED_APPIUM_OPTS_CAP} must be strings. '${capName}' is unexpected`
383
+ `Capability names in ${PREFIXED_APPIUM_OPTS_CAP} must be strings. '${capName}' is unexpected`,
380
384
  );
381
385
  }
382
386
  if (isStandardCap(capName)) {
383
387
  throw new errors.SessionNotCreatedError(
384
- `${PREFIXED_APPIUM_OPTS_CAP} must only contain vendor-specific capabilities. '${capName}' is unexpected`
388
+ `${PREFIXED_APPIUM_OPTS_CAP} must only contain vendor-specific capabilities. '${capName}' is unexpected`,
385
389
  );
386
390
  }
387
391
  return capName;
388
392
  };
389
- const preprocessedOptions = _(appiumOptions)
390
- .mapKeys((value, key: string) => verifyIfAcceptable(key))
391
- .mapKeys((value, key: string) => (shouldAddVendorPrefix(key) ? `${APPIUM_VENDOR_PREFIX}${key}` : key))
392
- .value();
393
+ const preprocessedOptions: Record<string, unknown> = {};
394
+ for (const [key, value] of Object.entries(appiumOptions as Record<string, unknown>)) {
395
+ const verifiedKey = verifyIfAcceptable(key);
396
+ const finalKey = shouldAddVendorPrefix(verifiedKey)
397
+ ? `${APPIUM_VENDOR_PREFIX}${verifiedKey}`
398
+ : verifiedKey;
399
+ preprocessedOptions[finalKey] = value;
400
+ }
393
401
  // warn if we are going to overwrite any keys on the base caps object
394
- const overwrittenKeys = _.intersection(Object.keys(obj), Object.keys(preprocessedOptions));
402
+ const overwrittenKeys = Object.keys(obj).filter((key) => key in preprocessedOptions);
395
403
  if (overwrittenKeys.length > 0) {
396
404
  log.warn(
397
405
  `Found capabilities inside ${PREFIXED_APPIUM_OPTS_CAP} that will overwrite ` +
398
- `capabilities at the top level: ${JSON.stringify(overwrittenKeys)}`
406
+ `capabilities at the top level: ${JSON.stringify(overwrittenKeys)}`,
399
407
  );
400
408
  }
401
- return _.cloneDeep({
402
- ..._.omit(obj, PREFIXED_APPIUM_OPTS_CAP) as NSCapabilities<C>,
409
+ const restObj = omit(obj, PREFIXED_APPIUM_OPTS_CAP) as NSCapabilities<C>;
410
+ return structuredClone({
411
+ ...restObj,
403
412
  ...preprocessedOptions,
404
413
  });
405
414
  }
@@ -408,15 +417,17 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
408
417
  * Return a copy of a capabilities object which has taken everything within the 'options'
409
418
  * capability and promoted it to the top level.
410
419
  */
411
- export function promoteAppiumOptions<C extends Constraints>(originalCaps: W3CCapabilities<C>): W3CCapabilities<C> {
420
+ export function promoteAppiumOptions<C extends Constraints>(
421
+ originalCaps: W3CCapabilities<C>,
422
+ ): W3CCapabilities<C> {
412
423
  const result = {} as W3CCapabilities<C>;
413
424
  const {alwaysMatch, firstMatch} = originalCaps;
414
- if (_.isPlainObject(alwaysMatch)) {
425
+ if (util.isPlainObject(alwaysMatch)) {
415
426
  result.alwaysMatch = promoteAppiumOptionsForObject(alwaysMatch);
416
427
  } else if ('alwaysMatch' in originalCaps) {
417
428
  result.alwaysMatch = alwaysMatch;
418
429
  }
419
- if (_.isArray(firstMatch)) {
430
+ if (Array.isArray(firstMatch)) {
420
431
  result.firstMatch = firstMatch.map(promoteAppiumOptionsForObject);
421
432
  } else if ('firstMatch' in originalCaps) {
422
433
  result.firstMatch = firstMatch;
@@ -1,7 +1,7 @@
1
+ import {util} from '@appium/support';
1
2
  import type {Constraints, DriverStatus, IBidiCommands} from '@appium/types';
2
3
  import type {BaseDriver} from '../driver';
3
4
  import {mixin} from './mixin';
4
- import _ from 'lodash';
5
5
 
6
6
  declare module '../driver' {
7
7
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -36,16 +36,16 @@ const BidiCommands: IBidiCommands = {
36
36
 
37
37
  async bidiStatus<C extends Constraints>(this: BaseDriver<C>): Promise<DriverStatus> {
38
38
  const result = await this.getStatus();
39
- if (!_.has(result, 'ready')) {
40
- //@ts-ignore This is OK
41
- result.ready = true;
42
- }
43
- if (!_.has(result, 'message')) {
44
- //@ts-ignore This is OK
45
- result.message = `${this.constructor.name} is ready to accept commands`;
46
- }
47
- return result as DriverStatus;
48
- }
39
+ const base: Record<string, unknown> = util.isPlainObject(result) ? {...result} : {};
40
+ return {
41
+ ...base,
42
+ ready: 'ready' in base ? (base.ready as boolean) : true,
43
+ message:
44
+ 'message' in base
45
+ ? (base.message as string)
46
+ : `${this.constructor.name} is ready to accept commands`,
47
+ };
48
+ },
49
49
  };
50
50
 
51
51
  mixin(BidiCommands);
@@ -1,5 +1,5 @@
1
- import type {Constraints, IEventCommands} from '@appium/types';
2
- import _ from 'lodash';
1
+ import type {Constraints, EventHistory, IEventCommands} from '@appium/types';
2
+ import {util} from '@appium/support';
3
3
  import type {BaseDriver} from '../driver';
4
4
  import {mixin} from './mixin';
5
5
 
@@ -16,7 +16,11 @@ const EventCommands: IEventCommands = {
16
16
  * separation
17
17
  * @param event - the event name
18
18
  */
19
- async logCustomEvent<C extends Constraints>(this: BaseDriver<C>, vendor: string, event: string) {
19
+ async logCustomEvent<C extends Constraints>(
20
+ this: BaseDriver<C>,
21
+ vendor: string,
22
+ event: string,
23
+ ): Promise<void> {
20
24
  this.logEvent(`${vendor}:${event}`);
21
25
  },
22
26
 
@@ -26,23 +30,25 @@ const EventCommands: IEventCommands = {
26
30
  * It returns all events if the type is not provided or empty string/array.
27
31
  * @returns the event history log object
28
32
  */
29
- async getLogEvents<C extends Constraints>(this: BaseDriver<C>, type: string | string[]) {
30
- if (_.isEmpty(type)) {
33
+ async getLogEvents<C extends Constraints>(
34
+ this: BaseDriver<C>,
35
+ type: string | string[],
36
+ ): Promise<Partial<EventHistory>> {
37
+ if (util.isEmpty(type)) {
31
38
  return this.eventHistory;
32
39
  }
33
40
 
34
- const typeList = _.castArray(type);
41
+ const typeList = Array.isArray(type) ? type : [type];
35
42
 
36
- return _.reduce(
37
- this.eventHistory,
38
- (acc, eventTimes, eventType) => {
43
+ return Object.entries(this.eventHistory).reduce<Partial<EventHistory>>(
44
+ (acc, [eventType, eventTimes]) => {
39
45
  if (typeList.includes(eventType)) {
40
46
  acc[eventType] = eventTimes;
41
47
  }
42
48
  return acc;
43
49
  },
44
- {}
45
- );
50
+ {},
51
+ ) as Record<string, number>;
46
52
  },
47
53
  };
48
54
 
@@ -1,4 +1,4 @@
1
- import _ from 'lodash';
1
+ import {util} from '@appium/support';
2
2
  import {errors, validateExecuteMethodParams} from '../../protocol';
3
3
  import type {
4
4
  Constraints,
@@ -17,31 +17,34 @@ declare module '../driver' {
17
17
  interface BaseDriver<C extends Constraints> extends IExecuteCommands {}
18
18
  }
19
19
 
20
- const ExecuteCommands: IExecuteCommands = {
20
+ const ExecuteCommands = {
21
21
  async executeMethod<C extends Constraints>(
22
22
  this: BaseDriver<C>,
23
23
  script: string,
24
- protoArgs: readonly [StringRecord<unknown>] | readonly unknown[]
24
+ protoArgs: readonly [StringRecord<unknown>] | readonly unknown[],
25
25
  ) {
26
26
  const Driver = this.constructor as DriverClass<Driver<C>>;
27
27
  const commandMetadata = {...Driver.executeMethodMap?.[script]};
28
28
  if (!commandMetadata.command) {
29
- const availableScripts = _.keys(Driver.executeMethodMap);
30
- if (_.isEmpty(availableScripts)) {
29
+ const availableScripts = Object.keys(Driver.executeMethodMap ?? {});
30
+ if (util.isEmpty(availableScripts)) {
31
31
  throw new errors.UnsupportedOperationError(
32
32
  `Unsupported execute method '${script}'. ` +
33
- `Make sure the installed ${Driver.name} is up-to-date. ` +
34
- `The current driver version does not define any execute methods.`
33
+ `Make sure the installed ${Driver.name} is up-to-date. ` +
34
+ `The current driver version does not define any execute methods.`,
35
35
  );
36
36
  }
37
- const {sorted: sortedMatches, suggestion} = rankLevenshteinCandidates(script, availableScripts);
37
+ const {sorted: sortedMatches, suggestion} = rankLevenshteinCandidates(
38
+ script,
39
+ availableScripts,
40
+ );
38
41
  throw new errors.UnsupportedOperationError(
39
42
  (suggestion
40
43
  ? `Unsupported execute method '${script}', did you mean '${suggestion}'? `
41
44
  : `Unsupported execute method '${script}'. `) +
42
- `Make sure the installed ${Driver.name} is up-to-date. ` +
43
- `Execute methods available in the current driver version are: ` +
44
- sortedMatches.join(', ')
45
+ `Make sure the installed ${Driver.name} is up-to-date. ` +
46
+ `Execute methods available in the current driver version are: ` +
47
+ sortedMatches.join(', '),
45
48
  );
46
49
  }
47
50
  const args = validateExecuteMethodParams(protoArgs as any[], commandMetadata.params);
@@ -49,6 +52,6 @@ const ExecuteCommands: IExecuteCommands = {
49
52
  const command = this[commandName] as DriverCommand;
50
53
  return await command.call(this, ...args);
51
54
  },
52
- };
55
+ } as IExecuteCommands;
53
56
 
54
57
  mixin(ExecuteCommands);