@appium/base-driver 10.5.1 → 10.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/basedriver/capabilities.d.ts.map +1 -1
- package/build/lib/basedriver/capabilities.js +45 -45
- package/build/lib/basedriver/capabilities.js.map +1 -1
- package/build/lib/basedriver/commands/bidi.d.ts.map +1 -1
- package/build/lib/basedriver/commands/bidi.js +9 -13
- package/build/lib/basedriver/commands/bidi.js.map +1 -1
- package/build/lib/basedriver/commands/event.d.ts.map +1 -1
- package/build/lib/basedriver/commands/event.js +4 -7
- package/build/lib/basedriver/commands/event.js.map +1 -1
- package/build/lib/basedriver/commands/execute.js +3 -6
- package/build/lib/basedriver/commands/execute.js.map +1 -1
- package/build/lib/basedriver/commands/log.d.ts.map +1 -1
- package/build/lib/basedriver/commands/log.js +1 -5
- package/build/lib/basedriver/commands/log.js.map +1 -1
- package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +5 -9
- package/build/lib/basedriver/commands/timeout.js.map +1 -1
- package/build/lib/basedriver/core.js +12 -12
- package/build/lib/basedriver/core.js.map +1 -1
- package/build/lib/basedriver/device-settings.d.ts.map +1 -1
- package/build/lib/basedriver/device-settings.js +3 -7
- package/build/lib/basedriver/device-settings.js.map +1 -1
- package/build/lib/basedriver/driver.d.ts.map +1 -1
- package/build/lib/basedriver/driver.js +13 -16
- package/build/lib/basedriver/driver.js.map +1 -1
- package/build/lib/basedriver/extension-core.d.ts +4 -1
- package/build/lib/basedriver/extension-core.d.ts.map +1 -1
- package/build/lib/basedriver/extension-core.js +27 -9
- package/build/lib/basedriver/extension-core.js.map +1 -1
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +28 -30
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/basedriver/ipc.d.ts +36 -0
- package/build/lib/basedriver/ipc.d.ts.map +1 -0
- package/build/lib/basedriver/ipc.js +155 -0
- package/build/lib/basedriver/ipc.js.map +1 -0
- package/build/lib/basedriver/validation.js +25 -28
- package/build/lib/basedriver/validation.js.map +1 -1
- package/build/lib/express/express-logging.d.ts.map +1 -1
- package/build/lib/express/express-logging.js +2 -3
- package/build/lib/express/express-logging.js.map +1 -1
- package/build/lib/express/idempotency.js +3 -6
- package/build/lib/express/idempotency.js.map +1 -1
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +6 -10
- 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 +64 -54
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/express/static.d.ts.map +1 -1
- package/build/lib/express/static.js +14 -7
- package/build/lib/express/static.js.map +1 -1
- package/build/lib/express/websocket.d.ts.map +1 -1
- package/build/lib/express/websocket.js +6 -9
- package/build/lib/express/websocket.js.map +1 -1
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +14 -17
- package/build/lib/helpers/capabilities.js.map +1 -1
- package/build/lib/helpers/extension-command-name.js +2 -5
- package/build/lib/helpers/extension-command-name.js.map +1 -1
- package/build/lib/helpers/levenshtein-match.d.ts.map +1 -1
- package/build/lib/helpers/levenshtein-match.js +2 -6
- package/build/lib/helpers/levenshtein-match.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 -14
- package/build/lib/index.js.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.js +13 -17
- package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy-request.d.ts +2 -2
- package/build/lib/jsonwp-proxy/proxy-request.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy-request.js +25 -21
- package/build/lib/jsonwp-proxy/proxy-request.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +29 -26
- package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +25 -29
- package/build/lib/protocol/errors.js.map +1 -1
- package/build/lib/protocol/helpers.d.ts.map +1 -1
- package/build/lib/protocol/helpers.js +9 -8
- package/build/lib/protocol/helpers.js.map +1 -1
- package/build/lib/protocol/protocol.d.ts.map +1 -1
- package/build/lib/protocol/protocol.js +43 -48
- package/build/lib/protocol/protocol.js.map +1 -1
- package/build/lib/protocol/routes.d.ts +1 -1
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +9 -12
- package/build/lib/protocol/routes.js.map +1 -1
- package/build/lib/protocol/validators.d.ts.map +1 -1
- package/build/lib/protocol/validators.js +1 -5
- package/build/lib/protocol/validators.js.map +1 -1
- package/build/lib/utils.d.ts +16 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +71 -0
- package/build/lib/utils.js.map +1 -0
- package/lib/basedriver/capabilities.ts +60 -55
- package/lib/basedriver/commands/bidi.ts +10 -10
- package/lib/basedriver/commands/event.ts +11 -10
- package/lib/basedriver/commands/execute.ts +3 -3
- package/lib/basedriver/commands/log.ts +3 -2
- package/lib/basedriver/commands/timeout.ts +5 -6
- package/lib/basedriver/core.ts +12 -12
- package/lib/basedriver/device-settings.ts +3 -4
- package/lib/basedriver/driver.ts +15 -13
- package/lib/basedriver/extension-core.ts +33 -7
- package/lib/basedriver/helpers.ts +28 -30
- package/lib/basedriver/ipc.ts +179 -0
- package/lib/basedriver/validation.ts +26 -26
- package/lib/express/express-logging.ts +3 -4
- package/lib/express/idempotency.ts +3 -3
- package/lib/express/middleware.ts +6 -8
- package/lib/express/server.ts +67 -61
- package/lib/express/static.ts +15 -7
- package/lib/express/websocket.ts +8 -10
- package/lib/helpers/capabilities.ts +18 -14
- package/lib/helpers/extension-command-name.ts +2 -2
- package/lib/helpers/levenshtein-match.ts +2 -5
- package/lib/index.js +1 -11
- package/lib/jsonwp-proxy/protocol-converter.ts +14 -15
- package/lib/jsonwp-proxy/proxy-request.ts +26 -26
- package/lib/jsonwp-proxy/proxy.ts +36 -37
- package/lib/protocol/errors.ts +29 -28
- package/lib/protocol/helpers.ts +9 -5
- package/lib/protocol/protocol.ts +44 -46
- package/lib/protocol/routes.ts +9 -9
- package/lib/protocol/validators.ts +1 -3
- package/lib/utils.ts +85 -0
- package/package.json +7 -9
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergePlainObjects = mergePlainObjects;
|
|
4
|
+
exports.omit = omit;
|
|
5
|
+
exports.omitKeys = omitKeys;
|
|
6
|
+
exports.pick = pick;
|
|
7
|
+
exports.pickBy = pickBy;
|
|
8
|
+
exports.compileLodashTemplate = compileLodashTemplate;
|
|
9
|
+
const support_1 = require("@appium/support");
|
|
10
|
+
/**
|
|
11
|
+
* Deep-merge plain objects into a clone of `target`. Skips null/undefined sources.
|
|
12
|
+
* Non-plain values on a key replace the previous value (same as lodash merge for objects).
|
|
13
|
+
*/
|
|
14
|
+
function mergePlainObjects(target, ...sources) {
|
|
15
|
+
const result = structuredClone(target);
|
|
16
|
+
for (const source of sources) {
|
|
17
|
+
if (source == null) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
for (const [key, value] of Object.entries(source)) {
|
|
21
|
+
const existing = result[key];
|
|
22
|
+
if (support_1.util.isPlainObject(existing) && support_1.util.isPlainObject(value)) {
|
|
23
|
+
result[key] = mergePlainObjects(existing, value);
|
|
24
|
+
}
|
|
25
|
+
else if (value !== undefined) {
|
|
26
|
+
result[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/** Return a shallow copy of `obj` without `key`. Non-objects are returned unchanged. */
|
|
33
|
+
function omit(obj, key) {
|
|
34
|
+
if (!support_1.util.isPlainObject(obj)) {
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
return Object.fromEntries(Object.entries(obj).filter(([k]) => k !== key));
|
|
38
|
+
}
|
|
39
|
+
/** Return a shallow copy of `obj` without any of `keys`. */
|
|
40
|
+
function omitKeys(obj, keys) {
|
|
41
|
+
if (!support_1.util.isPlainObject(obj) || keys.length === 0) {
|
|
42
|
+
return obj;
|
|
43
|
+
}
|
|
44
|
+
const keysToOmit = new Set(keys);
|
|
45
|
+
return Object.fromEntries(Object.entries(obj).filter(([k]) => !keysToOmit.has(k)));
|
|
46
|
+
}
|
|
47
|
+
/** Return a shallow copy of `obj` containing only listed keys. */
|
|
48
|
+
function pick(obj, keys) {
|
|
49
|
+
const keysToPick = new Set(keys);
|
|
50
|
+
return Object.fromEntries(Object.entries(obj).filter(([k]) => keysToPick.has(k)));
|
|
51
|
+
}
|
|
52
|
+
/** Return a shallow copy of `obj` whose entries pass `predicate`. */
|
|
53
|
+
function pickBy(obj, predicate) {
|
|
54
|
+
return Object.fromEntries(Object.entries(obj).filter(([key, value]) => predicate(value, key)));
|
|
55
|
+
}
|
|
56
|
+
/** Compile a lodash-style template string (`<%= expression %>`) into a render function. */
|
|
57
|
+
function compileLodashTemplate(template) {
|
|
58
|
+
const parts = [];
|
|
59
|
+
let lastIndex = 0;
|
|
60
|
+
const re = /<%=\s*([\s\S]+?)\s*%>/g;
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = re.exec(template)) !== null) {
|
|
63
|
+
parts.push(JSON.stringify(template.slice(lastIndex, match.index)));
|
|
64
|
+
parts.push(`String(${match[1]})`);
|
|
65
|
+
lastIndex = match.index + match[0].length;
|
|
66
|
+
}
|
|
67
|
+
parts.push(JSON.stringify(template.slice(lastIndex)));
|
|
68
|
+
const fn = new Function('obj', `with (obj) { return ${parts.join(' + ')}; }`);
|
|
69
|
+
return (params) => fn(params);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../lib/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,9 +9,9 @@ import type {
|
|
|
9
9
|
KeyAsString,
|
|
10
10
|
MergeExclusive,
|
|
11
11
|
} from 'type-fest';
|
|
12
|
-
import _ from 'lodash';
|
|
13
12
|
import {validator} from './validation';
|
|
14
13
|
import {util} from '@appium/support';
|
|
14
|
+
import {omit, pickBy} from '../utils';
|
|
15
15
|
import {log} from './logger';
|
|
16
16
|
import {errors} from '../protocol/errors';
|
|
17
17
|
|
|
@@ -50,7 +50,7 @@ export function mergeCaps<
|
|
|
50
50
|
|
|
51
51
|
for (const [name, value] of Object.entries(secondary)) {
|
|
52
52
|
// Overwriting is not allowed. Primary and secondary must have different properties (w3c rule 4.4)
|
|
53
|
-
if (
|
|
53
|
+
if (primary[name] !== undefined) {
|
|
54
54
|
throw new errors.InvalidArgumentError(
|
|
55
55
|
`property '${name}' should not exist on both primary (${JSON.stringify(
|
|
56
56
|
primary
|
|
@@ -73,32 +73,31 @@ export function validateCaps<C extends Constraints>(
|
|
|
73
73
|
): Capabilities<C> {
|
|
74
74
|
const {skipPresenceConstraint} = opts;
|
|
75
75
|
|
|
76
|
-
if (!
|
|
76
|
+
if (!util.isPlainObject(caps)) {
|
|
77
77
|
throw new errors.InvalidArgumentError(`must be a JSON object`);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// Remove the 'presence' constraint if we're not checking for it
|
|
81
|
-
constraints = (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
return constraint;
|
|
93
|
-
}
|
|
94
|
-
)
|
|
81
|
+
constraints = Object.fromEntries(
|
|
82
|
+
Object.entries(constraints ?? {}).map(([key, constraint]) => {
|
|
83
|
+
if (skipPresenceConstraint) {
|
|
84
|
+
return [key, omit(constraint as Record<string, unknown>, 'presence')];
|
|
85
|
+
}
|
|
86
|
+
if ((constraint as {presence?: unknown}).presence === true) {
|
|
87
|
+
return [key, {...omit(constraint as Record<string, unknown>, 'presence'), presence: {allowEmpty: false}}];
|
|
88
|
+
}
|
|
89
|
+
return [key, constraint];
|
|
90
|
+
})
|
|
95
91
|
) as C;
|
|
96
92
|
|
|
97
|
-
const validationErrors = validator.validate(
|
|
93
|
+
const validationErrors = validator.validate(
|
|
94
|
+
pickBy(caps, (value) => util.hasValue(value)),
|
|
95
|
+
constraints
|
|
96
|
+
);
|
|
98
97
|
|
|
99
98
|
if (validationErrors) {
|
|
100
99
|
const message: string[] = [];
|
|
101
|
-
for (const [attribute, reasons] of
|
|
100
|
+
for (const [attribute, reasons] of Object.entries(validationErrors)) {
|
|
102
101
|
for (const reason of (reasons as string[])) {
|
|
103
102
|
message.push(`'${attribute}' ${reason}`);
|
|
104
103
|
}
|
|
@@ -151,12 +150,14 @@ export function isStandardCap(cap: string): boolean {
|
|
|
151
150
|
export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<C>): Capabilities<C> {
|
|
152
151
|
// split into prefixed and non-prefixed.
|
|
153
152
|
// non-prefixed should be standard caps at this point
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
);
|
|
153
|
+
const capKeys = Object.keys(caps);
|
|
154
|
+
const prefixedCaps = capKeys.filter((cap) => String(cap).startsWith(APPIUM_VENDOR_PREFIX));
|
|
155
|
+
const nonPrefixedCaps = capKeys.filter((cap) => !String(cap).startsWith(APPIUM_VENDOR_PREFIX));
|
|
157
156
|
|
|
158
157
|
// initialize this with the k/v pairs of the non-prefixed caps
|
|
159
|
-
const strippedCaps =
|
|
158
|
+
const strippedCaps: Record<string, unknown> = Object.fromEntries(
|
|
159
|
+
nonPrefixedCaps.map((cap) => [cap, caps[cap as keyof typeof caps]])
|
|
160
|
+
) as Capabilities<C>;
|
|
160
161
|
const badPrefixedCaps: string[] = [];
|
|
161
162
|
|
|
162
163
|
// Strip out the 'appium:' prefix
|
|
@@ -166,16 +167,16 @@ export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<
|
|
|
166
167
|
// If it's standard capability that was prefixed, add it to an array of incorrectly prefixed capabilities
|
|
167
168
|
if (isStandardCap(strippedCapName)) {
|
|
168
169
|
badPrefixedCaps.push(strippedCapName);
|
|
169
|
-
if (
|
|
170
|
-
strippedCaps[strippedCapName] = caps[prefixedCap];
|
|
170
|
+
if (strippedCaps[strippedCapName] == null) {
|
|
171
|
+
strippedCaps[strippedCapName] = caps[prefixedCap as keyof typeof caps];
|
|
171
172
|
} else {
|
|
172
173
|
log.warn(
|
|
173
|
-
`Ignoring capability '${prefixedCap}=${caps[prefixedCap]}' and ` +
|
|
174
|
+
`Ignoring capability '${prefixedCap}=${caps[prefixedCap as keyof typeof caps]}' and ` +
|
|
174
175
|
`using capability '${strippedCapName}=${strippedCaps[strippedCapName]}'`
|
|
175
176
|
);
|
|
176
177
|
}
|
|
177
178
|
} else {
|
|
178
|
-
strippedCaps[strippedCapName] = caps[prefixedCap];
|
|
179
|
+
strippedCaps[strippedCapName] = caps[prefixedCap as keyof typeof caps];
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -187,7 +188,7 @@ export function stripAppiumPrefixes<C extends Constraints>(caps: NSCapabilities<
|
|
|
187
188
|
)} are standard capabilities and do not require "appium:" prefix`
|
|
188
189
|
);
|
|
189
190
|
}
|
|
190
|
-
return strippedCaps
|
|
191
|
+
return strippedCaps as Capabilities<C>;
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
/**
|
|
@@ -199,16 +200,15 @@ export function findNonPrefixedCaps<C extends Constraints>(
|
|
|
199
200
|
firstMatch = []
|
|
200
201
|
}: W3CCapabilities<C>
|
|
201
202
|
): string[] {
|
|
202
|
-
return
|
|
203
|
-
.reduce(
|
|
203
|
+
return util.uniq(
|
|
204
|
+
[alwaysMatch, ...firstMatch].reduce<string[]>(
|
|
204
205
|
(unprefixedCaps, caps) => [
|
|
205
206
|
...unprefixedCaps,
|
|
206
207
|
...Object.keys(caps).filter((cap) => !cap.includes(':') && !isStandardCap(cap)),
|
|
207
208
|
],
|
|
208
209
|
[]
|
|
209
210
|
)
|
|
210
|
-
|
|
211
|
-
.value();
|
|
211
|
+
);
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
/**
|
|
@@ -221,7 +221,7 @@ export function parseCaps<C extends Constraints>(
|
|
|
221
221
|
shouldValidateCaps: boolean | undefined = true
|
|
222
222
|
): ParsedCaps<C> {
|
|
223
223
|
// If capabilities request is not an object, return error (#1.1)
|
|
224
|
-
if (!
|
|
224
|
+
if (!util.isPlainObject(caps)) {
|
|
225
225
|
throw new errors.InvalidArgumentError(
|
|
226
226
|
'The capabilities argument was not valid for the following reason(s): "capabilities" must be a JSON object.'
|
|
227
227
|
);
|
|
@@ -235,7 +235,7 @@ export function parseCaps<C extends Constraints>(
|
|
|
235
235
|
} = caps;
|
|
236
236
|
|
|
237
237
|
// Reject 'firstMatch' argument if it's not an array (#3.2)
|
|
238
|
-
if (!
|
|
238
|
+
if (!Array.isArray(allFirstMatchCaps)) {
|
|
239
239
|
throw new errors.InvalidArgumentError(
|
|
240
240
|
'The capabilities.firstMatch argument was not valid for the following reason(s): "capabilities.firstMatch" must be a JSON array or undefined'
|
|
241
241
|
);
|
|
@@ -253,7 +253,7 @@ export function parseCaps<C extends Constraints>(
|
|
|
253
253
|
|
|
254
254
|
// Check for non-prefixed, non-standard capabilities and log warnings if they are found
|
|
255
255
|
const nonPrefixedCaps = findNonPrefixedCaps(caps);
|
|
256
|
-
if (!
|
|
256
|
+
if (!util.isEmpty(nonPrefixedCaps)) {
|
|
257
257
|
throw new errors.InvalidArgumentError(
|
|
258
258
|
`All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: ${nonPrefixedCaps}`
|
|
259
259
|
);
|
|
@@ -271,22 +271,24 @@ export function parseCaps<C extends Constraints>(
|
|
|
271
271
|
}
|
|
272
272
|
// Remove the 'presence' constraint for any keys that are already present in 'requiredCaps'
|
|
273
273
|
// since we know that this constraint has already passed
|
|
274
|
-
const filteredConstraints =
|
|
274
|
+
const filteredConstraints = Object.fromEntries(
|
|
275
|
+
Object.entries(constraints ?? {}).filter(([key]) => !(key in strippedRequiredCaps))
|
|
276
|
+
) as C;
|
|
275
277
|
|
|
276
278
|
// Validate all of the first match capabilities and return an array with only the valid caps (see spec #5)
|
|
277
279
|
const validationErrors: string[] = [];
|
|
278
|
-
const validatedFirstMatchCaps =
|
|
279
|
-
|
|
280
|
+
const validatedFirstMatchCaps = strippedAllFirstMatchCaps
|
|
281
|
+
.map((firstMatchCaps) => {
|
|
280
282
|
try {
|
|
281
283
|
// Validate firstMatch caps
|
|
282
284
|
return shouldValidateCaps
|
|
283
285
|
? validateCaps(firstMatchCaps, filteredConstraints)
|
|
284
286
|
: firstMatchCaps;
|
|
285
287
|
} catch (e) {
|
|
286
|
-
validationErrors.push(e.message);
|
|
288
|
+
validationErrors.push((e as Error).message);
|
|
287
289
|
}
|
|
288
290
|
})
|
|
289
|
-
|
|
291
|
+
.filter(Boolean) as Capabilities<C>[];
|
|
290
292
|
|
|
291
293
|
/**
|
|
292
294
|
* Try to merge requiredCaps with first match capabilities, break once it finds its first match
|
|
@@ -300,8 +302,8 @@ export function parseCaps<C extends Constraints>(
|
|
|
300
302
|
break;
|
|
301
303
|
}
|
|
302
304
|
} catch (err) {
|
|
303
|
-
log.warn(err.message);
|
|
304
|
-
validationErrors.push(err.message);
|
|
305
|
+
log.warn((err as Error).message);
|
|
306
|
+
validationErrors.push((err as Error).message);
|
|
305
307
|
}
|
|
306
308
|
}
|
|
307
309
|
|
|
@@ -330,7 +332,7 @@ export function processCapabilities<
|
|
|
330
332
|
|
|
331
333
|
// If we found an error throw an exception
|
|
332
334
|
if (!util.hasValue(matchedCaps)) {
|
|
333
|
-
if (
|
|
335
|
+
if (Array.isArray(w3cCaps.firstMatch) && w3cCaps.firstMatch.length > 1) {
|
|
334
336
|
// If there was more than one 'firstMatch' cap, indicate that we couldn't find a matching capabilities set and show all the errors
|
|
335
337
|
throw new errors.InvalidArgumentError(
|
|
336
338
|
`Could not find matching capabilities from ${JSON.stringify(
|
|
@@ -356,12 +358,12 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
|
|
|
356
358
|
return obj;
|
|
357
359
|
}
|
|
358
360
|
|
|
359
|
-
if (!
|
|
361
|
+
if (!util.isPlainObject(appiumOptions)) {
|
|
360
362
|
throw new errors.SessionNotCreatedError(
|
|
361
363
|
`The ${PREFIXED_APPIUM_OPTS_CAP} capability must be an object`
|
|
362
364
|
);
|
|
363
365
|
}
|
|
364
|
-
if (
|
|
366
|
+
if (util.isEmpty(appiumOptions)) {
|
|
365
367
|
return obj;
|
|
366
368
|
}
|
|
367
369
|
|
|
@@ -374,7 +376,7 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
|
|
|
374
376
|
*/
|
|
375
377
|
const shouldAddVendorPrefix = (capName: string) => !capName.startsWith(APPIUM_VENDOR_PREFIX);
|
|
376
378
|
const verifyIfAcceptable = (capName: string) => {
|
|
377
|
-
if (
|
|
379
|
+
if (typeof capName !== 'string') {
|
|
378
380
|
throw new errors.SessionNotCreatedError(
|
|
379
381
|
`Capability names in ${PREFIXED_APPIUM_OPTS_CAP} must be strings. '${capName}' is unexpected`
|
|
380
382
|
);
|
|
@@ -386,20 +388,23 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
|
|
|
386
388
|
}
|
|
387
389
|
return capName;
|
|
388
390
|
};
|
|
389
|
-
const preprocessedOptions =
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
const preprocessedOptions: Record<string, unknown> = {};
|
|
392
|
+
for (const [key, value] of Object.entries(appiumOptions as Record<string, unknown>)) {
|
|
393
|
+
const verifiedKey = verifyIfAcceptable(key);
|
|
394
|
+
const finalKey = shouldAddVendorPrefix(verifiedKey) ? `${APPIUM_VENDOR_PREFIX}${verifiedKey}` : verifiedKey;
|
|
395
|
+
preprocessedOptions[finalKey] = value;
|
|
396
|
+
}
|
|
393
397
|
// warn if we are going to overwrite any keys on the base caps object
|
|
394
|
-
const overwrittenKeys =
|
|
398
|
+
const overwrittenKeys = Object.keys(obj).filter((key) => key in preprocessedOptions);
|
|
395
399
|
if (overwrittenKeys.length > 0) {
|
|
396
400
|
log.warn(
|
|
397
401
|
`Found capabilities inside ${PREFIXED_APPIUM_OPTS_CAP} that will overwrite ` +
|
|
398
402
|
`capabilities at the top level: ${JSON.stringify(overwrittenKeys)}`
|
|
399
403
|
);
|
|
400
404
|
}
|
|
401
|
-
|
|
402
|
-
|
|
405
|
+
const restObj = omit(obj, PREFIXED_APPIUM_OPTS_CAP) as NSCapabilities<C>;
|
|
406
|
+
return structuredClone({
|
|
407
|
+
...restObj,
|
|
403
408
|
...preprocessedOptions,
|
|
404
409
|
});
|
|
405
410
|
}
|
|
@@ -411,12 +416,12 @@ export function promoteAppiumOptionsForObject<C extends Constraints>(obj: NSCapa
|
|
|
411
416
|
export function promoteAppiumOptions<C extends Constraints>(originalCaps: W3CCapabilities<C>): W3CCapabilities<C> {
|
|
412
417
|
const result = {} as W3CCapabilities<C>;
|
|
413
418
|
const {alwaysMatch, firstMatch} = originalCaps;
|
|
414
|
-
if (
|
|
419
|
+
if (util.isPlainObject(alwaysMatch)) {
|
|
415
420
|
result.alwaysMatch = promoteAppiumOptionsForObject(alwaysMatch);
|
|
416
421
|
} else if ('alwaysMatch' in originalCaps) {
|
|
417
422
|
result.alwaysMatch = alwaysMatch;
|
|
418
423
|
}
|
|
419
|
-
if (
|
|
424
|
+
if (Array.isArray(firstMatch)) {
|
|
420
425
|
result.firstMatch = firstMatch.map(promoteAppiumOptionsForObject);
|
|
421
426
|
} else if ('firstMatch' in originalCaps) {
|
|
422
427
|
result.firstMatch = firstMatch;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import {util} from '@appium/support';
|
|
1
2
|
import type {Constraints, DriverStatus, IBidiCommands} from '@appium/types';
|
|
2
3
|
import type {BaseDriver} from '../driver';
|
|
3
4
|
import {mixin} from './mixin';
|
|
4
|
-
import _ from 'lodash';
|
|
5
5
|
|
|
6
6
|
declare module '../driver' {
|
|
7
7
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -36,15 +36,15 @@ const BidiCommands: IBidiCommands = {
|
|
|
36
36
|
|
|
37
37
|
async bidiStatus<C extends Constraints>(this: BaseDriver<C>): Promise<DriverStatus> {
|
|
38
38
|
const result = await this.getStatus();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
const base: Record<string, unknown> = util.isPlainObject(result) ? {...result} : {};
|
|
40
|
+
return {
|
|
41
|
+
...base,
|
|
42
|
+
ready: 'ready' in base ? (base.ready as boolean) : true,
|
|
43
|
+
message:
|
|
44
|
+
'message' in base
|
|
45
|
+
? (base.message as string)
|
|
46
|
+
: `${this.constructor.name} is ready to accept commands`,
|
|
47
|
+
};
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {Constraints, IEventCommands} from '@appium/types';
|
|
2
|
-
import
|
|
1
|
+
import type {Constraints, EventHistory, IEventCommands} from '@appium/types';
|
|
2
|
+
import {util} from '@appium/support';
|
|
3
3
|
import type {BaseDriver} from '../driver';
|
|
4
4
|
import {mixin} from './mixin';
|
|
5
5
|
|
|
@@ -16,7 +16,7 @@ const EventCommands: IEventCommands = {
|
|
|
16
16
|
* separation
|
|
17
17
|
* @param event - the event name
|
|
18
18
|
*/
|
|
19
|
-
async logCustomEvent<C extends Constraints>(this: BaseDriver<C>, vendor: string, event: string) {
|
|
19
|
+
async logCustomEvent<C extends Constraints>(this: BaseDriver<C>, vendor: string, event: string): Promise<void> {
|
|
20
20
|
this.logEvent(`${vendor}:${event}`);
|
|
21
21
|
},
|
|
22
22
|
|
|
@@ -26,23 +26,24 @@ const EventCommands: IEventCommands = {
|
|
|
26
26
|
* It returns all events if the type is not provided or empty string/array.
|
|
27
27
|
* @returns the event history log object
|
|
28
28
|
*/
|
|
29
|
-
async getLogEvents<C extends Constraints>(this: BaseDriver<C>, type: string | string[])
|
|
30
|
-
|
|
29
|
+
async getLogEvents<C extends Constraints>(this: BaseDriver<C>, type: string | string[]): Promise<
|
|
30
|
+
Partial<EventHistory>
|
|
31
|
+
> {
|
|
32
|
+
if (util.isEmpty(type)) {
|
|
31
33
|
return this.eventHistory;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const typeList =
|
|
36
|
+
const typeList = Array.isArray(type) ? type : [type];
|
|
35
37
|
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
(acc, eventTimes, eventType) => {
|
|
38
|
+
return Object.entries(this.eventHistory).reduce<Partial<EventHistory>>(
|
|
39
|
+
(acc, [eventType, eventTimes]) => {
|
|
39
40
|
if (typeList.includes(eventType)) {
|
|
40
41
|
acc[eventType] = eventTimes;
|
|
41
42
|
}
|
|
42
43
|
return acc;
|
|
43
44
|
},
|
|
44
45
|
{}
|
|
45
|
-
)
|
|
46
|
+
) as Record<string, number>;
|
|
46
47
|
},
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import {errors, validateExecuteMethodParams} from '../../protocol';
|
|
3
3
|
import type {
|
|
4
4
|
Constraints,
|
|
@@ -26,8 +26,8 @@ const ExecuteCommands: IExecuteCommands = {
|
|
|
26
26
|
const Driver = this.constructor as DriverClass<Driver<C>>;
|
|
27
27
|
const commandMetadata = {...Driver.executeMethodMap?.[script]};
|
|
28
28
|
if (!commandMetadata.command) {
|
|
29
|
-
const availableScripts =
|
|
30
|
-
if (
|
|
29
|
+
const availableScripts = Object.keys(Driver.executeMethodMap ?? {});
|
|
30
|
+
if (util.isEmpty(availableScripts)) {
|
|
31
31
|
throw new errors.UnsupportedOperationError(
|
|
32
32
|
`Unsupported execute method '${script}'. ` +
|
|
33
33
|
`Make sure the installed ${Driver.name} is up-to-date. ` +
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {Constraints, Driver, ILogCommands} from '@appium/types';
|
|
2
|
-
import _ from 'lodash';
|
|
3
2
|
import type {BaseDriver} from '../driver';
|
|
4
3
|
import {mixin} from './mixin';
|
|
5
4
|
|
|
@@ -20,7 +19,9 @@ const LogCommands: ILogCommands = {
|
|
|
20
19
|
this.log.debug(`Retrieving '${String(logType)}' logs`);
|
|
21
20
|
|
|
22
21
|
if (!(logType in this.supportedLogTypes)) {
|
|
23
|
-
const logsTypesWithDescriptions =
|
|
22
|
+
const logsTypesWithDescriptions = Object.fromEntries(
|
|
23
|
+
Object.entries(this.supportedLogTypes).map(([key, value]) => [key, value.description])
|
|
24
|
+
);
|
|
24
25
|
throw new Error(
|
|
25
26
|
`Unsupported log type '${String(logType)}'. ` +
|
|
26
27
|
`Supported types: ${JSON.stringify(logsTypesWithDescriptions)}`
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {waitForCondition} from 'asyncbox';
|
|
2
|
-
import _ from 'lodash';
|
|
3
2
|
import {util} from '@appium/support';
|
|
4
3
|
import {errors} from '../../protocol';
|
|
5
4
|
import type {BaseDriver} from '../driver';
|
|
@@ -15,7 +14,7 @@ const MIN_TIMEOUT = 0;
|
|
|
15
14
|
|
|
16
15
|
const TimeoutCommands: ITimeoutCommands = {
|
|
17
16
|
async timeouts<C extends Constraints>(this: BaseDriver<C>, type, ms, script, pageLoad, implicit) {
|
|
18
|
-
if (type &&
|
|
17
|
+
if (type && typeof type === 'string' && util.hasValue(ms)) {
|
|
19
18
|
// legacy stuff with some Appium-specific additions
|
|
20
19
|
this.log.debug(`Timeout arguments: ${JSON.stringify({type, ms})}}`);
|
|
21
20
|
switch (type) {
|
|
@@ -33,7 +32,7 @@ const TimeoutCommands: ITimeoutCommands = {
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
this.log.debug(`W3C timeout argument: ${JSON.stringify({script, pageLoad, implicit})}}`);
|
|
36
|
-
if ([script, pageLoad, implicit].every(
|
|
35
|
+
if ([script, pageLoad, implicit].every((value) => value == null)) {
|
|
37
36
|
throw new errors.InvalidArgumentError('W3C protocol expects any of script, pageLoad or implicit to be set');
|
|
38
37
|
}
|
|
39
38
|
if (util.hasValue(script)) {
|
|
@@ -82,7 +81,7 @@ const TimeoutCommands: ITimeoutCommands = {
|
|
|
82
81
|
if (this.managedDrivers?.length) {
|
|
83
82
|
this.log.debug('Setting implicit wait on managed drivers');
|
|
84
83
|
for (const driver of this.managedDrivers) {
|
|
85
|
-
if (
|
|
84
|
+
if (typeof driver.setImplicitWait === 'function') {
|
|
86
85
|
driver.setImplicitWait(ms);
|
|
87
86
|
}
|
|
88
87
|
}
|
|
@@ -95,7 +94,7 @@ const TimeoutCommands: ITimeoutCommands = {
|
|
|
95
94
|
if (this.managedDrivers?.length) {
|
|
96
95
|
this.log.debug('Setting new command timeout on managed drivers');
|
|
97
96
|
for (const driver of this.managedDrivers) {
|
|
98
|
-
if (
|
|
97
|
+
if (typeof driver.setNewCommandTimeout === 'function') {
|
|
99
98
|
driver.setNewCommandTimeout(ms);
|
|
100
99
|
}
|
|
101
100
|
}
|
|
@@ -122,7 +121,7 @@ const TimeoutCommands: ITimeoutCommands = {
|
|
|
122
121
|
|
|
123
122
|
parseTimeoutArgument<C extends Constraints>(this: BaseDriver<C>, ms: number | string) {
|
|
124
123
|
const duration = parseInt(String(ms), 10);
|
|
125
|
-
if (
|
|
124
|
+
if (Number.isNaN(duration) || duration < MIN_TIMEOUT) {
|
|
126
125
|
throw new errors.UnknownError(`Invalid timeout value '${ms}'`);
|
|
127
126
|
}
|
|
128
127
|
return duration;
|
package/lib/basedriver/core.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
StringRecord,
|
|
13
13
|
} from '@appium/types';
|
|
14
14
|
import AsyncLock from 'async-lock';
|
|
15
|
-
import
|
|
15
|
+
import {util} from '@appium/support';
|
|
16
16
|
import os from 'node:os';
|
|
17
17
|
import {
|
|
18
18
|
DEFAULT_BASE_PATH,
|
|
@@ -116,7 +116,7 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
116
116
|
this.shouldValidateCaps = shouldValidateCaps;
|
|
117
117
|
|
|
118
118
|
// keeping track of initial opts
|
|
119
|
-
this.initialOpts =
|
|
119
|
+
this.initialOpts = structuredClone(opts);
|
|
120
120
|
|
|
121
121
|
this.sessionId = null;
|
|
122
122
|
this.helpers = helpers;
|
|
@@ -166,7 +166,7 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
166
166
|
* inadvertently change data outside of logEvent
|
|
167
167
|
*/
|
|
168
168
|
get eventHistory() {
|
|
169
|
-
return
|
|
169
|
+
return structuredClone(this._eventHistory);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
|
@@ -263,7 +263,7 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
263
263
|
isFeatureEnabled(name: string): boolean {
|
|
264
264
|
// automationName comparison is case-insensitive,
|
|
265
265
|
// while feature name is case-sensitive
|
|
266
|
-
const currentAutomationName =
|
|
266
|
+
const currentAutomationName = String(this.opts.automationName).toLowerCase();
|
|
267
267
|
|
|
268
268
|
const parseFullName = (fullName: string) => {
|
|
269
269
|
const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
|
|
@@ -279,7 +279,7 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
281
|
return [
|
|
282
|
-
|
|
282
|
+
fullName.substring(0, separatorPos).toLowerCase(),
|
|
283
283
|
fullName.substring(separatorPos + 1)
|
|
284
284
|
];
|
|
285
285
|
};
|
|
@@ -288,12 +288,12 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
288
288
|
[currentAutomationName, ALL_DRIVERS_MATCH].includes(automationName) && featureName === name;
|
|
289
289
|
|
|
290
290
|
// if we have explicitly denied this feature, return false immediately
|
|
291
|
-
if (!
|
|
291
|
+
if (!util.isEmpty(this.denyInsecure) && parseFullNames(this.denyInsecure).some(matches)) {
|
|
292
292
|
return false;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// if we specifically have allowed the feature, return true
|
|
296
|
-
if (!
|
|
296
|
+
if (!util.isEmpty(this.allowInsecure) && parseFullNames(this.allowInsecure).some(matches)) {
|
|
297
297
|
return true;
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -332,7 +332,7 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
332
332
|
validStrategies = validStrategies.concat(this.webLocatorStrategies);
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
if (!
|
|
335
|
+
if (!validStrategies.includes(strategy)) {
|
|
336
336
|
throw new errors.InvalidSelectorError(
|
|
337
337
|
`Locator Strategy '${strategy}' is not supported for this session`,
|
|
338
338
|
);
|
|
@@ -370,17 +370,17 @@ export class DriverCore<const C extends Constraints, Settings extends StringReco
|
|
|
370
370
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
371
371
|
proxyRouteIsAvoided(sessionId: string, method: HTTPMethod, url: string, body?: any): boolean {
|
|
372
372
|
for (const avoidSchema of this.getProxyAvoidList(sessionId)) {
|
|
373
|
-
if (!
|
|
373
|
+
if (!Array.isArray(avoidSchema) || avoidSchema.length !== 2) {
|
|
374
374
|
throw new Error('Proxy avoidance must be a list of pairs');
|
|
375
375
|
}
|
|
376
376
|
const [avoidMethod, avoidPathRegex] = avoidSchema;
|
|
377
|
-
if (!
|
|
377
|
+
if (!['GET', 'POST', 'DELETE'].includes(avoidMethod)) {
|
|
378
378
|
throw new Error(`Unrecognized proxy avoidance method '${avoidMethod}'`);
|
|
379
379
|
}
|
|
380
|
-
if (!
|
|
380
|
+
if (!(avoidPathRegex instanceof RegExp)) {
|
|
381
381
|
throw new Error('Proxy avoidance path must be a regular expression');
|
|
382
382
|
}
|
|
383
|
-
const normalizedUrl = url.replace(new RegExp(`^${
|
|
383
|
+
const normalizedUrl = url.replace(new RegExp(`^${util.escapeRegExp(this.basePath)}`), '');
|
|
384
384
|
if (avoidMethod === method && avoidPathRegex.test(normalizedUrl)) {
|
|
385
385
|
return true;
|
|
386
386
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util, node} from '@appium/support';
|
|
2
2
|
import {log} from './logger';
|
|
3
|
-
import {node, util} from '@appium/support';
|
|
4
3
|
import {errors} from '../protocol/errors';
|
|
5
4
|
import type {StringRecord, IDeviceSettings, SettingsUpdateListener} from '@appium/types';
|
|
6
5
|
|
|
@@ -36,7 +35,7 @@ export class DeviceSettings<T extends StringRecord = StringRecord> implements ID
|
|
|
36
35
|
* @param newSettings - New settings to merge (must be plain object; total size remains bounded).
|
|
37
36
|
*/
|
|
38
37
|
async update(newSettings: T): Promise<void> {
|
|
39
|
-
if (!
|
|
38
|
+
if (!util.isPlainObject(newSettings)) {
|
|
40
39
|
throw new errors.InvalidArgumentError(
|
|
41
40
|
`Settings update should be called with valid JSON. Got ` +
|
|
42
41
|
`${JSON.stringify(newSettings)} instead`
|
|
@@ -51,7 +50,7 @@ export class DeviceSettings<T extends StringRecord = StringRecord> implements ID
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
for (const prop in newSettings) {
|
|
54
|
-
if (
|
|
53
|
+
if (this._settings[prop] !== undefined) {
|
|
55
54
|
if (this._settings[prop] === newSettings[prop]) {
|
|
56
55
|
log.debug(`The value of '${prop}' setting did not change. Skipping the update for it`);
|
|
57
56
|
continue;
|