@appium/base-driver 10.6.0 → 10.7.1

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 (157) 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 +15 -7
  4. package/build/lib/basedriver/capabilities.js.map +1 -1
  5. package/build/lib/basedriver/commands/bidi.js +1 -1
  6. package/build/lib/basedriver/commands/event.js.map +1 -1
  7. package/build/lib/basedriver/commands/execute.js.map +1 -1
  8. package/build/lib/basedriver/commands/find.d.ts.map +1 -1
  9. package/build/lib/basedriver/commands/find.js +2 -1
  10. package/build/lib/basedriver/commands/find.js.map +1 -1
  11. package/build/lib/basedriver/commands/timeout.js +4 -4
  12. package/build/lib/basedriver/commands/timeout.js.map +1 -1
  13. package/build/lib/basedriver/core.d.ts.map +1 -1
  14. package/build/lib/basedriver/core.js +5 -2
  15. package/build/lib/basedriver/core.js.map +1 -1
  16. package/build/lib/basedriver/device-settings.d.ts.map +1 -1
  17. package/build/lib/basedriver/device-settings.js.map +1 -1
  18. package/build/lib/basedriver/driver.d.ts.map +1 -1
  19. package/build/lib/basedriver/driver.js +23 -24
  20. package/build/lib/basedriver/driver.js.map +1 -1
  21. package/build/lib/basedriver/extension-core.d.ts.map +1 -1
  22. package/build/lib/basedriver/extension-core.js +11 -5
  23. package/build/lib/basedriver/extension-core.js.map +1 -1
  24. package/build/lib/basedriver/helpers.d.ts.map +1 -1
  25. package/build/lib/basedriver/helpers.js +20 -4
  26. package/build/lib/basedriver/helpers.js.map +1 -1
  27. package/build/lib/basedriver/ipc.d.ts.map +1 -1
  28. package/build/lib/basedriver/ipc.js +6 -4
  29. package/build/lib/basedriver/ipc.js.map +1 -1
  30. package/build/lib/basedriver/validation.d.ts.map +1 -1
  31. package/build/lib/basedriver/validation.js +3 -2
  32. package/build/lib/basedriver/validation.js.map +1 -1
  33. package/build/lib/express/express-logging.d.ts +0 -1
  34. package/build/lib/express/express-logging.d.ts.map +1 -1
  35. package/build/lib/express/express-logging.js +9 -8
  36. package/build/lib/express/express-logging.js.map +1 -1
  37. package/build/lib/express/idempotency.js.map +1 -1
  38. package/build/lib/express/middleware.d.ts.map +1 -1
  39. package/build/lib/express/middleware.js.map +1 -1
  40. package/build/lib/express/server.d.ts +1 -1
  41. package/build/lib/express/server.d.ts.map +1 -1
  42. package/build/lib/express/server.js +19 -20
  43. package/build/lib/express/server.js.map +1 -1
  44. package/build/lib/express/websocket.d.ts.map +1 -1
  45. package/build/lib/express/websocket.js.map +1 -1
  46. package/build/lib/helpers/capabilities.d.ts.map +1 -1
  47. package/build/lib/helpers/capabilities.js.map +1 -1
  48. package/build/lib/helpers/levenshtein-match.d.ts.map +1 -1
  49. package/build/lib/helpers/levenshtein-match.js +4 -1
  50. package/build/lib/helpers/levenshtein-match.js.map +1 -1
  51. package/build/lib/index.d.ts +1 -1
  52. package/build/lib/index.d.ts.map +1 -1
  53. package/build/lib/index.js +3 -2
  54. package/build/lib/index.js.map +1 -1
  55. package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
  56. package/build/lib/jsonwp-proxy/protocol-converter.js +14 -7
  57. package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
  58. package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
  59. package/build/lib/jsonwp-proxy/proxy.js +17 -11
  60. package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
  61. package/build/lib/protocol/errors.d.ts.map +1 -1
  62. package/build/lib/protocol/errors.js +13 -13
  63. package/build/lib/protocol/errors.js.map +1 -1
  64. package/build/lib/protocol/protocol.d.ts +1 -1
  65. package/build/lib/protocol/protocol.d.ts.map +1 -1
  66. package/build/lib/protocol/protocol.js +35 -18
  67. package/build/lib/protocol/protocol.js.map +1 -1
  68. package/build/lib/protocol/routes.d.ts.map +1 -1
  69. package/build/lib/protocol/routes.js +7 -5
  70. package/build/lib/protocol/routes.js.map +1 -1
  71. package/build/lib/test-pages/crash.d.ts.map +1 -0
  72. package/build/lib/test-pages/crash.js.map +1 -0
  73. package/build/lib/test-pages/env.d.ts +5 -0
  74. package/build/lib/test-pages/env.d.ts.map +1 -0
  75. package/build/lib/test-pages/env.js +12 -0
  76. package/build/lib/test-pages/env.js.map +1 -0
  77. package/build/lib/{express/static.d.ts → test-pages/handlers.d.ts} +1 -2
  78. package/build/lib/test-pages/handlers.d.ts.map +1 -0
  79. package/build/lib/{express/static.js → test-pages/handlers.js} +7 -17
  80. package/build/lib/test-pages/handlers.js.map +1 -0
  81. package/build/lib/test-pages/index.d.ts +6 -0
  82. package/build/lib/test-pages/index.d.ts.map +1 -0
  83. package/build/lib/test-pages/index.js +35 -0
  84. package/build/lib/test-pages/index.js.map +1 -0
  85. package/build/lib/test-pages/static-dir.d.ts +8 -0
  86. package/build/lib/test-pages/static-dir.d.ts.map +1 -0
  87. package/build/lib/test-pages/static-dir.js +24 -0
  88. package/build/lib/test-pages/static-dir.js.map +1 -0
  89. package/build/lib/test-pages/template.d.ts +3 -0
  90. package/build/lib/test-pages/template.d.ts.map +1 -0
  91. package/build/lib/test-pages/template.js +19 -0
  92. package/build/lib/test-pages/template.js.map +1 -0
  93. package/build/lib/utils.d.ts +0 -2
  94. package/build/lib/utils.d.ts.map +1 -1
  95. package/build/lib/utils.js +0 -16
  96. package/build/lib/utils.js.map +1 -1
  97. package/lib/basedriver/capabilities.ts +72 -66
  98. package/lib/basedriver/commands/bidi.ts +1 -1
  99. package/lib/basedriver/commands/event.ts +10 -5
  100. package/lib/basedriver/commands/execute.ts +12 -9
  101. package/lib/basedriver/commands/find.ts +20 -12
  102. package/lib/basedriver/commands/log.ts +2 -2
  103. package/lib/basedriver/commands/timeout.ts +17 -8
  104. package/lib/basedriver/core.ts +14 -14
  105. package/lib/basedriver/device-settings.ts +4 -8
  106. package/lib/basedriver/driver.ts +50 -40
  107. package/lib/basedriver/extension-core.ts +33 -17
  108. package/lib/basedriver/helpers.ts +57 -26
  109. package/lib/basedriver/ipc.ts +37 -18
  110. package/lib/basedriver/validation.ts +13 -6
  111. package/lib/express/express-logging.ts +14 -17
  112. package/lib/express/idempotency.ts +6 -6
  113. package/lib/express/middleware.ts +10 -12
  114. package/lib/express/server.ts +53 -61
  115. package/lib/express/websocket.ts +5 -7
  116. package/lib/helpers/capabilities.ts +5 -4
  117. package/lib/helpers/extension-command-name.ts +1 -1
  118. package/lib/helpers/levenshtein-match.ts +20 -11
  119. package/lib/index.js +2 -1
  120. package/lib/jsonwp-proxy/protocol-converter.ts +51 -27
  121. package/lib/jsonwp-proxy/proxy.ts +42 -42
  122. package/lib/protocol/errors.ts +47 -67
  123. package/lib/protocol/protocol.ts +116 -72
  124. package/lib/protocol/routes.ts +9 -9
  125. package/lib/test-pages/env.ts +9 -0
  126. package/lib/{express/static.ts → test-pages/handlers.ts} +7 -27
  127. package/lib/test-pages/index.ts +34 -0
  128. package/lib/test-pages/static-dir.ts +19 -0
  129. package/lib/test-pages/template.ts +17 -0
  130. package/lib/utils.ts +3 -23
  131. package/package.json +9 -10
  132. package/tsconfig.json +1 -0
  133. package/build/lib/express/crash.d.ts.map +0 -1
  134. package/build/lib/express/crash.js.map +0 -1
  135. package/build/lib/express/static.d.ts.map +0 -1
  136. package/build/lib/express/static.js.map +0 -1
  137. /package/build/lib/{express → test-pages}/crash.d.ts +0 -0
  138. /package/build/lib/{express → test-pages}/crash.js +0 -0
  139. /package/lib/{express → test-pages}/crash.ts +0 -0
  140. /package/{static → test-fixtures/static}/appium.png +0 -0
  141. /package/{static → test-fixtures/static}/favicon.ico +0 -0
  142. /package/{static → test-fixtures/static}/js/jquery.min.js +0 -0
  143. /package/{static → test-fixtures/static}/test/frameset.html +0 -0
  144. /package/{static → test-fixtures/static}/test/guinea-pig-app-banner.html +0 -0
  145. /package/{static → test-fixtures/static}/test/guinea-pig-scrollable.html +0 -0
  146. /package/{static → test-fixtures/static}/test/guinea-pig.html +0 -0
  147. /package/{static → test-fixtures/static}/test/guinea-pig2.html +0 -0
  148. /package/{static → test-fixtures/static}/test/guinea-pig3.html +0 -0
  149. /package/{static → test-fixtures/static}/test/guinea-pig4.html +0 -0
  150. /package/{static → test-fixtures/static}/test/guinea-pig5.html +0 -0
  151. /package/{static → test-fixtures/static}/test/iframes.html +0 -0
  152. /package/{static → test-fixtures/static}/test/shadow-dom.html +0 -0
  153. /package/{static → test-fixtures/static}/test/subframe1.html +0 -0
  154. /package/{static → test-fixtures/static}/test/subframe2.html +0 -0
  155. /package/{static → test-fixtures/static}/test/subframe3.html +0 -0
  156. /package/{static → test-fixtures/static}/test/touch.html +0 -0
  157. /package/{static → test-fixtures/static}/test/welcome.html +0 -0
@@ -34,16 +34,17 @@ export function isW3cCaps(caps: unknown): caps is W3CCapabilities<Constraints> {
34
34
  export function fixCaps<C extends Constraints>(
35
35
  oldCaps: Record<string, unknown>,
36
36
  desiredCapConstraints: C,
37
- log: AppiumLogger
37
+ log: AppiumLogger,
38
38
  ): Capabilities<C> {
39
39
  const caps = {...oldCaps} as Record<string, unknown>;
40
40
 
41
- const logCastWarning = (prefix: string) => log.warn(`${prefix}. This may cause unexpected behavior`);
41
+ const logCastWarning = (prefix: string) =>
42
+ log.warn(`${prefix}. This may cause unexpected behavior`);
42
43
 
43
44
  // boolean capabilities can be passed in as strings 'false' and 'true'
44
45
  // which we want to translate into boolean values
45
46
  const booleanCaps = Object.keys(desiredCapConstraints).filter(
46
- (key) => desiredCapConstraints[key as keyof C]?.isBoolean === true
47
+ (key) => desiredCapConstraints[key as keyof C]?.isBoolean === true,
47
48
  );
48
49
  for (const cap of booleanCaps) {
49
50
  const value = oldCaps[cap];
@@ -62,7 +63,7 @@ export function fixCaps<C extends Constraints>(
62
63
 
63
64
  // int capabilities are often sent in as strings by frameworks
64
65
  const intCaps = Object.keys(desiredCapConstraints).filter(
65
- (key) => desiredCapConstraints[key as keyof C]?.isNumber === true
66
+ (key) => desiredCapConstraints[key as keyof C]?.isNumber === true,
66
67
  );
67
68
  for (const cap of intCaps) {
68
69
  const value = oldCaps[cap];
@@ -11,7 +11,7 @@ import type {BaseDriver} from '../basedriver/driver';
11
11
  */
12
12
  export function resolveExecuteExtensionName<C extends Constraints>(
13
13
  this: BaseDriver<C>,
14
- commandName: string
14
+ commandName: string,
15
15
  ): string {
16
16
  const Driver = this.constructor as DriverClass<Driver<C>>;
17
17
  const methodMap = Driver.executeMethodMap;
@@ -29,22 +29,31 @@ export function rankLevenshteinCandidates(
29
29
 
30
30
  const matchesMap: StringRecord<string[]> = candidates
31
31
  .map((name) => [distance(target, name), name] as const)
32
- .reduce((acc, [dist, name]) => {
33
- const key = String(dist);
34
- if (key in acc) {
35
- acc[key].push(name);
36
- } else {
37
- acc[key] = [name];
38
- }
39
- return acc;
40
- }, {});
41
- const sortedDistanceKeys = Object.keys(matchesMap).sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
32
+ .reduce(
33
+ (acc, [dist, name]) => {
34
+ const key = String(dist);
35
+ if (key in acc) {
36
+ acc[key].push(name);
37
+ } else {
38
+ acc[key] = [name];
39
+ }
40
+ return acc;
41
+ },
42
+ {} as StringRecord<string[]>,
43
+ );
44
+ const sortedDistanceKeys = Object.keys(matchesMap).sort(
45
+ (a, b) => parseInt(a, 10) - parseInt(b, 10),
46
+ );
42
47
  const sorted = sortedDistanceKeys.flatMap((k) => (matchesMap[k] ?? []).sort());
43
48
 
44
49
  const best = sorted[0];
45
50
  const firstDistanceKey = sortedDistanceKeys[0];
46
51
  const minDist = firstDistanceKey !== undefined ? parseInt(firstDistanceKey, 10) : NaN;
47
- const suggestion = maxEditDistance >= 0 && best !== undefined && !Number.isNaN(minDist) && minDist <= maxEditDistance
52
+ const suggestion =
53
+ maxEditDistance >= 0 &&
54
+ best !== undefined &&
55
+ !Number.isNaN(minDist) &&
56
+ minDist <= maxEditDistance
48
57
  ? best
49
58
  : undefined;
50
59
  return {sorted, suggestion};
package/lib/index.js CHANGED
@@ -14,7 +14,8 @@ export * from './protocol';
14
14
  export {errorFromMJSONWPStatusCode as errorFromCode} from './protocol';
15
15
 
16
16
  // Express exports
17
- export {STATIC_DIR} from './express/static';
17
+ /** @deprecated Removed in Appium 4. Use hard-copied test fixtures in driver CI instead. */
18
+ export {TEST_FIXTURES_DIR as STATIC_DIR} from './test-pages';
18
19
  export {server, normalizeBasePath} from './express/server';
19
20
 
20
21
  // jsonwp-proxy exports
@@ -6,7 +6,7 @@ import {MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY, PROTOCOLS} from '../constants';
6
6
  export type ProxyFunction = (
7
7
  url: string,
8
8
  method: string,
9
- body?: HTTPBody
9
+ body?: HTTPBody,
10
10
  ) => Promise<[ProxyResponse, HTTPBody]>;
11
11
 
12
12
  export const COMMAND_URLS_CONFLICTS = [
@@ -19,7 +19,8 @@ export const COMMAND_URLS_CONFLICTS = [
19
19
  },
20
20
  {
21
21
  commandNames: ['getElementScreenshot'],
22
- jsonwpConverter: (url: string) => url.replace(/\/element\/([^/]+)\/screenshot$/, '/screenshot/$1'),
22
+ jsonwpConverter: (url: string) =>
23
+ url.replace(/\/element\/([^/]+)\/screenshot$/, '/screenshot/$1'),
23
24
  w3cConverter: (url: string) => url.replace(/\/screenshot\/([^/]+)/, '/element/$1/screenshot'),
24
25
  },
25
26
  {
@@ -59,7 +60,7 @@ export class ProtocolConverter {
59
60
  */
60
61
  constructor(
61
62
  public proxyFunc: ProxyFunction,
62
- log: AppiumLogger | null = null
63
+ log: AppiumLogger | null = null,
63
64
  ) {
64
65
  this._log = log;
65
66
  }
@@ -84,7 +85,7 @@ export class ProtocolConverter {
84
85
  commandName: string,
85
86
  url: string,
86
87
  method: string,
87
- body?: HTTPBody
88
+ body?: HTTPBody,
88
89
  ): Promise<[ProxyResponse, HTTPBody]> {
89
90
  if (!this.downstreamProtocol) {
90
91
  return await this.proxyFunc(url, method, body);
@@ -117,12 +118,12 @@ export class ProtocolConverter {
117
118
  this.downstreamProtocol === MJSONWP ? jsonwpConverter(url) : w3cConverter(url);
118
119
  if (rewrittenUrl === url) {
119
120
  this.log.debug(
120
- `Did not know how to rewrite the original URL '${url}' for ${this.downstreamProtocol} protocol`
121
+ `Did not know how to rewrite the original URL '${url}' for ${this.downstreamProtocol} protocol`,
121
122
  );
122
123
  break;
123
124
  }
124
125
  this.log.info(
125
- `Rewrote the original URL '${url}' to '${rewrittenUrl}' for ${this.downstreamProtocol} protocol`
126
+ `Rewrote the original URL '${url}' to '${rewrittenUrl}' for ${this.downstreamProtocol} protocol`,
126
127
  );
127
128
  return await this.proxyFunc(rewrittenUrl, method, body);
128
129
  }
@@ -142,7 +143,11 @@ export class ProtocolConverter {
142
143
  }
143
144
 
144
145
  const bodyObj = (util.safeJsonParse(body) as Record<string, unknown>) ?? {};
145
- if (this.downstreamProtocol === W3C && Object.hasOwn(bodyObj, 'ms') && Object.hasOwn(bodyObj, 'type')) {
146
+ if (
147
+ this.downstreamProtocol === W3C &&
148
+ Object.hasOwn(bodyObj, 'ms') &&
149
+ Object.hasOwn(bodyObj, 'type')
150
+ ) {
146
151
  const typeToW3C = (x: string) => (x === 'page load' ? 'pageLoad' : x);
147
152
  return [
148
153
  {
@@ -151,15 +156,20 @@ export class ProtocolConverter {
151
156
  ];
152
157
  }
153
158
 
154
- if (this.downstreamProtocol === MJSONWP && (!Object.hasOwn(bodyObj, 'ms') || !Object.hasOwn(bodyObj, 'type'))) {
159
+ if (
160
+ this.downstreamProtocol === MJSONWP &&
161
+ (!Object.hasOwn(bodyObj, 'ms') || !Object.hasOwn(bodyObj, 'type'))
162
+ ) {
155
163
  const typeToJSONWP = (x: string) => (x === 'pageLoad' ? 'page load' : x);
156
- return Object.entries(bodyObj)
157
- // Only transform the entry if ms value is a valid positive float number
158
- .filter((pair) => /^\d+(?:[.,]\d*?)?$/.test(`${pair[1]}`))
159
- .map((pair) => ({
160
- type: typeToJSONWP(pair[0]),
161
- ms: pair[1],
162
- }));
164
+ return (
165
+ Object.entries(bodyObj)
166
+ // Only transform the entry if ms value is a valid positive float number
167
+ .filter((pair) => /^\d+(?:[.,]\d*?)?$/.test(`${pair[1]}`))
168
+ .map((pair) => ({
169
+ type: typeToJSONWP(pair[0]),
170
+ ms: pair[1],
171
+ }))
172
+ );
163
173
  }
164
174
 
165
175
  return [bodyObj];
@@ -171,14 +181,14 @@ export class ProtocolConverter {
171
181
  private async proxySetTimeouts(
172
182
  url: string,
173
183
  method: string,
174
- body?: HTTPBody
184
+ body?: HTTPBody,
175
185
  ): Promise<[ProxyResponse, HTTPBody]> {
176
186
  const timeoutRequestObjects = this.getTimeoutRequestObjects(body);
177
187
  if (timeoutRequestObjects.length === 0) {
178
188
  return await this.proxyFunc(url, method, body);
179
189
  }
180
190
  this.log.debug(
181
- `Will send the following request bodies to /timeouts: ${JSON.stringify(timeoutRequestObjects)}`
191
+ `Will send the following request bodies to /timeouts: ${JSON.stringify(timeoutRequestObjects)}`,
182
192
  );
183
193
 
184
194
  let response!: ProxyResponse;
@@ -202,12 +212,16 @@ export class ProtocolConverter {
202
212
  private async proxySetWindow(
203
213
  url: string,
204
214
  method: string,
205
- body: HTTPBody
215
+ body: HTTPBody,
206
216
  ): Promise<[ProxyResponse, HTTPBody]> {
207
217
  const bodyObj = util.safeJsonParse(body);
208
218
  if (util.isPlainObject(bodyObj)) {
209
219
  const obj = bodyObj as Record<string, unknown>;
210
- if (this.downstreamProtocol === W3C && Object.hasOwn(bodyObj, 'name') && !Object.hasOwn(bodyObj, 'handle')) {
220
+ if (
221
+ this.downstreamProtocol === W3C &&
222
+ Object.hasOwn(bodyObj, 'name') &&
223
+ !Object.hasOwn(bodyObj, 'handle')
224
+ ) {
211
225
  this.log.debug(`Copied 'name' value '${obj.name}' to 'handle' as per W3C spec`);
212
226
  return await this.proxyFunc(url, method, {...obj, handle: obj.name});
213
227
  }
@@ -226,10 +240,13 @@ export class ProtocolConverter {
226
240
  private async proxySetValue(
227
241
  url: string,
228
242
  method: string,
229
- body: HTTPBody
243
+ body: HTTPBody,
230
244
  ): Promise<[ProxyResponse, HTTPBody]> {
231
245
  const bodyObj = util.safeJsonParse(body) as Record<string, unknown> | undefined;
232
- if (util.isPlainObject(bodyObj) && (util.hasValue(bodyObj?.text) || util.hasValue(bodyObj?.value))) {
246
+ if (
247
+ util.isPlainObject(bodyObj) &&
248
+ (util.hasValue(bodyObj?.text) || util.hasValue(bodyObj?.value))
249
+ ) {
233
250
  let {text, value} = bodyObj;
234
251
  if (util.hasValue(text) && !util.hasValue(value)) {
235
252
  value = typeof text === 'string' ? [...text] : Array.isArray(text) ? text : [];
@@ -246,13 +263,20 @@ export class ProtocolConverter {
246
263
  private async proxySetFrame(
247
264
  url: string,
248
265
  method: string,
249
- body: HTTPBody
266
+ body: HTTPBody,
250
267
  ): Promise<[ProxyResponse, HTTPBody]> {
251
268
  const bodyObj = util.safeJsonParse(body);
252
- if (Object.hasOwn(bodyObj ?? {}, 'id') && util.isPlainObject((bodyObj as Record<string, unknown>).id)) {
269
+ if (
270
+ Object.hasOwn(bodyObj ?? {}, 'id') &&
271
+ util.isPlainObject((bodyObj as Record<string, unknown>).id)
272
+ ) {
253
273
  return await this.proxyFunc(url, method, {
254
274
  ...(bodyObj as object),
255
- id: duplicateKeys((bodyObj as Record<string, unknown>).id as object, MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY),
275
+ id: duplicateKeys(
276
+ (bodyObj as Record<string, unknown>).id as object,
277
+ MJSONWP_ELEMENT_KEY,
278
+ W3C_ELEMENT_KEY,
279
+ ),
256
280
  });
257
281
  }
258
282
  return await this.proxyFunc(url, method, body);
@@ -261,14 +285,14 @@ export class ProtocolConverter {
261
285
  private async proxyPerformActions(
262
286
  url: string,
263
287
  method: string,
264
- body: HTTPBody
288
+ body: HTTPBody,
265
289
  ): Promise<[ProxyResponse, HTTPBody]> {
266
290
  const bodyObj = util.safeJsonParse(body);
267
291
  if (util.isPlainObject(bodyObj)) {
268
292
  return await this.proxyFunc(
269
293
  url,
270
294
  method,
271
- duplicateKeys(bodyObj as object, MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY)
295
+ duplicateKeys(bodyObj as object, MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY),
272
296
  );
273
297
  }
274
298
  return await this.proxyFunc(url, method, body);
@@ -276,7 +300,7 @@ export class ProtocolConverter {
276
300
 
277
301
  private async proxyReleaseActions(
278
302
  url: string,
279
- method: string
303
+ method: string,
280
304
  ): Promise<[ProxyResponse, HTTPBody]> {
281
305
  return await this.proxyFunc(url, method);
282
306
  }
@@ -31,7 +31,7 @@ import type {AxiosError, AxiosResponse, RawAxiosRequestConfig} from 'axios';
31
31
  const DEFAULT_LOG = logger.getLogger('WD Proxy');
32
32
  const DEFAULT_REQUEST_TIMEOUT = 240000;
33
33
  const COMMAND_WITH_SESSION_ID_MATCHER = pathToRegexMatch(
34
- '{/*prefix}/session/:sessionId{/*command}'
34
+ '{/*prefix}/session/:sessionId{/*command}',
35
35
  );
36
36
 
37
37
  const {MJSONWP, W3C} = PROTOCOLS;
@@ -71,7 +71,7 @@ export class JWProxy {
71
71
  constructor(opts: ProxyOptions = {}) {
72
72
  const filteredOptsWithoutLog = omit(
73
73
  pick(opts as Record<string, unknown>, ALLOWED_OPTS),
74
- 'log'
74
+ 'log',
75
75
  ) as Omit<ProxyOptions, 'log'>;
76
76
  const options = {
77
77
  scheme: 'http',
@@ -92,7 +92,14 @@ export class JWProxy {
92
92
  timeout: number;
93
93
  };
94
94
  options.scheme = options.scheme.toLowerCase();
95
- Object.assign(this, options);
95
+ this.scheme = options.scheme;
96
+ this.server = options.server;
97
+ this.port = options.port;
98
+ this.base = options.base;
99
+ this.reqBasePath = options.reqBasePath;
100
+ this.sessionId = options.sessionId;
101
+ this.timeout = options.timeout;
102
+ this.headers = options.headers;
96
103
 
97
104
  this._activeRequests = [];
98
105
  this._downstreamProtocol = null;
@@ -151,11 +158,8 @@ export class JWProxy {
151
158
  getUrlForProxy(url: string, method?: HTTPMethod): string {
152
159
  const parsedUrl = this._parseUrl(url);
153
160
  const normalizedPathname = this._toNormalizedPathname(parsedUrl);
154
- const commandName = normalizedPathname
155
- ? routeToCommandName(normalizedPathname, method)
156
- : '';
157
- const requiresSessionId =
158
- !commandName || (commandName && isSessionCommand(commandName));
161
+ const commandName = normalizedPathname ? routeToCommandName(normalizedPathname, method) : '';
162
+ const requiresSessionId = !commandName || (commandName && isSessionCommand(commandName));
159
163
  const proxyPrefix = `${this.scheme}://${this.server}:${this.port}${this.base}`;
160
164
  let proxySuffix = normalizedPathname ? `/${normalizedPathname.replace(/^\/+/, '')}` : '';
161
165
  if (parsedUrl.search) {
@@ -165,9 +169,7 @@ export class JWProxy {
165
169
  return `${proxyPrefix}${proxySuffix}`;
166
170
  }
167
171
  if (!this.sessionId) {
168
- throw new ReferenceError(
169
- `Session ID is not set, but saw a URL that requires it (${url})`
170
- );
172
+ throw new ReferenceError(`Session ID is not set, but saw a URL that requires it (${url})`);
171
173
  }
172
174
  return `${proxyPrefix}/session/${this.sessionId}${proxySuffix}`;
173
175
  }
@@ -178,7 +180,7 @@ export class JWProxy {
178
180
  async proxy(
179
181
  url: string,
180
182
  method: string,
181
- body: HTTPBody = null
183
+ body: HTTPBody = null,
182
184
  ): Promise<[ProxyResponse, HTTPBody]> {
183
185
  method = method.toUpperCase();
184
186
  const newUrl = this.getUrlForProxy(url, method as HTTPMethod);
@@ -210,11 +212,11 @@ export class JWProxy {
210
212
  this.log.warn(
211
213
  'Invalid body payload (%s): %s',
212
214
  (error as Error).message,
213
- logger.markSensitive(truncateBody(body))
215
+ logger.markSensitive(truncateBody(body)),
214
216
  );
215
217
  throw new Error(
216
218
  'Cannot interpret the request body as valid JSON. Check the server log for more details.',
217
- {cause: error}
219
+ {cause: error},
218
220
  );
219
221
  }
220
222
  } else {
@@ -228,7 +230,7 @@ export class JWProxy {
228
230
  url || '/',
229
231
  method,
230
232
  newUrl,
231
- reqOpts.data ? logger.markSensitive(truncateBody(reqOpts.data)) : 'no'
233
+ reqOpts.data ? logger.markSensitive(truncateBody(reqOpts.data)) : 'no',
232
234
  );
233
235
 
234
236
  const throwProxyError = (error: unknown): never => {
@@ -258,8 +260,7 @@ export class JWProxy {
258
260
  if (status === 200) {
259
261
  const value = data.value as Record<string, unknown> | undefined;
260
262
  const raw = data.sessionId ?? value?.sessionId;
261
- this.sessionId =
262
- typeof raw === 'string' ? raw : raw != null ? String(raw) : null;
263
+ this.sessionId = typeof raw === 'string' ? raw : raw != null ? String(raw) : null;
263
264
  }
264
265
  this.downstreamProtocol = this.getProtocolFromResBody(data) ?? this.downstreamProtocol;
265
266
  this.log.info(`Determined the downstream protocol as '${this.downstreamProtocol}'`);
@@ -284,18 +285,14 @@ export class JWProxy {
284
285
  this.log.info(
285
286
  util.hasValue(err.response.status)
286
287
  ? `Got response with status ${err.response.status}: ${error}`
287
- : `Got response with unknown status: ${error}`
288
+ : `Got response with unknown status: ${error}`,
288
289
  );
289
290
  }
290
291
  } else {
291
292
  proxyErrorMsg = `Could not proxy command to the remote server. Original error: ${err.message}`;
292
293
  this.log.info(err.message);
293
294
  }
294
- throw new errors.ProxyRequestError(
295
- proxyErrorMsg,
296
- err.response?.data,
297
- err.response?.status
298
- );
295
+ throw new errors.ProxyRequestError(proxyErrorMsg, err.response?.data, err.response?.status);
299
296
  }
300
297
  }
301
298
 
@@ -317,13 +314,11 @@ export class JWProxy {
317
314
  async proxyCommand(
318
315
  url: string,
319
316
  method: HTTPMethod,
320
- body: HTTPBody = null
317
+ body: HTTPBody = null,
321
318
  ): Promise<[ProxyResponse, HTTPBody]> {
322
319
  const parsedUrl = this._parseUrl(url);
323
320
  const normalizedPathname = this._toNormalizedPathname(parsedUrl);
324
- const commandName = normalizedPathname
325
- ? routeToCommandName(normalizedPathname, method)
326
- : '';
321
+ const commandName = normalizedPathname ? routeToCommandName(normalizedPathname, method) : '';
327
322
  if (!commandName) {
328
323
  return await this.proxy(url, method, body);
329
324
  }
@@ -335,11 +330,7 @@ export class JWProxy {
335
330
  /**
336
331
  * Executes a WebDriver command and returns the unwrapped `value` field (or throws).
337
332
  */
338
- async command(
339
- url: string,
340
- method: HTTPMethod,
341
- body: HTTPBody = null
342
- ): Promise<HTTPBody> {
333
+ async command(url: string, method: HTTPMethod, body: HTTPBody = null): Promise<HTTPBody> {
343
334
  let response: ProxyResponse;
344
335
  let resBodyObj: HTTPBody;
345
336
  try {
@@ -362,9 +353,12 @@ export class JWProxy {
362
353
  if (util.isPlainObject(message) && Object.hasOwn(message, 'message')) {
363
354
  message = (message as Record<string, unknown>).message;
364
355
  }
365
- throw errorFromMJSONWPStatusCode(status, util.isEmpty(message)
366
- ? getSummaryByCode(status)
367
- : (message as string | {message: string}));
356
+ throw errorFromMJSONWPStatusCode(
357
+ status,
358
+ util.isEmpty(message)
359
+ ? getSummaryByCode(status)
360
+ : (message as string | {message: string}),
361
+ );
368
362
  }
369
363
  } else if (protocol === W3C) {
370
364
  if (response.statusCode < 300) {
@@ -375,7 +369,7 @@ export class JWProxy {
375
369
  throw errorFromW3CJsonCode(
376
370
  value.error as string,
377
371
  (value.message as string) ?? '',
378
- value.stacktrace as string | undefined
372
+ value.stacktrace as string | undefined,
379
373
  );
380
374
  }
381
375
  } else if (response.statusCode === 200) {
@@ -385,7 +379,7 @@ export class JWProxy {
385
379
  `Did not know what to do with response code '${response.statusCode}' ` +
386
380
  `and response body '${util.truncateString(JSON.stringify(resBodyObj), {
387
381
  length: 300,
388
- })}'`
382
+ })}'`,
389
383
  );
390
384
  }
391
385
 
@@ -410,20 +404,22 @@ export class JWProxy {
410
404
  const [response, body] = await this.proxyCommand(
411
405
  req.originalUrl,
412
406
  req.method as HTTPMethod,
413
- req.body
407
+ req.body,
414
408
  );
415
409
  statusCode = response.statusCode;
416
410
  resBodyObj = body;
417
411
  } catch (err: unknown) {
418
412
  [statusCode, resBodyObj] = getResponseForW3CError(
419
- isErrorType(err, errors.ProxyRequestError) ? (err as InstanceType<typeof errors.ProxyRequestError>).getActualError() : err
413
+ isErrorType(err, errors.ProxyRequestError)
414
+ ? (err as InstanceType<typeof errors.ProxyRequestError>).getActualError()
415
+ : err,
420
416
  );
421
417
  }
422
418
  res.setHeader('content-type', 'application/json; charset=utf-8');
423
419
  if (!util.isPlainObject(resBodyObj)) {
424
420
  const error = new errors.UnknownError(
425
421
  `The downstream server response with the status code ${statusCode} is not a valid JSON object: ` +
426
- util.truncateString(`${resBodyObj}`, {length: 300})
422
+ util.truncateString(`${resBodyObj}`, {length: 300}),
427
423
  );
428
424
  [statusCode, resBodyObj] = getResponseForW3CError(error);
429
425
  }
@@ -487,10 +483,14 @@ export class JWProxy {
487
483
  // This is needed for the backward compatibility
488
484
  // if drivers don't set reqBasePath properly
489
485
  if (!this.reqBasePath) {
490
- if (match && match.params && Array.isArray((match.params as Record<string, unknown>).prefix)) {
486
+ if (
487
+ match &&
488
+ match.params &&
489
+ Array.isArray((match.params as Record<string, unknown>).prefix)
490
+ ) {
491
491
  pathname = pathname.replace(
492
492
  `/${((match.params as Record<string, unknown>).prefix as string[]).join('/')}`,
493
- ''
493
+ '',
494
494
  );
495
495
  } else if (pathname.startsWith('/wd/hub')) {
496
496
  pathname = pathname.replace('/wd/hub', '');