@appium/base-driver 10.0.0-beta.0 → 10.0.0-beta.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 (92) hide show
  1. package/README.md +0 -8
  2. package/build/lib/basedriver/capabilities.d.ts.map +1 -1
  3. package/build/lib/basedriver/capabilities.js +2 -4
  4. package/build/lib/basedriver/capabilities.js.map +1 -1
  5. package/build/lib/basedriver/commands/timeout.js +7 -25
  6. package/build/lib/basedriver/commands/timeout.js.map +1 -1
  7. package/build/lib/basedriver/core.d.ts +0 -8
  8. package/build/lib/basedriver/core.d.ts.map +1 -1
  9. package/build/lib/basedriver/core.js +8 -18
  10. package/build/lib/basedriver/core.js.map +1 -1
  11. package/build/lib/basedriver/driver.js +2 -2
  12. package/build/lib/basedriver/driver.js.map +1 -1
  13. package/build/lib/basedriver/helpers.d.ts +9 -1
  14. package/build/lib/basedriver/helpers.d.ts.map +1 -1
  15. package/build/lib/basedriver/helpers.js +56 -142
  16. package/build/lib/basedriver/helpers.js.map +1 -1
  17. package/build/lib/basedriver/validation.d.ts +7 -0
  18. package/build/lib/basedriver/validation.d.ts.map +1 -0
  19. package/build/lib/basedriver/validation.js +130 -0
  20. package/build/lib/basedriver/validation.js.map +1 -0
  21. package/build/lib/express/middleware.d.ts +0 -6
  22. package/build/lib/express/middleware.d.ts.map +1 -1
  23. package/build/lib/express/middleware.js +28 -60
  24. package/build/lib/express/middleware.js.map +1 -1
  25. package/build/lib/express/server.d.ts.map +1 -1
  26. package/build/lib/express/server.js +0 -1
  27. package/build/lib/express/server.js.map +1 -1
  28. package/build/lib/helpers/capabilities.d.ts +13 -6
  29. package/build/lib/helpers/capabilities.d.ts.map +1 -1
  30. package/build/lib/helpers/capabilities.js +7 -0
  31. package/build/lib/helpers/capabilities.js.map +1 -1
  32. package/build/lib/index.d.ts +1 -0
  33. package/build/lib/index.d.ts.map +1 -1
  34. package/build/lib/index.js +3 -1
  35. package/build/lib/index.js.map +1 -1
  36. package/build/lib/jsonwp-proxy/proxy.d.ts +0 -8
  37. package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
  38. package/build/lib/jsonwp-proxy/proxy.js +7 -38
  39. package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
  40. package/build/lib/protocol/errors.d.ts +171 -277
  41. package/build/lib/protocol/errors.d.ts.map +1 -1
  42. package/build/lib/protocol/errors.js +201 -421
  43. package/build/lib/protocol/errors.js.map +1 -1
  44. package/build/lib/protocol/helpers.d.ts +6 -6
  45. package/build/lib/protocol/helpers.d.ts.map +1 -1
  46. package/build/lib/protocol/helpers.js +11 -7
  47. package/build/lib/protocol/helpers.js.map +1 -1
  48. package/build/lib/protocol/index.d.ts +2 -1
  49. package/build/lib/protocol/index.d.ts.map +1 -1
  50. package/build/lib/protocol/index.js +2 -1
  51. package/build/lib/protocol/index.js.map +1 -1
  52. package/build/lib/protocol/protocol.d.ts +5 -0
  53. package/build/lib/protocol/protocol.d.ts.map +1 -1
  54. package/build/lib/protocol/protocol.js +23 -23
  55. package/build/lib/protocol/protocol.js.map +1 -1
  56. package/build/lib/protocol/routes.d.ts +14 -715
  57. package/build/lib/protocol/routes.d.ts.map +1 -1
  58. package/build/lib/protocol/routes.js +28 -487
  59. package/build/lib/protocol/routes.js.map +1 -1
  60. package/build/lib/protocol/validators.d.ts +4 -7
  61. package/build/lib/protocol/validators.d.ts.map +1 -1
  62. package/build/lib/protocol/validators.js +4 -21
  63. package/build/lib/protocol/validators.js.map +1 -1
  64. package/lib/basedriver/capabilities.ts +2 -4
  65. package/lib/basedriver/commands/timeout.ts +11 -34
  66. package/lib/basedriver/core.ts +10 -19
  67. package/lib/basedriver/driver.ts +3 -3
  68. package/lib/basedriver/helpers.js +61 -167
  69. package/lib/basedriver/validation.ts +145 -0
  70. package/lib/express/middleware.js +32 -70
  71. package/lib/express/server.js +0 -2
  72. package/lib/helpers/capabilities.js +9 -4
  73. package/lib/index.js +2 -0
  74. package/lib/jsonwp-proxy/proxy.js +8 -45
  75. package/lib/protocol/{errors.js → errors.ts} +322 -436
  76. package/lib/protocol/helpers.js +12 -8
  77. package/lib/protocol/index.js +8 -1
  78. package/lib/protocol/protocol.js +25 -23
  79. package/lib/protocol/routes.js +30 -497
  80. package/lib/protocol/validators.ts +19 -0
  81. package/package.json +10 -11
  82. package/build/lib/basedriver/desired-caps.d.ts +0 -5
  83. package/build/lib/basedriver/desired-caps.d.ts.map +0 -1
  84. package/build/lib/basedriver/desired-caps.js +0 -92
  85. package/build/lib/basedriver/desired-caps.js.map +0 -1
  86. package/lib/basedriver/README.md +0 -36
  87. package/lib/basedriver/desired-caps.js +0 -103
  88. package/lib/express/README.md +0 -59
  89. package/lib/jsonwp-proxy/README.md +0 -52
  90. package/lib/jsonwp-status/README.md +0 -20
  91. package/lib/protocol/README.md +0 -100
  92. package/lib/protocol/validators.js +0 -38
@@ -1,51 +1,63 @@
1
1
  import _ from 'lodash';
2
2
  import {util, logger} from '@appium/support';
3
3
  import {StatusCodes as HTTPStatusCodes} from 'http-status-codes';
4
+ import type { ErrorBiDiCommandResponse, Class } from '@appium/types';
4
5
 
5
6
  const mjsonwpLog = logger.getLogger('MJSONWP');
6
7
  const w3cLog = logger.getLogger('W3C');
7
8
 
8
- const W3C_UNKNOWN_ERROR = 'unknown error';
9
-
10
9
  class BaseError extends Error {
11
- constructor(message = '') {
10
+ public cause: Error | undefined;
11
+ public message: string;
12
+ public name: string;
13
+ public stack: string | undefined;
14
+
15
+ constructor(message: string = '', cause?: Error) {
12
16
  super(message);
13
- /** @type {[string, () => any][]} */
14
- const propsMap = [
15
- ['message', () => message],
16
- ['name', () => this.constructor.name],
17
- ['stack', () => (new Error(message)).stack],
18
- ];
17
+ this.cause = cause;
18
+ this.message = message;
19
+ this.name = this.constructor.name;
20
+ this._formatStack();
21
+ }
22
+
23
+ private _formatStack(): void {
19
24
  // eslint-disable-next-line no-prototype-builtins
20
- const shouldSkipStack = Error.hasOwnProperty('captureStackTrace');
21
- for (const [propName, valueGetter] of propsMap) {
22
- if (propName === 'stack' && shouldSkipStack) {
23
- continue;
24
- }
25
- Object.defineProperty(this, propName, {
26
- configurable: true,
27
- enumerable: false,
28
- value: valueGetter(),
29
- writable: true,
30
- });
31
- }
32
- if (shouldSkipStack) {
25
+ if (Error.hasOwnProperty('captureStackTrace') && _.isEmpty(this.stack)) {
33
26
  Error.captureStackTrace(this, this.constructor);
34
27
  }
28
+ if (!_.isString(this.cause?.stack)) {
29
+ return;
30
+ }
31
+ if (_.isEmpty(this.stack)) {
32
+ this.stack = this.cause.stack;
33
+ return;
34
+ }
35
+ const stackLines = this.stack?.split('\n') ?? [];
36
+ stackLines.push('The above error is caused by');
37
+ stackLines.push(...this.cause.stack.split('\n'));
38
+ this.stack = stackLines.join('\n');
35
39
  }
36
40
  }
37
41
 
38
42
  // base error class for all of our errors
39
43
  export class ProtocolError extends BaseError {
40
- constructor(msg, jsonwpCode, w3cStatus, error) {
41
- super(msg);
42
- this.jsonwpCode = jsonwpCode;
43
- this.error = error || W3C_UNKNOWN_ERROR;
44
- if (this.jsonwpCode === null) {
45
- this.jsonwpCode = 13;
46
- }
47
- this.w3cStatus = w3cStatus || HTTPStatusCodes.BAD_REQUEST;
48
- this._stacktrace = null;
44
+ protected _stacktrace: string | undefined;
45
+ public jsonwpCode: number;
46
+ public error: string;
47
+ public w3cStatus: number;
48
+
49
+ constructor(
50
+ msg: string,
51
+ jsonwpCode: number,
52
+ w3cStatus: number,
53
+ w3cErrorSignature: string,
54
+ cause?: Error,
55
+ ) {
56
+ super(msg, cause);
57
+ this.jsonwpCode = jsonwpCode ?? UnknownError.code();
58
+ this.error = w3cErrorSignature ?? UnknownError.error();
59
+ this.w3cStatus = w3cStatus ?? UnknownError.w3cStatus();
60
+ this._stacktrace = undefined;
49
61
  }
50
62
 
51
63
  get stacktrace() {
@@ -58,14 +70,14 @@ export class ProtocolError extends BaseError {
58
70
 
59
71
  /**
60
72
  * Get the Bidi protocol version of an error
61
- * @param {string|number} id - the id used in the request for which this error forms the response
73
+ * @param id - the id used in the request for which this error forms the response
62
74
  * @see https://w3c.github.io/webdriver-bidi/#protocol-definition
63
- * @returns {import('@appium/types').ErrorBiDiCommandResponse} The object conforming to the shape of a BiDi error response
75
+ * @returns The object conforming to the shape of a BiDi error response
64
76
  */
65
- bidiErrObject(id) {
77
+ bidiErrObject(id: string|number): ErrorBiDiCommandResponse {
66
78
  // if we don't have an id, the client didn't send one, so we have nothing to send back.
67
79
  // send back zero rather than making something up
68
- const intId = /** @type {number} */ (_.isInteger(id) ? id : (parseInt(`${id}`, 10) || 0));
80
+ const intId = (_.isInteger(id) ? id : (parseInt(`${id}`, 10) || 0)) as number;
69
81
  return {
70
82
  id: intId,
71
83
  type: 'error',
@@ -91,15 +103,14 @@ export class NoSuchDriverError extends ProtocolError {
91
103
  static error() {
92
104
  return 'invalid session id';
93
105
  }
94
- /**
95
- * @param {string} [message] error message
96
- */
97
- constructor(message) {
106
+
107
+ constructor(message: string = '', cause?: Error) {
98
108
  super(
99
109
  message || 'A session is either terminated or not started',
100
110
  NoSuchDriverError.code(),
101
111
  NoSuchDriverError.w3cStatus(),
102
112
  NoSuchDriverError.error(),
113
+ cause,
103
114
  );
104
115
  }
105
116
  }
@@ -114,16 +125,15 @@ export class NoSuchElementError extends ProtocolError {
114
125
  static error() {
115
126
  return 'no such element';
116
127
  }
117
- /**
118
- * @param {string} [message] error message
119
- */
120
- constructor(message) {
128
+
129
+ constructor(message: string = '', cause?: Error) {
121
130
  super(
122
131
  message ||
123
132
  'An element could not be located on the page using the given ' + 'search parameters.',
124
133
  NoSuchElementError.code(),
125
134
  NoSuchElementError.w3cStatus(),
126
135
  NoSuchElementError.error(),
136
+ cause,
127
137
  );
128
138
  }
129
139
  }
@@ -138,11 +148,8 @@ export class NoSuchFrameError extends ProtocolError {
138
148
  static w3cStatus() {
139
149
  return HTTPStatusCodes.NOT_FOUND;
140
150
  }
141
- /**
142
- *
143
- * @param {string} [message]
144
- */
145
- constructor(message) {
151
+
152
+ constructor(message: string = '', cause?: Error) {
146
153
  super(
147
154
  message ||
148
155
  'A request to switch to a frame could not be satisfied because ' +
@@ -150,6 +157,7 @@ export class NoSuchFrameError extends ProtocolError {
150
157
  NoSuchFrameError.code(),
151
158
  NoSuchFrameError.w3cStatus(),
152
159
  NoSuchFrameError.error(),
160
+ cause,
153
161
  );
154
162
  }
155
163
  }
@@ -164,11 +172,8 @@ export class UnknownCommandError extends ProtocolError {
164
172
  static error() {
165
173
  return 'unknown command';
166
174
  }
167
- /**
168
- *
169
- * @param {string} [message]
170
- */
171
- constructor(message) {
175
+
176
+ constructor(message: string = '', cause?: Error) {
172
177
  super(
173
178
  message ||
174
179
  'The requested resource could not be found, or a request was ' +
@@ -177,6 +182,7 @@ export class UnknownCommandError extends ProtocolError {
177
182
  UnknownCommandError.code(),
178
183
  UnknownCommandError.w3cStatus(),
179
184
  UnknownCommandError.error(),
185
+ cause,
180
186
  );
181
187
  }
182
188
  }
@@ -191,11 +197,8 @@ export class StaleElementReferenceError extends ProtocolError {
191
197
  static error() {
192
198
  return 'stale element reference';
193
199
  }
194
- /**
195
- *
196
- * @param {string} [message]
197
- */
198
- constructor(message) {
200
+
201
+ constructor(message: string = '', cause?: Error) {
199
202
  super(
200
203
  message ||
201
204
  'An element command failed because the referenced element is no ' +
@@ -203,6 +206,7 @@ export class StaleElementReferenceError extends ProtocolError {
203
206
  StaleElementReferenceError.code(),
204
207
  StaleElementReferenceError.w3cStatus(),
205
208
  StaleElementReferenceError.error(),
209
+ cause,
206
210
  );
207
211
  }
208
212
  }
@@ -217,10 +221,8 @@ export class ElementNotVisibleError extends ProtocolError {
217
221
  static error() {
218
222
  return 'element not visible';
219
223
  }
220
- /**
221
- * @param {string} [message] error message
222
- */
223
- constructor(message) {
224
+
225
+ constructor(message: string = '', cause?: Error) {
224
226
  super(
225
227
  message ||
226
228
  'An element command could not be completed because the element is ' +
@@ -228,6 +230,7 @@ export class ElementNotVisibleError extends ProtocolError {
228
230
  ElementNotVisibleError.code(),
229
231
  ElementNotVisibleError.w3cStatus(),
230
232
  ElementNotVisibleError.error(),
233
+ cause,
231
234
  );
232
235
  }
233
236
  }
@@ -242,11 +245,8 @@ export class InvalidElementStateError extends ProtocolError {
242
245
  static error() {
243
246
  return 'invalid element state';
244
247
  }
245
- /**
246
- *
247
- * @param {string} [message]
248
- */
249
- constructor(message) {
248
+
249
+ constructor(message: string = '', cause?: Error) {
250
250
  super(
251
251
  message ||
252
252
  'An element command could not be completed because the element is ' +
@@ -254,6 +254,7 @@ export class InvalidElementStateError extends ProtocolError {
254
254
  InvalidElementStateError.code(),
255
255
  InvalidElementStateError.w3cStatus(),
256
256
  InvalidElementStateError.error(),
257
+ cause,
257
258
  );
258
259
  }
259
260
  }
@@ -266,16 +267,17 @@ export class UnknownError extends ProtocolError {
266
267
  return HTTPStatusCodes.INTERNAL_SERVER_ERROR;
267
268
  }
268
269
  static error() {
269
- return W3C_UNKNOWN_ERROR;
270
+ return 'unknown error';
270
271
  }
271
- constructor(errorOrMessage) {
272
- const origMessage = _.isString((errorOrMessage || {}).message)
273
- ? errorOrMessage.message
274
- : errorOrMessage;
275
- const message =
276
- 'An unknown server-side error occurred while processing the command.' +
277
- (origMessage ? ` Original error: ${origMessage}` : '');
278
- super(message, UnknownError.code(), UnknownError.w3cStatus(), UnknownError.error());
272
+
273
+ constructor(message: string = '', cause?: Error) {
274
+ super(
275
+ message || 'An unknown server-side error occurred while processing the command.',
276
+ UnknownError.code(),
277
+ UnknownError.w3cStatus(),
278
+ UnknownError.error(),
279
+ cause,
280
+ );
279
281
  }
280
282
  }
281
283
 
@@ -289,16 +291,15 @@ export class UnknownMethodError extends ProtocolError {
289
291
  static error() {
290
292
  return 'unknown method';
291
293
  }
292
- /**
293
- * @param {string} [message] error message
294
- */
295
- constructor(message) {
294
+
295
+ constructor(message: string = '', cause?: Error) {
296
296
  super(
297
297
  message ||
298
298
  'The requested command matched a known URL but did not match an method for that URL',
299
299
  UnknownMethodError.code(),
300
300
  UnknownMethodError.w3cStatus(),
301
301
  UnknownMethodError.error(),
302
+ cause,
302
303
  );
303
304
  }
304
305
  }
@@ -313,15 +314,14 @@ export class UnsupportedOperationError extends ProtocolError {
313
314
  static error() {
314
315
  return 'unsupported operation';
315
316
  }
316
- /**
317
- * @param {string} [message] error message
318
- */
319
- constructor(message) {
317
+
318
+ constructor(message: string = '', cause?: Error) {
320
319
  super(
321
320
  message || 'A server-side error occurred. Command cannot be supported.',
322
321
  UnsupportedOperationError.code(),
323
322
  UnsupportedOperationError.w3cStatus(),
324
323
  UnsupportedOperationError.error(),
324
+ cause,
325
325
  );
326
326
  }
327
327
  }
@@ -336,15 +336,14 @@ export class ElementIsNotSelectableError extends ProtocolError {
336
336
  static w3cStatus() {
337
337
  return HTTPStatusCodes.BAD_REQUEST;
338
338
  }
339
- /**
340
- * @param {string} [message] error message
341
- */
342
- constructor(message) {
339
+
340
+ constructor(message: string = '', cause?: Error) {
343
341
  super(
344
342
  message || 'An attempt was made to select an element that cannot be selected.',
345
343
  ElementIsNotSelectableError.code(),
346
344
  ElementIsNotSelectableError.w3cStatus(),
347
345
  ElementIsNotSelectableError.error(),
346
+ cause,
348
347
  );
349
348
  }
350
349
  }
@@ -359,10 +358,8 @@ export class ElementClickInterceptedError extends ProtocolError {
359
358
  static w3cStatus() {
360
359
  return HTTPStatusCodes.BAD_REQUEST;
361
360
  }
362
- /**
363
- * @param {string} [message] error message
364
- */
365
- constructor(message) {
361
+
362
+ constructor(message: string = '', cause?: Error) {
366
363
  super(
367
364
  message ||
368
365
  'The Element Click command could not be completed because the element receiving ' +
@@ -370,6 +367,7 @@ export class ElementClickInterceptedError extends ProtocolError {
370
367
  ElementClickInterceptedError.code(),
371
368
  ElementClickInterceptedError.w3cStatus(),
372
369
  ElementClickInterceptedError.error(),
370
+ cause,
373
371
  );
374
372
  }
375
373
  }
@@ -384,16 +382,15 @@ export class ElementNotInteractableError extends ProtocolError {
384
382
  static w3cStatus() {
385
383
  return HTTPStatusCodes.BAD_REQUEST;
386
384
  }
387
- /**
388
- * @param {string} [message] error message
389
- */
390
- constructor(message) {
385
+
386
+ constructor(message: string = '', cause?: Error) {
391
387
  super(
392
388
  message ||
393
389
  'A command could not be completed because the element is not pointer- or keyboard interactable',
394
390
  ElementNotInteractableError.code(),
395
391
  ElementNotInteractableError.w3cStatus(),
396
392
  ElementNotInteractableError.error(),
393
+ cause,
397
394
  );
398
395
  }
399
396
  }
@@ -402,16 +399,18 @@ export class InsecureCertificateError extends ProtocolError {
402
399
  static error() {
403
400
  return 'insecure certificate';
404
401
  }
405
- /**
406
- * @param {string} [message] error message
407
- */
408
- constructor(message) {
402
+ static w3cStatus() {
403
+ return HTTPStatusCodes.BAD_REQUEST;
404
+ }
405
+
406
+ constructor(message: string = '', cause?: Error) {
409
407
  super(
410
408
  message ||
411
409
  'Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate',
412
- ElementIsNotSelectableError.code(),
413
- null,
410
+ UnknownError.code(),
411
+ InsecureCertificateError.w3cStatus(),
414
412
  InsecureCertificateError.error(),
413
+ cause,
415
414
  );
416
415
  }
417
416
  }
@@ -426,15 +425,14 @@ export class JavaScriptError extends ProtocolError {
426
425
  static error() {
427
426
  return 'javascript error';
428
427
  }
429
- /**
430
- * @param {string} [message] error message
431
- */
432
- constructor(message) {
428
+
429
+ constructor(message: string = '', cause?: Error) {
433
430
  super(
434
431
  message || 'An error occurred while executing user supplied JavaScript.',
435
432
  JavaScriptError.code(),
436
433
  JavaScriptError.w3cStatus(),
437
434
  JavaScriptError.error(),
435
+ cause,
438
436
  );
439
437
  }
440
438
  }
@@ -449,15 +447,14 @@ export class XPathLookupError extends ProtocolError {
449
447
  static error() {
450
448
  return 'invalid selector';
451
449
  }
452
- /**
453
- * @param {string} [message] error message
454
- */
455
- constructor(message) {
450
+
451
+ constructor(message: string = '', cause?: Error) {
456
452
  super(
457
453
  message || 'An error occurred while searching for an element by XPath.',
458
454
  XPathLookupError.code(),
459
455
  XPathLookupError.w3cStatus(),
460
456
  XPathLookupError.error(),
457
+ cause,
461
458
  );
462
459
  }
463
460
  }
@@ -472,15 +469,14 @@ export class TimeoutError extends ProtocolError {
472
469
  static error() {
473
470
  return 'timeout';
474
471
  }
475
- /**
476
- * @param {string} [message] error message
477
- */
478
- constructor(message) {
472
+
473
+ constructor(message: string = '', cause?: Error) {
479
474
  super(
480
475
  message || 'An operation did not complete before its timeout expired.',
481
476
  TimeoutError.code(),
482
477
  TimeoutError.w3cStatus(),
483
478
  TimeoutError.error(),
479
+ cause,
484
480
  );
485
481
  }
486
482
  }
@@ -495,10 +491,8 @@ export class NoSuchWindowError extends ProtocolError {
495
491
  static w3cStatus() {
496
492
  return HTTPStatusCodes.NOT_FOUND;
497
493
  }
498
- /**
499
- * @param {string} [message] error message
500
- */
501
- constructor(message) {
494
+
495
+ constructor(message: string = '', cause?: Error) {
502
496
  super(
503
497
  message ||
504
498
  'A request to switch to a different window could not be satisfied ' +
@@ -506,6 +500,7 @@ export class NoSuchWindowError extends ProtocolError {
506
500
  NoSuchWindowError.code(),
507
501
  NoSuchWindowError.w3cStatus(),
508
502
  NoSuchWindowError.error(),
503
+ cause,
509
504
  );
510
505
  }
511
506
  }
@@ -520,15 +515,14 @@ export class InvalidArgumentError extends ProtocolError {
520
515
  static w3cStatus() {
521
516
  return HTTPStatusCodes.BAD_REQUEST;
522
517
  }
523
- /**
524
- * @param {string} [err] error message
525
- */
526
- constructor(err) {
518
+
519
+ constructor(message: string = '', cause?: Error) {
527
520
  super(
528
- err || 'The arguments passed to the command are either invalid or malformed',
521
+ message || 'The arguments passed to the command are either invalid or malformed',
529
522
  InvalidArgumentError.code(),
530
523
  InvalidArgumentError.w3cStatus(),
531
524
  InvalidArgumentError.error(),
525
+ cause,
532
526
  );
533
527
  }
534
528
  }
@@ -543,17 +537,16 @@ export class InvalidCookieDomainError extends ProtocolError {
543
537
  static w3cStatus() {
544
538
  return HTTPStatusCodes.BAD_REQUEST;
545
539
  }
546
- /**
547
- * @param {string} [err] error message
548
- */
549
- constructor(err) {
540
+
541
+ constructor(message: string = '', cause?: Error) {
550
542
  super(
551
- err ||
543
+ message ||
552
544
  'An illegal attempt was made to set a cookie under a different ' +
553
545
  'domain than the current page.',
554
546
  InvalidCookieDomainError.code(),
555
547
  InvalidCookieDomainError.w3cStatus(),
556
548
  InvalidCookieDomainError.error(),
549
+ cause,
557
550
  );
558
551
  }
559
552
  }
@@ -568,16 +561,15 @@ export class NoSuchCookieError extends ProtocolError {
568
561
  static error() {
569
562
  return 'no such cookie';
570
563
  }
571
- /**
572
- * @param {string} [err] error message
573
- */
574
- constructor(err) {
564
+
565
+ constructor(message: string = '', cause?: Error) {
575
566
  super(
576
- err ||
567
+ message ||
577
568
  'No cookie matching the given path name was found amongst the associated cookies of the current browsing context’s active document',
578
569
  NoSuchCookieError.code(),
579
570
  NoSuchCookieError.w3cStatus(),
580
571
  NoSuchCookieError.error(),
572
+ cause,
581
573
  );
582
574
  }
583
575
  }
@@ -592,15 +584,14 @@ export class UnableToSetCookieError extends ProtocolError {
592
584
  static error() {
593
585
  return 'unable to set cookie';
594
586
  }
595
- /**
596
- * @param {string} [err] error message
597
- */
598
- constructor(err) {
587
+
588
+ constructor(message: string = '', cause?: Error) {
599
589
  super(
600
- err || "A request to set a cookie's value could not be satisfied.",
590
+ message || "A request to set a cookie's value could not be satisfied.",
601
591
  UnableToSetCookieError.code(),
602
592
  UnableToSetCookieError.w3cStatus(),
603
593
  UnableToSetCookieError.error(),
594
+ cause,
604
595
  );
605
596
  }
606
597
  }
@@ -615,15 +606,13 @@ export class UnexpectedAlertOpenError extends ProtocolError {
615
606
  static error() {
616
607
  return 'unexpected alert open';
617
608
  }
618
- /**
619
- * @param {string} [message] error message
620
- */
621
- constructor(message) {
609
+ constructor(message: string = '', cause?: Error) {
622
610
  super(
623
611
  message || 'A modal dialog was open, blocking this operation',
624
612
  UnexpectedAlertOpenError.code(),
625
613
  UnexpectedAlertOpenError.w3cStatus(),
626
614
  UnexpectedAlertOpenError.error(),
615
+ cause,
627
616
  );
628
617
  }
629
618
  }
@@ -638,16 +627,14 @@ export class NoAlertOpenError extends ProtocolError {
638
627
  static error() {
639
628
  return 'no such alert';
640
629
  }
641
- /**
642
- *
643
- * @param {string} [message]
644
- */
645
- constructor(message) {
630
+
631
+ constructor(message: string = '', cause?: Error) {
646
632
  super(
647
- message || 'An attempt was made to operate on a modal dialog when one ' + 'was not open.',
633
+ message || 'An attempt was made to operate on a modal dialog when one was not open.',
648
634
  NoAlertOpenError.code(),
649
635
  NoAlertOpenError.w3cStatus(),
650
636
  NoAlertOpenError.error(),
637
+ cause,
651
638
  );
652
639
  }
653
640
  }
@@ -664,15 +651,14 @@ export class ScriptTimeoutError extends ProtocolError {
664
651
  static error() {
665
652
  return 'script timeout';
666
653
  }
667
- /**
668
- * @param {string} [err] error message
669
- */
670
- constructor(err) {
654
+
655
+ constructor(message: string = '', cause?: Error) {
671
656
  super(
672
- err || 'A script did not complete before its timeout expired.',
657
+ message || 'A script did not complete before its timeout expired.',
673
658
  ScriptTimeoutError.code(),
674
659
  ScriptTimeoutError.w3cStatus(),
675
660
  ScriptTimeoutError.error(),
661
+ cause,
676
662
  );
677
663
  }
678
664
  }
@@ -687,15 +673,14 @@ export class InvalidElementCoordinatesError extends ProtocolError {
687
673
  static error() {
688
674
  return 'invalid coordinates';
689
675
  }
690
- /**
691
- * @param {string} [err] error message
692
- */
693
- constructor(err) {
676
+
677
+ constructor(message: string = '', cause?: Error) {
694
678
  super(
695
- err || 'The coordinates provided to an interactions operation are invalid.',
679
+ message || 'The coordinates provided to an interactions operation are invalid.',
696
680
  InvalidElementCoordinatesError.code(),
697
681
  InvalidElementCoordinatesError.w3cStatus(),
698
682
  InvalidElementCoordinatesError.error(),
683
+ cause,
699
684
  );
700
685
  }
701
686
  }
@@ -712,15 +697,14 @@ export class IMENotAvailableError extends ProtocolError {
712
697
  static error() {
713
698
  return 'unsupported operation';
714
699
  }
715
- /**
716
- * @param {string} [message] error message
717
- */
718
- constructor(message) {
700
+
701
+ constructor(message: string = '', cause?: Error) {
719
702
  super(
720
703
  message || 'IME was not available.',
721
704
  IMENotAvailableError.code(),
722
705
  IMENotAvailableError.w3cStatus(),
723
706
  IMENotAvailableError.error(),
707
+ cause,
724
708
  );
725
709
  }
726
710
  }
@@ -735,15 +719,14 @@ export class IMEEngineActivationFailedError extends ProtocolError {
735
719
  static error() {
736
720
  return 'unsupported operation';
737
721
  }
738
- /**
739
- * @param {string} [err] error message
740
- */
741
- constructor(err) {
722
+
723
+ constructor(message: string = '', cause?: Error) {
742
724
  super(
743
- err || 'An IME engine could not be started.',
725
+ message || 'An IME engine could not be started.',
744
726
  IMEEngineActivationFailedError.code(),
745
727
  IMEEngineActivationFailedError.w3cStatus(),
746
728
  IMEEngineActivationFailedError.error(),
729
+ cause,
747
730
  );
748
731
  }
749
732
  }
@@ -758,15 +741,14 @@ export class InvalidSelectorError extends ProtocolError {
758
741
  static error() {
759
742
  return 'invalid selector';
760
743
  }
761
- /**
762
- * @param {string} [err] error message
763
- */
764
- constructor(err) {
744
+
745
+ constructor(message: string = '', cause?: Error) {
765
746
  super(
766
- err || 'Argument was an invalid selector (e.g. XPath/CSS).',
747
+ message || 'Argument was an invalid selector (e.g. XPath/CSS).',
767
748
  InvalidSelectorError.code(),
768
749
  InvalidSelectorError.w3cStatus(),
769
750
  InvalidSelectorError.error(),
751
+ cause,
770
752
  );
771
753
  }
772
754
  }
@@ -781,17 +763,14 @@ export class SessionNotCreatedError extends ProtocolError {
781
763
  static error() {
782
764
  return 'session not created';
783
765
  }
784
- constructor(details) {
785
- let message = 'A new session could not be created.';
786
- if (details) {
787
- message += ` Details: ${details}`;
788
- }
789
766
 
767
+ constructor(message: string = '', cause?: Error) {
790
768
  super(
791
- message,
769
+ `A new session could not be created.${message ? (' Details: ' + message) : ''}`,
792
770
  SessionNotCreatedError.code(),
793
771
  SessionNotCreatedError.w3cStatus(),
794
772
  SessionNotCreatedError.error(),
773
+ cause,
795
774
  );
796
775
  }
797
776
  }
@@ -806,15 +785,14 @@ export class MoveTargetOutOfBoundsError extends ProtocolError {
806
785
  static error() {
807
786
  return 'move target out of bounds';
808
787
  }
809
- /**
810
- * @param {string} [err] error message
811
- */
812
- constructor(err) {
788
+
789
+ constructor(message: string = '', cause?: Error) {
813
790
  super(
814
- err || 'Target provided for a move action is out of bounds.',
791
+ message || 'Target provided for a move action is out of bounds.',
815
792
  MoveTargetOutOfBoundsError.code(),
816
793
  MoveTargetOutOfBoundsError.w3cStatus(),
817
794
  MoveTargetOutOfBoundsError.error(),
795
+ cause,
818
796
  );
819
797
  }
820
798
  }
@@ -823,12 +801,15 @@ export class NoSuchContextError extends ProtocolError {
823
801
  static code() {
824
802
  return 35;
825
803
  }
826
- /**
827
- *
828
- * @param {string} [message]
829
- */
830
- constructor(message) {
831
- super(message || 'No such context found.', NoSuchContextError.code());
804
+
805
+ constructor(message: string = '', cause?: Error) {
806
+ super(
807
+ message || 'No such context found.',
808
+ NoSuchContextError.code(),
809
+ UnknownError.w3cStatus(),
810
+ UnknownError.error(),
811
+ cause,
812
+ );
832
813
  }
833
814
  }
834
815
 
@@ -836,33 +817,27 @@ export class InvalidContextError extends ProtocolError {
836
817
  static code() {
837
818
  return 36;
838
819
  }
839
- /**
840
- *
841
- * @param {string} [message]
842
- */
843
- constructor(message) {
820
+
821
+ constructor(message: string = '', cause?: Error) {
844
822
  super(
845
823
  message || 'That command could not be executed in the current context.',
846
824
  InvalidContextError.code(),
825
+ UnknownError.w3cStatus(),
826
+ UnknownError.error(),
827
+ cause,
847
828
  );
848
829
  }
849
830
  }
850
831
 
851
- // These are aliases for UnknownMethodError
832
+ // Aliases to UnknownMethodError
852
833
  export class NotYetImplementedError extends UnknownMethodError {
853
- /**
854
- * @param {string} [err] error message
855
- */
856
- constructor(err) {
857
- super(err || 'Method has not yet been implemented');
834
+ constructor(message: string = '', cause?: Error) {
835
+ super(message || 'Method has not yet been implemented', cause);
858
836
  }
859
837
  }
860
838
  export class NotImplementedError extends UnknownMethodError {
861
- /**
862
- * @param {string} [err] error message
863
- */
864
- constructor(err) {
865
- super(err || 'Method is not implemented');
839
+ constructor(message: string = '', cause?: Error) {
840
+ super(message || 'Method is not implemented', cause);
866
841
  }
867
842
  }
868
843
 
@@ -876,62 +851,63 @@ export class UnableToCaptureScreen extends ProtocolError {
876
851
  static error() {
877
852
  return 'unable to capture screen';
878
853
  }
879
- /**
880
- * @param {string} [err] error message
881
- */
882
- constructor(err) {
854
+
855
+ constructor(message: string = '', cause?: Error) {
883
856
  super(
884
- err || 'A screen capture was made impossible',
857
+ message || 'A screen capture was made impossible',
885
858
  UnableToCaptureScreen.code(),
886
859
  UnableToCaptureScreen.w3cStatus(),
887
860
  UnableToCaptureScreen.error(),
861
+ cause,
888
862
  );
889
863
  }
890
864
  }
891
865
 
892
- function generateBadParametersMessage(requiredParams, actualParams) {
893
- const toArray = (/** @type {any} */ x) => (_.isArray(x) ? x : []);
866
+ function generateBadParametersMessage(
867
+ paramRequirements: ParameterRequirements,
868
+ paramNames: string[]
869
+ ): string {
870
+ const toArray = function <T> (x: T | T[]): T[] {
871
+ if (_.isUndefined(x)) {
872
+ return [];
873
+ }
874
+ if (_.isArray(x)) {
875
+ return x;
876
+ }
877
+ return [x];
878
+ };
894
879
 
895
- const requiredParamNames = toArray(requiredParams?.required);
896
- const actualParamNames = toArray(actualParams);
880
+ const requiredParamNames = toArray(paramRequirements.required);
881
+ const actualParamNames = toArray(paramNames);
897
882
  const missingRequiredParamNames = _.difference(requiredParamNames, actualParamNames);
898
- /** @type {string[]} */
899
- const resultLines = [];
883
+ const resultLines: string[] = [];
900
884
  resultLines.push(
901
885
  _.isEmpty(missingRequiredParamNames)
902
886
  ? // This should not happen
903
887
  'Some of the provided parameters are not known'
904
888
  : `The following required parameter${
905
- missingRequiredParamNames.length === 1 ? ' is ' : 's are '
906
- }` + `missing: ${JSON.stringify(missingRequiredParamNames)}`,
889
+ missingRequiredParamNames.length === 1 ? ' is' : 's are'
890
+ } missing: ${JSON.stringify(missingRequiredParamNames)}`,
907
891
  );
908
892
  if (!_.isEmpty(requiredParamNames)) {
909
893
  resultLines.push(`Known required parameters are: ${JSON.stringify(requiredParamNames)}`);
910
894
  }
911
- const optionalParamNames = _.difference(toArray(requiredParams?.optional), ['sessionId', 'id']);
895
+ const optionalParamNames = _.difference(toArray(paramRequirements.optional), ['sessionId', 'id']);
912
896
  if (!_.isEmpty(optionalParamNames)) {
913
897
  resultLines.push(`Known optional parameters are: ${JSON.stringify(optionalParamNames)}`);
914
898
  }
915
899
  resultLines.push(
916
900
  `You have provided${
917
- _.isEmpty(actualParamNames) ? ' none' : ': ' + JSON.stringify(actualParams)
901
+ _.isEmpty(actualParamNames) ? ' none' : ': ' + JSON.stringify(paramNames)
918
902
  }`,
919
903
  );
920
904
  return resultLines.join('\n');
921
905
  }
922
906
 
923
907
  // Equivalent to W3C InvalidArgumentError
924
- export class BadParametersError extends BaseError {
925
- static error() {
926
- return 'invalid argument';
927
- }
928
- constructor(requiredParams, actualParams, errMessage) {
929
- super(
930
- errMessage
931
- ? `Parameters were incorrect. You sent ${JSON.stringify(actualParams)}, ${errMessage}`
932
- : generateBadParametersMessage(requiredParams, actualParams),
933
- );
934
- this.w3cStatus = HTTPStatusCodes.BAD_REQUEST;
908
+ export class BadParametersError extends InvalidArgumentError {
909
+ constructor(paramReqs: ParameterRequirements, paramNames: string[]) {
910
+ super(generateBadParametersMessage(paramReqs, paramNames));
935
911
  }
936
912
  }
937
913
 
@@ -942,54 +918,67 @@ export class BadParametersError extends BaseError {
942
918
  * for proxy failure to generate the client response.
943
919
  */
944
920
  export class ProxyRequestError extends BaseError {
945
- constructor(err, responseError, httpStatus) {
946
- let responseErrorObj = util.safeJsonParse(responseError);
947
- if (!_.isPlainObject(responseErrorObj)) {
948
- responseErrorObj = {};
949
- }
950
- let origMessage = _.isString(responseError) ? responseError : '';
951
- if (!_.isEmpty(responseErrorObj)) {
952
- if (_.isString(responseErrorObj.value)) {
953
- origMessage = responseErrorObj.value;
954
- } else if (
955
- _.isPlainObject(responseErrorObj.value) &&
956
- _.isString(responseErrorObj.value.message)
957
- ) {
958
- origMessage = responseErrorObj.value.message;
959
- }
960
- }
961
- super(_.isEmpty(err) ? `Proxy request unsuccessful. ${origMessage}` : err);
962
-
963
- this.w3cStatus = HTTPStatusCodes.BAD_REQUEST;
921
+ private readonly _w3cError?: W3CError;
922
+ private readonly _w3cErrorStatus?: number;
923
+ private readonly _jwpError?: MJSONWPError;
924
+
925
+ constructor(
926
+ message: string,
927
+ httpResponseData: any,
928
+ httpStatus?: number,
929
+ cause?: Error,
930
+ ) {
931
+ const [responseErrorObj, originalMessage] = ProxyRequestError._parseHttpResponse(httpResponseData);
932
+ super(
933
+ _.isEmpty(message)
934
+ ? `Proxy request unsuccessful.${originalMessage ? (' ' + originalMessage) : ''}`
935
+ : message,
936
+ cause,
937
+ );
964
938
 
965
939
  // If the response error is an object and value is an object, it's a W3C error (for JSONWP value is a string)
966
940
  if (_.isPlainObject(responseErrorObj.value) && _.has(responseErrorObj.value, 'error')) {
967
- this.w3c = responseErrorObj.value;
968
- this.w3cStatus = httpStatus || HTTPStatusCodes.BAD_REQUEST;
969
- } else {
970
- this.jsonwp = responseErrorObj;
941
+ this._w3cError = responseErrorObj.value;
942
+ this._w3cErrorStatus = httpStatus;
943
+ } else if (_.has(responseErrorObj, 'status')) {
944
+ this._jwpError = responseErrorObj;
971
945
  }
972
946
  }
973
947
 
974
- getActualError() {
975
- // If it's MJSONWP error, returns actual error cause for request failure based on `jsonwp.status`
976
- if (util.hasValue(this.jsonwp?.status) && util.hasValue(this.jsonwp?.value)) {
977
- return errorFromMJSONWPStatusCode(this.jsonwp.status, this.jsonwp.value);
978
- } else if (util.hasValue(this.w3c) && _.isNumber(this.w3cStatus) && this.w3cStatus >= 300) {
948
+ getActualError(): ProtocolError {
949
+ if (util.hasValue(this._jwpError?.status) && util.hasValue(this._jwpError?.value)) {
950
+ // If it's MJSONWP error, returns actual error cause for request failure based on `jsonwp.status`
951
+ return errorFromMJSONWPStatusCode(this._jwpError.status, this._jwpError.value);
952
+ }
953
+ if (util.hasValue(this._w3cError) && _.isNumber(this._w3cErrorStatus) && this._w3cErrorStatus >= 300) {
979
954
  return errorFromW3CJsonCode(
980
- this.w3c.error,
981
- this.w3c.message || this.message,
982
- this.w3c.stacktrace,
955
+ this._w3cError.error,
956
+ this._w3cError.message || this.message,
957
+ this._w3cError.stacktrace || this.stack,
983
958
  );
984
959
  }
985
- return new UnknownError(this.message);
960
+ return new UnknownError(this.message, this.cause);
961
+ }
962
+
963
+ private static _parseHttpResponse(data: any): [Record<string, any>, string] {
964
+ let responseErrorObj: Record<string, any> = util.safeJsonParse(data);
965
+ if (!_.isPlainObject(responseErrorObj)) {
966
+ responseErrorObj = {};
967
+ }
968
+ let errorMessage: string = _.isString(data) ? data : '';
969
+ if (_.isString(responseErrorObj.value)) {
970
+ errorMessage = responseErrorObj.value;
971
+ } else if (_.isString(responseErrorObj.value?.message)) {
972
+ errorMessage = responseErrorObj.value.message;
973
+ }
974
+ return [responseErrorObj, errorMessage];
986
975
  }
987
976
  }
977
+
988
978
  // map of error class name to error class
989
- const errors = {
979
+ export const errors = {
990
980
  NotYetImplementedError,
991
981
  NotImplementedError,
992
- BadParametersError,
993
982
  InvalidArgumentError,
994
983
  NoSuchDriverError,
995
984
  NoSuchElementError,
@@ -1027,209 +1016,106 @@ const errors = {
1027
1016
  UnknownMethodError,
1028
1017
  UnsupportedOperationError,
1029
1018
  ProxyRequestError,
1030
- };
1019
+ } as const;
1031
1020
 
1032
- // map of error code to error class
1033
- const jsonwpErrorCodeMap = {};
1034
- for (let ErrorClass of _.values(errors)) {
1035
- if ('code' in ErrorClass) {
1036
- jsonwpErrorCodeMap[ErrorClass.code()] = ErrorClass;
1037
- }
1038
- }
1021
+ const jsonwpErrorCodeMap: Record<string, Class<ProtocolError>> = _.values(errors)
1022
+ .reduce((acc: Record<string, Class<ProtocolError>>, ErrorClass: any) => {
1023
+ if ('code' in ErrorClass) {
1024
+ acc[ErrorClass.code()] = ErrorClass;
1025
+ }
1026
+ return acc;
1027
+ }, {});
1028
+
1029
+ const w3cErrorCodeMap: Record<string, Class<ProtocolError>> = _.values(errors)
1030
+ .reduce((acc: Record<string, Class<ProtocolError>>, ErrorClass: any) => {
1031
+ if ('error' in ErrorClass) {
1032
+ acc[ErrorClass.error()] = ErrorClass;
1033
+ }
1034
+ return acc;
1035
+ }, {});
1039
1036
 
1040
- const w3cErrorCodeMap = {};
1041
- for (let ErrorClass of _.values(errors)) {
1042
- if ('error' in ErrorClass) {
1043
- w3cErrorCodeMap[ErrorClass.error()] = ErrorClass;
1044
- }
1045
- }
1046
1037
 
1047
- function isUnknownError(err) {
1048
- return (
1049
- !err.constructor.name ||
1050
- !_.values(errors).find(function equalNames(error) {
1051
- return error.name === err.constructor.name;
1052
- })
1053
- );
1054
- }
1055
1038
  /**
1056
1039
  * Type guard to check if an Error is of a specific type
1057
- * @template {Error} T
1058
- * @param {any} err
1059
- * @param {import('@appium/types').Class<T>} type
1060
- * @returns {err is T}
1061
1040
  */
1062
- function isErrorType(err, type) {
1063
- // `name` property is the constructor name
1064
- if (type.name === ProtocolError.name) {
1065
- // `jsonwpCode` is `0` on success
1066
- return !!err.jsonwpCode;
1067
- } else if (type.name === ProxyRequestError.name) {
1068
- // `status` is `0` on success
1069
- if (err.jsonwp) {
1070
- return !!err.jsonwp.status;
1071
- }
1072
-
1073
- if (_.isPlainObject(err.w3c)) {
1074
- return _.isNumber(err.w3cStatus) && err.w3cStatus >= 300;
1075
- }
1076
-
1077
- return false;
1078
- }
1079
- return err.constructor.name === type.name;
1041
+ export function isErrorType<T>(err: any, type: Class<T>): err is T {
1042
+ return err.constructor?.name === type.name;
1080
1043
  }
1081
1044
 
1082
1045
  /**
1083
1046
  * Retrieve an error derived from MJSONWP status
1084
- * @param {number} code JSONWP status code
1085
- * @param {string|Object} value The error message, or an object with a `message` property
1086
- * @return {ProtocolError} The error that is associated with provided JSONWP status code
1047
+ * @param code JSONWP status code
1048
+ * @param value The error message, or an object with a `message` property
1049
+ * @return The error that is associated with provided JSONWP status code
1087
1050
  */
1088
- function errorFromMJSONWPStatusCode(code, value = '') {
1051
+ export function errorFromMJSONWPStatusCode(code: number, value: string | {message: string} = ''): ProtocolError {
1052
+ const ErrorClass = jsonwpErrorCodeMap[code] ?? UnknownError;
1053
+ mjsonwpLog.debug(`Matched JSONWP error code ${code} to ${ErrorClass.name}`);
1089
1054
  // if `value` is an object, pull message from it, otherwise use the plain
1090
1055
  // value, or default to an empty string, if null
1091
- const message = (value || {}).message || value || '';
1092
- if (code !== UnknownError.code() && jsonwpErrorCodeMap[code]) {
1093
- mjsonwpLog.debug(`Matched JSONWP error code ${code} to ${jsonwpErrorCodeMap[code].name}`);
1094
- return new jsonwpErrorCodeMap[code](message);
1095
- }
1096
- mjsonwpLog.debug(`Matched JSONWP error code ${code} to UnknownError`);
1097
- return new UnknownError(message);
1056
+ const message = ((value || {}) as any).message || value || '';
1057
+ return new ErrorClass(message);
1098
1058
  }
1099
1059
 
1100
1060
  /**
1101
1061
  * Retrieve an error derived from W3C JSON Code
1102
- * @param {string} code W3C error string (see https://www.w3.org/TR/webdriver/#handling-errors `JSON Error Code` column)
1103
- * @param {string} message the error message
1104
- * @param {?string} stacktrace an optional error stacktrace
1105
- * @return {ProtocolError} The error that is associated with the W3C error string
1062
+ * @param signature W3C error string (see https://www.w3.org/TR/webdriver/#handling-errors `JSON Error Code` column)
1063
+ * @param message the error message
1064
+ * @param stacktrace an optional error stacktrace
1065
+ * @return The error that is associated with the W3C error string
1106
1066
  */
1107
- function errorFromW3CJsonCode(code, message, stacktrace = null) {
1108
- if (code && w3cErrorCodeMap[code.toLowerCase()]) {
1109
- w3cLog.debug(`Matched W3C error code '${code}' to ${w3cErrorCodeMap[code.toLowerCase()].name}`);
1110
- const resultError = new w3cErrorCodeMap[code.toLowerCase()](message);
1111
- resultError.stacktrace = stacktrace;
1112
- return resultError;
1113
- }
1114
- w3cLog.debug(`Matched W3C error code '${code}' to UnknownError`);
1115
- const resultError = new UnknownError(message);
1067
+ export function errorFromW3CJsonCode(signature: string, message: string, stacktrace?: string): ProtocolError {
1068
+ const ErrorClass = w3cErrorCodeMap[_.toLower(signature)] ?? UnknownError;
1069
+ w3cLog.debug(`Matched W3C error code '${signature}' to ${ErrorClass.name}`);
1070
+ const resultError = new ErrorClass(message);
1116
1071
  resultError.stacktrace = stacktrace;
1117
1072
  return resultError;
1118
1073
  }
1119
1074
 
1120
- /**
1121
- *
1122
- * @param {any} err
1123
- * @returns {err is ProtocolError}
1124
- */
1125
- function isProtocolError(err) {
1126
- return 'w3cStatus' in err;
1127
- }
1128
-
1129
1075
  /**
1130
1076
  * Convert an Appium error to proper W3C HTTP response
1131
- * @param {ProtocolError|MJSONWPError} err The error that needs to be translated
1077
+ *
1078
+ * @param err The error that needs to be translated
1132
1079
  */
1133
- function getResponseForW3CError(err) {
1134
- let httpStatus;
1135
-
1136
- // W3C defined error message (https://www.w3.org/TR/webdriver/#dfn-error-code)
1137
- let w3cErrorString;
1138
-
1139
- if (!isProtocolError(err)) {
1140
- err = util.hasValue(err.status)
1141
- ? // If it's a JSONWP error, find corresponding error
1142
- errorFromMJSONWPStatusCode(err.status, err.value)
1143
- : new errors.UnknownError(err.message);
1144
- }
1080
+ export function getResponseForW3CError(err: any): [number, { value: W3CError }] {
1081
+ const protocolErrorToResponse: (e: ProtocolError) => [number, { value: W3CError }] =
1082
+ (e: ProtocolError) => [
1083
+ e.w3cStatus,
1084
+ {
1085
+ value: {
1086
+ error: e.error,
1087
+ message: e.message,
1088
+ stacktrace: e.stacktrace || e.stack,
1089
+ }
1090
+ }
1091
+ ];
1145
1092
 
1146
- if (isErrorType(err, errors.BadParametersError)) {
1147
- // respond with a 400 if we have bad parameters
1148
- w3cLog.debug(`Bad parameters: ${err}`);
1149
- w3cErrorString = BadParametersError.error();
1150
- } else {
1151
- // @ts-expect-error unclear what the problem is here
1152
- w3cErrorString = err.error;
1093
+ // err is ProtocolError
1094
+ if (['error', 'w3cStatus'].every((prop) => _.has(err, prop))) {
1095
+ return protocolErrorToResponse(err);
1153
1096
  }
1154
1097
 
1155
- httpStatus = err.w3cStatus;
1156
-
1157
- if (!w3cErrorString) {
1158
- w3cErrorString = UnknownError.error();
1098
+ // err is ProxyRequestError
1099
+ if (_.has(err, 'getActualError') && _.isFunction(err.getActualError)) {
1100
+ return protocolErrorToResponse(err.getActualError());
1159
1101
  }
1160
1102
 
1161
- let httpResBody = {
1162
- value: {
1163
- error: w3cErrorString,
1164
- message: err.message,
1165
- stacktrace: err.stacktrace || err.stack,
1166
- },
1167
- };
1168
- return [httpStatus, httpResBody];
1103
+ return protocolErrorToResponse(new UnknownError(err.message, err));
1169
1104
  }
1170
1105
 
1171
- /**
1172
- * Convert an Appium error to a proper JSONWP response
1173
- * @param {ProtocolError} err The error to be converted
1174
- */
1175
- function getResponseForJsonwpError(err) {
1176
- if (isUnknownError(err)) {
1177
- err = new errors.UnknownError(err);
1178
- }
1179
- // MJSONWP errors are usually 500 status code so set it to that by default
1180
- let httpStatus = HTTPStatusCodes.INTERNAL_SERVER_ERROR;
1181
-
1182
- /** @type {HttpResultBody} */
1183
- let httpResBody = {
1184
- status: err.jsonwpCode,
1185
- value: {
1186
- message: err.message,
1187
- },
1188
- };
1189
-
1190
- if (isErrorType(err, errors.BadParametersError)) {
1191
- // respond with a 400 if we have bad parameters
1192
- mjsonwpLog.debug(`Bad parameters: ${err}`);
1193
- httpStatus = HTTPStatusCodes.BAD_REQUEST;
1194
- httpResBody = err.message;
1195
- } else if (
1196
- isErrorType(err, errors.NotYetImplementedError) ||
1197
- isErrorType(err, errors.NotImplementedError)
1198
- ) {
1199
- // respond with a 501 if the method is not implemented
1200
- httpStatus = HTTPStatusCodes.NOT_IMPLEMENTED;
1201
- } else if (isErrorType(err, errors.NoSuchDriverError)) {
1202
- // respond with a 404 if there is no driver for the session
1203
- httpStatus = HTTPStatusCodes.NOT_FOUND;
1204
- }
1205
-
1206
- return [httpStatus, httpResBody];
1106
+ interface MJSONWPError {
1107
+ status: number;
1108
+ value?: any;
1109
+ message?: string;
1207
1110
  }
1208
1111
 
1209
- export {
1210
- errors,
1211
- isErrorType,
1212
- isUnknownError,
1213
- errorFromMJSONWPStatusCode,
1214
- errorFromW3CJsonCode,
1215
- getResponseForW3CError,
1216
- getResponseForJsonwpError,
1217
- };
1218
-
1219
- /**
1220
- * @typedef { string | {value: HttpResultBodyValue, status?: number } } HttpResultBody
1221
- */
1222
-
1223
- /**
1224
- * @typedef HttpResultBodyValue
1225
- * @property {string} [message]
1226
- * @property {string|Error} [error]
1227
- * @property {string} [stacktrace]
1228
- */
1112
+ interface W3CError {
1113
+ error: string;
1114
+ message?: string;
1115
+ stacktrace?: string;
1116
+ }
1229
1117
 
1230
- /**
1231
- * @typedef MJSONWPError
1232
- * @property {number} status
1233
- * @property {string|object} value
1234
- * @property {string} message
1235
- */
1118
+ interface ParameterRequirements {
1119
+ required: string[]|string;
1120
+ optional?: string[]|string;
1121
+ }