@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.
- package/README.md +0 -8
- package/build/lib/basedriver/capabilities.d.ts.map +1 -1
- package/build/lib/basedriver/capabilities.js +2 -4
- package/build/lib/basedriver/capabilities.js.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +7 -25
- package/build/lib/basedriver/commands/timeout.js.map +1 -1
- package/build/lib/basedriver/core.d.ts +0 -8
- package/build/lib/basedriver/core.d.ts.map +1 -1
- package/build/lib/basedriver/core.js +8 -18
- package/build/lib/basedriver/core.js.map +1 -1
- package/build/lib/basedriver/driver.js +2 -2
- package/build/lib/basedriver/driver.js.map +1 -1
- package/build/lib/basedriver/helpers.d.ts +9 -1
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +56 -142
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/basedriver/validation.d.ts +7 -0
- package/build/lib/basedriver/validation.d.ts.map +1 -0
- package/build/lib/basedriver/validation.js +130 -0
- package/build/lib/basedriver/validation.js.map +1 -0
- package/build/lib/express/middleware.d.ts +0 -6
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +28 -60
- package/build/lib/express/middleware.js.map +1 -1
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +0 -1
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/helpers/capabilities.d.ts +13 -6
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +7 -0
- package/build/lib/helpers/capabilities.js.map +1 -1
- package/build/lib/index.d.ts +1 -0
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +3 -1
- package/build/lib/index.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.d.ts +0 -8
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +7 -38
- package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
- package/build/lib/protocol/errors.d.ts +171 -277
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +201 -421
- package/build/lib/protocol/errors.js.map +1 -1
- package/build/lib/protocol/helpers.d.ts +6 -6
- package/build/lib/protocol/helpers.d.ts.map +1 -1
- package/build/lib/protocol/helpers.js +11 -7
- package/build/lib/protocol/helpers.js.map +1 -1
- package/build/lib/protocol/index.d.ts +2 -1
- package/build/lib/protocol/index.d.ts.map +1 -1
- package/build/lib/protocol/index.js +2 -1
- package/build/lib/protocol/index.js.map +1 -1
- package/build/lib/protocol/protocol.d.ts +5 -0
- package/build/lib/protocol/protocol.d.ts.map +1 -1
- package/build/lib/protocol/protocol.js +23 -23
- package/build/lib/protocol/protocol.js.map +1 -1
- package/build/lib/protocol/routes.d.ts +14 -715
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +28 -487
- package/build/lib/protocol/routes.js.map +1 -1
- package/build/lib/protocol/validators.d.ts +4 -7
- package/build/lib/protocol/validators.d.ts.map +1 -1
- package/build/lib/protocol/validators.js +4 -21
- package/build/lib/protocol/validators.js.map +1 -1
- package/lib/basedriver/capabilities.ts +2 -4
- package/lib/basedriver/commands/timeout.ts +11 -34
- package/lib/basedriver/core.ts +10 -19
- package/lib/basedriver/driver.ts +3 -3
- package/lib/basedriver/helpers.js +61 -167
- package/lib/basedriver/validation.ts +145 -0
- package/lib/express/middleware.js +32 -70
- package/lib/express/server.js +0 -2
- package/lib/helpers/capabilities.js +9 -4
- package/lib/index.js +2 -0
- package/lib/jsonwp-proxy/proxy.js +8 -45
- package/lib/protocol/{errors.js → errors.ts} +322 -436
- package/lib/protocol/helpers.js +12 -8
- package/lib/protocol/index.js +8 -1
- package/lib/protocol/protocol.js +25 -23
- package/lib/protocol/routes.js +30 -497
- package/lib/protocol/validators.ts +19 -0
- package/package.json +10 -11
- package/build/lib/basedriver/desired-caps.d.ts +0 -5
- package/build/lib/basedriver/desired-caps.d.ts.map +0 -1
- package/build/lib/basedriver/desired-caps.js +0 -92
- package/build/lib/basedriver/desired-caps.js.map +0 -1
- package/lib/basedriver/README.md +0 -36
- package/lib/basedriver/desired-caps.js +0 -103
- package/lib/express/README.md +0 -59
- package/lib/jsonwp-proxy/README.md +0 -52
- package/lib/jsonwp-status/README.md +0 -20
- package/lib/protocol/README.md +0 -100
- 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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
270
|
+
return 'unknown error';
|
|
270
271
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
(
|
|
278
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
413
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
525
|
-
*/
|
|
526
|
-
constructor(err) {
|
|
518
|
+
|
|
519
|
+
constructor(message: string = '', cause?: Error) {
|
|
527
520
|
super(
|
|
528
|
-
|
|
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
|
-
|
|
548
|
-
*/
|
|
549
|
-
constructor(err) {
|
|
540
|
+
|
|
541
|
+
constructor(message: string = '', cause?: Error) {
|
|
550
542
|
super(
|
|
551
|
-
|
|
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
|
-
|
|
573
|
-
*/
|
|
574
|
-
constructor(err) {
|
|
564
|
+
|
|
565
|
+
constructor(message: string = '', cause?: Error) {
|
|
575
566
|
super(
|
|
576
|
-
|
|
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
|
-
|
|
597
|
-
*/
|
|
598
|
-
constructor(err) {
|
|
587
|
+
|
|
588
|
+
constructor(message: string = '', cause?: Error) {
|
|
599
589
|
super(
|
|
600
|
-
|
|
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
|
|
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
|
-
|
|
669
|
-
*/
|
|
670
|
-
constructor(err) {
|
|
654
|
+
|
|
655
|
+
constructor(message: string = '', cause?: Error) {
|
|
671
656
|
super(
|
|
672
|
-
|
|
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
|
-
|
|
692
|
-
*/
|
|
693
|
-
constructor(err) {
|
|
676
|
+
|
|
677
|
+
constructor(message: string = '', cause?: Error) {
|
|
694
678
|
super(
|
|
695
|
-
|
|
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
|
-
|
|
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
|
-
|
|
740
|
-
*/
|
|
741
|
-
constructor(err) {
|
|
722
|
+
|
|
723
|
+
constructor(message: string = '', cause?: Error) {
|
|
742
724
|
super(
|
|
743
|
-
|
|
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
|
-
|
|
763
|
-
*/
|
|
764
|
-
constructor(err) {
|
|
744
|
+
|
|
745
|
+
constructor(message: string = '', cause?: Error) {
|
|
765
746
|
super(
|
|
766
|
-
|
|
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
|
-
|
|
811
|
-
*/
|
|
812
|
-
constructor(err) {
|
|
788
|
+
|
|
789
|
+
constructor(message: string = '', cause?: Error) {
|
|
813
790
|
super(
|
|
814
|
-
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
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
|
-
//
|
|
832
|
+
// Aliases to UnknownMethodError
|
|
852
833
|
export class NotYetImplementedError extends UnknownMethodError {
|
|
853
|
-
|
|
854
|
-
|
|
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
|
-
|
|
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
|
-
|
|
881
|
-
*/
|
|
882
|
-
constructor(err) {
|
|
854
|
+
|
|
855
|
+
constructor(message: string = '', cause?: Error) {
|
|
883
856
|
super(
|
|
884
|
-
|
|
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(
|
|
893
|
-
|
|
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(
|
|
896
|
-
const actualParamNames = toArray(
|
|
880
|
+
const requiredParamNames = toArray(paramRequirements.required);
|
|
881
|
+
const actualParamNames = toArray(paramNames);
|
|
897
882
|
const missingRequiredParamNames = _.difference(requiredParamNames, actualParamNames);
|
|
898
|
-
|
|
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
|
|
906
|
-
}
|
|
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(
|
|
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(
|
|
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
|
|
925
|
-
|
|
926
|
-
|
|
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
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
)
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
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.
|
|
968
|
-
this.
|
|
969
|
-
} else {
|
|
970
|
-
this.
|
|
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
|
-
|
|
976
|
-
|
|
977
|
-
return errorFromMJSONWPStatusCode(this.
|
|
978
|
-
}
|
|
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.
|
|
981
|
-
this.
|
|
982
|
-
this.
|
|
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
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
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
|
-
|
|
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
|
|
1085
|
-
* @param
|
|
1086
|
-
* @return
|
|
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
|
-
|
|
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
|
|
1103
|
-
* @param
|
|
1104
|
-
* @param
|
|
1105
|
-
* @return
|
|
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(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
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
|
-
*
|
|
1077
|
+
*
|
|
1078
|
+
* @param err The error that needs to be translated
|
|
1132
1079
|
*/
|
|
1133
|
-
function getResponseForW3CError(err) {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
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
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1173
|
-
|
|
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
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
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
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
* @property {string} message
|
|
1235
|
-
*/
|
|
1118
|
+
interface ParameterRequirements {
|
|
1119
|
+
required: string[]|string;
|
|
1120
|
+
optional?: string[]|string;
|
|
1121
|
+
}
|