@appium/base-driver 8.5.3 → 8.5.4
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 +1 -1
- package/build/lib/basedriver/commands/event.js +1 -1
- package/build/lib/basedriver/commands/find.d.ts.map +1 -1
- package/build/lib/basedriver/commands/find.js +1 -1
- package/build/lib/basedriver/commands/index.js +1 -1
- package/build/lib/basedriver/commands/log.d.ts.map +1 -1
- package/build/lib/basedriver/commands/log.js +1 -1
- package/build/lib/basedriver/commands/session.js +1 -1
- package/build/lib/basedriver/commands/settings.d.ts.map +1 -1
- package/build/lib/basedriver/commands/settings.js +1 -1
- package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +1 -1
- package/build/lib/basedriver/core.d.ts +120 -139
- package/build/lib/basedriver/core.d.ts.map +1 -1
- package/build/lib/basedriver/core.js +1 -49
- package/build/lib/basedriver/desired-caps.d.ts +5 -2
- package/build/lib/basedriver/desired-caps.d.ts.map +1 -1
- package/build/lib/basedriver/desired-caps.js +14 -18
- package/build/lib/basedriver/device-settings.d.ts +9 -9
- package/build/lib/basedriver/device-settings.d.ts.map +1 -1
- package/build/lib/basedriver/device-settings.js +4 -4
- package/build/lib/basedriver/driver.d.ts +43 -38
- package/build/lib/basedriver/driver.d.ts.map +1 -1
- package/build/lib/basedriver/driver.js +58 -11
- package/build/lib/basedriver/helpers.d.ts +8 -3
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +4 -6
- package/build/lib/basedriver/logger.d.ts +1 -1
- package/build/lib/basedriver/logger.d.ts.map +1 -1
- package/build/lib/basedriver/logger.js +1 -1
- package/build/lib/constants.js +1 -1
- package/build/lib/express/crash.d.ts.map +1 -1
- package/build/lib/express/crash.js +1 -1
- package/build/lib/express/express-logging.d.ts.map +1 -1
- package/build/lib/express/express-logging.js +1 -1
- package/build/lib/express/idempotency.js +1 -1
- package/build/lib/express/logger.d.ts +1 -1
- package/build/lib/express/logger.d.ts.map +1 -1
- package/build/lib/express/logger.js +1 -1
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +1 -1
- package/build/lib/express/server.d.ts +21 -0
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +4 -9
- package/build/lib/express/static.d.ts.map +1 -1
- package/build/lib/express/static.js +2 -2
- package/build/lib/express/websocket.d.ts +14 -11
- package/build/lib/express/websocket.d.ts.map +1 -1
- package/build/lib/express/websocket.js +2 -2
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +1 -1
- package/build/lib/index.d.ts +2 -1
- package/build/lib/index.js +7 -1
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.js +2 -2
- package/build/lib/jsonwp-proxy/proxy.d.ts +30 -5
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +20 -4
- package/build/lib/jsonwp-status/status.d.ts.map +1 -1
- package/build/lib/jsonwp-status/status.js +2 -2
- package/build/lib/protocol/errors.d.ts +17 -8
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +9 -5
- package/build/lib/protocol/helpers.js +1 -1
- package/build/lib/protocol/index.js +1 -1
- package/build/lib/protocol/protocol.d.ts.map +1 -1
- package/build/lib/protocol/protocol.js +1 -1
- package/build/lib/protocol/routes.d.ts +17 -3
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +1 -1
- package/build/lib/protocol/validators.js +1 -1
- package/build/test/basedriver/driver-e2e-tests.js +1 -1
- package/build/test/basedriver/driver-tests.js +1 -1
- package/build/test/basedriver/index.js +1 -1
- package/build/test/e2e/basedriver/driver.e2e.spec.js +1 -1
- package/build/test/e2e/basedriver/helpers.e2e.spec.js +1 -1
- package/build/test/e2e/basedriver/websockets.e2e.spec.js +1 -1
- package/build/test/e2e/express/server.e2e.spec.js +1 -1
- package/build/test/e2e/jsonwp-proxy/proxy.e2e.spec.js +1 -1
- package/build/test/e2e/protocol/fake-driver.js +1 -1
- package/build/test/e2e/protocol/helpers.js +1 -1
- package/build/test/e2e/protocol/protocol.e2e.spec.js +13 -13
- package/build/test/helpers.js +1 -1
- package/build/test/unit/basedriver/capabilities.spec.js +12 -12
- package/build/test/unit/basedriver/capability.spec.js +15 -15
- package/build/test/unit/basedriver/commands/event.spec.js +1 -1
- package/build/test/unit/basedriver/commands/log.spec.js +1 -1
- package/build/test/unit/basedriver/device-settings.spec.js +1 -1
- package/build/test/unit/basedriver/driver.spec.js +1 -1
- package/build/test/unit/basedriver/helpers.spec.js +33 -33
- package/build/test/unit/basedriver/timeout.spec.js +1 -1
- package/build/test/unit/express/server.spec.js +1 -1
- package/build/test/unit/express/static.spec.js +2 -2
- package/build/test/unit/jsonwp-proxy/mock-request.js +1 -1
- package/build/test/unit/jsonwp-proxy/protocol-converter.spec.js +1 -1
- package/build/test/unit/jsonwp-proxy/proxy.spec.js +2 -2
- package/build/test/unit/jsonwp-proxy/url.spec.js +1 -1
- package/build/test/unit/jsonwp-status/status.spec.js +1 -1
- package/build/test/unit/protocol/errors.spec.js +1 -1
- package/build/test/unit/protocol/routes.spec.js +1 -1
- package/build/test/unit/protocol/validator.spec.js +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/basedriver/capabilities.js +95 -47
- package/lib/basedriver/commands/event.js +4 -4
- package/lib/basedriver/commands/find.js +12 -26
- package/lib/basedriver/commands/index.js +7 -7
- package/lib/basedriver/commands/log.js +5 -7
- package/lib/basedriver/commands/session.js +3 -3
- package/lib/basedriver/commands/settings.js +3 -5
- package/lib/basedriver/commands/timeout.js +18 -23
- package/lib/basedriver/core.js +150 -229
- package/lib/basedriver/desired-caps.js +30 -29
- package/lib/basedriver/device-settings.js +21 -20
- package/lib/basedriver/driver.js +131 -96
- package/lib/basedriver/helpers.js +124 -81
- package/lib/basedriver/logger.js +1 -1
- package/lib/constants.js +2 -6
- package/lib/express/crash.js +4 -6
- package/lib/express/express-logging.js +26 -24
- package/lib/express/idempotency.js +16 -16
- package/lib/express/logger.js +1 -1
- package/lib/express/middleware.js +49 -33
- package/lib/express/server.js +68 -44
- package/lib/express/static.js +11 -12
- package/lib/express/websocket.js +26 -16
- package/lib/helpers/capabilities.js +11 -16
- package/lib/index.js +50 -33
- package/lib/jsonwp-proxy/protocol-converter.js +85 -69
- package/lib/jsonwp-proxy/proxy.js +116 -53
- package/lib/jsonwp-status/status.js +36 -29
- package/lib/protocol/errors.js +469 -292
- package/lib/protocol/helpers.js +5 -8
- package/lib/protocol/index.js +22 -15
- package/lib/protocol/protocol.js +103 -55
- package/lib/protocol/routes.js +430 -273
- package/lib/protocol/validators.js +5 -5
- package/package.json +7 -6
- package/test/basedriver/driver-e2e-tests.js +92 -66
- package/test/basedriver/driver-tests.js +90 -33
- package/test/basedriver/index.js +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import _ from 'lodash';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import {validator} from './desired-caps';
|
|
5
|
+
import {util} from '@appium/support';
|
|
6
6
|
import log from './logger';
|
|
7
|
-
import {
|
|
7
|
+
import {errors} from '../protocol/errors';
|
|
8
8
|
|
|
9
9
|
const APPIUM_VENDOR_PREFIX = 'appium:';
|
|
10
10
|
const APPIUM_OPTS_CAP = 'options';
|
|
@@ -17,13 +17,17 @@ const PREFIXED_APPIUM_OPTS_CAP = `${APPIUM_VENDOR_PREFIX}${APPIUM_OPTS_CAP}`;
|
|
|
17
17
|
* @param {Capabilities} [secondary]
|
|
18
18
|
* @returns {Capabilities}
|
|
19
19
|
*/
|
|
20
|
-
function mergeCaps
|
|
20
|
+
function mergeCaps(primary = {}, secondary = {}) {
|
|
21
21
|
let result = Object.assign({}, primary);
|
|
22
22
|
|
|
23
23
|
for (let [name, value] of _.toPairs(secondary)) {
|
|
24
24
|
// Overwriting is not allowed. Primary and secondary must have different properties (w3c rule 4.4)
|
|
25
25
|
if (!_.isUndefined(primary[name])) {
|
|
26
|
-
throw new errors.InvalidArgumentError(
|
|
26
|
+
throw new errors.InvalidArgumentError(
|
|
27
|
+
`property '${name}' should not exist on both primary (${JSON.stringify(
|
|
28
|
+
primary
|
|
29
|
+
)}) and secondary (${JSON.stringify(secondary)}) object`
|
|
30
|
+
);
|
|
27
31
|
}
|
|
28
32
|
result[name] = value;
|
|
29
33
|
}
|
|
@@ -39,8 +43,7 @@ function mergeCaps (primary = {}, secondary = {}) {
|
|
|
39
43
|
* @param {ValidateCapsOpts} [opts]
|
|
40
44
|
* @returns {Capabilities}
|
|
41
45
|
*/
|
|
42
|
-
function validateCaps
|
|
43
|
-
|
|
46
|
+
function validateCaps(caps, constraints = {}, opts = {}) {
|
|
44
47
|
let {skipPresenceConstraint} = opts;
|
|
45
48
|
|
|
46
49
|
if (!_.isPlainObject(caps)) {
|
|
@@ -56,9 +59,9 @@ function validateCaps (caps, constraints = {}, opts = {}) {
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
let validationErrors = validator.validate(_.pickBy(caps, util.hasValue),
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
let validationErrors = validator.validate(_.pickBy(caps, util.hasValue), constraints, {
|
|
63
|
+
fullMessages: false,
|
|
64
|
+
});
|
|
62
65
|
|
|
63
66
|
if (validationErrors) {
|
|
64
67
|
let message = [];
|
|
@@ -84,16 +87,19 @@ const STANDARD_CAPS = [
|
|
|
84
87
|
'proxy',
|
|
85
88
|
'setWindowRect',
|
|
86
89
|
'timeouts',
|
|
87
|
-
'unhandledPromptBehavior'
|
|
90
|
+
'unhandledPromptBehavior',
|
|
88
91
|
];
|
|
89
92
|
|
|
90
|
-
function isStandardCap
|
|
91
|
-
return !!_.find(
|
|
93
|
+
function isStandardCap(cap) {
|
|
94
|
+
return !!_.find(
|
|
95
|
+
STANDARD_CAPS,
|
|
96
|
+
(standardCap) => standardCap.toLowerCase() === `${cap}`.toLowerCase()
|
|
97
|
+
);
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
// If the 'appium:' prefix was provided and it's a valid capability, strip out the prefix (see https://www.w3.org/TR/webdriver/#dfn-extension-capabilities)
|
|
95
101
|
// (NOTE: Method is destructive and mutates contents of caps)
|
|
96
|
-
function stripAppiumPrefixes
|
|
102
|
+
function stripAppiumPrefixes(caps) {
|
|
97
103
|
const prefix = 'appium:';
|
|
98
104
|
const prefixedCaps = _.filter(_.keys(caps), (cap) => `${cap}`.startsWith(prefix));
|
|
99
105
|
const badPrefixedCaps = [];
|
|
@@ -108,8 +114,10 @@ function stripAppiumPrefixes (caps) {
|
|
|
108
114
|
if (_.isNil(caps[strippedCapName])) {
|
|
109
115
|
caps[strippedCapName] = caps[prefixedCap];
|
|
110
116
|
} else {
|
|
111
|
-
log.warn(
|
|
112
|
-
`
|
|
117
|
+
log.warn(
|
|
118
|
+
`Ignoring capability '${prefixedCap}=${caps[prefixedCap]}' and ` +
|
|
119
|
+
`using capability '${strippedCapName}=${caps[strippedCapName]}'`
|
|
120
|
+
);
|
|
113
121
|
}
|
|
114
122
|
} else {
|
|
115
123
|
caps[strippedCapName] = caps[prefixedCap];
|
|
@@ -121,7 +129,11 @@ function stripAppiumPrefixes (caps) {
|
|
|
121
129
|
|
|
122
130
|
// If we found standard caps that were incorrectly prefixed, throw an exception (e.g.: don't accept 'appium:platformName', only accept just 'platformName')
|
|
123
131
|
if (badPrefixedCaps.length > 0) {
|
|
124
|
-
log.warn(
|
|
132
|
+
log.warn(
|
|
133
|
+
`The capabilities ${JSON.stringify(
|
|
134
|
+
badPrefixedCaps
|
|
135
|
+
)} are standard capabilities and do not require "appium:" prefix`
|
|
136
|
+
);
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
|
|
@@ -129,12 +141,15 @@ function stripAppiumPrefixes (caps) {
|
|
|
129
141
|
* Get an array of all the unprefixed caps that are being used in 'alwaysMatch' and all of the 'firstMatch' object
|
|
130
142
|
* @param {Object} caps A capabilities object
|
|
131
143
|
*/
|
|
132
|
-
function findNonPrefixedCaps
|
|
144
|
+
function findNonPrefixedCaps({alwaysMatch = {}, firstMatch = []}) {
|
|
133
145
|
return _.chain([alwaysMatch, ...firstMatch])
|
|
134
|
-
.reduce(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
.reduce(
|
|
147
|
+
(unprefixedCaps, caps) => [
|
|
148
|
+
...unprefixedCaps,
|
|
149
|
+
...Object.keys(caps).filter((cap) => !cap.includes(':') && !isStandardCap(cap)),
|
|
150
|
+
],
|
|
151
|
+
[]
|
|
152
|
+
)
|
|
138
153
|
.uniq()
|
|
139
154
|
.value();
|
|
140
155
|
}
|
|
@@ -147,10 +162,12 @@ function findNonPrefixedCaps ({alwaysMatch = {}, firstMatch = []}) {
|
|
|
147
162
|
* @param {boolean} [shouldValidateCaps]
|
|
148
163
|
* @returns
|
|
149
164
|
*/
|
|
150
|
-
function parseCaps
|
|
165
|
+
function parseCaps(caps, constraints = {}, shouldValidateCaps = true) {
|
|
151
166
|
// If capabilities request is not an object, return error (#1.1)
|
|
152
167
|
if (!_.isPlainObject(caps)) {
|
|
153
|
-
throw new errors.InvalidArgumentError(
|
|
168
|
+
throw new errors.InvalidArgumentError(
|
|
169
|
+
'The capabilities argument was not valid for the following reason(s): "capabilities" must be a JSON object.'
|
|
170
|
+
);
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
// Let 'requiredCaps' be property named 'alwaysMatch' from capabilities request (#2)
|
|
@@ -162,21 +179,27 @@ function parseCaps (caps, constraints = {}, shouldValidateCaps = true) {
|
|
|
162
179
|
|
|
163
180
|
// Reject 'firstMatch' argument if it's not an array (#3.2)
|
|
164
181
|
if (!_.isArray(allFirstMatchCaps)) {
|
|
165
|
-
throw new errors.InvalidArgumentError(
|
|
182
|
+
throw new errors.InvalidArgumentError(
|
|
183
|
+
'The capabilities.firstMatch argument was not valid for the following reason(s): "capabilities.firstMatch" must be a JSON array or undefined'
|
|
184
|
+
);
|
|
166
185
|
}
|
|
167
186
|
|
|
168
187
|
// If an empty array as provided, we'll be forgiving and make it an array of one empty object
|
|
169
188
|
// In the future, reject 'firstMatch' argument if its array did not have one or more entries (#3.2)
|
|
170
189
|
if (allFirstMatchCaps.length === 0) {
|
|
171
|
-
log.warn(
|
|
172
|
-
`
|
|
190
|
+
log.warn(
|
|
191
|
+
`The firstMatch array in the given capabilities has no entries. Adding an empty entry fo rnow, ` +
|
|
192
|
+
`but it will require one or more entries as W3C spec.`
|
|
193
|
+
);
|
|
173
194
|
allFirstMatchCaps.push({});
|
|
174
195
|
}
|
|
175
196
|
|
|
176
197
|
// Check for non-prefixed, non-standard capabilities and log warnings if they are found
|
|
177
198
|
let nonPrefixedCaps = findNonPrefixedCaps(caps);
|
|
178
199
|
if (!_.isEmpty(nonPrefixedCaps)) {
|
|
179
|
-
throw new errors.InvalidArgumentError(
|
|
200
|
+
throw new errors.InvalidArgumentError(
|
|
201
|
+
`All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: ${nonPrefixedCaps}`
|
|
202
|
+
);
|
|
180
203
|
}
|
|
181
204
|
|
|
182
205
|
// Strip out the 'appium:' prefix from all
|
|
@@ -187,10 +210,11 @@ function parseCaps (caps, constraints = {}, shouldValidateCaps = true) {
|
|
|
187
210
|
|
|
188
211
|
// Validate the requiredCaps. But don't validate 'presence' because if that constraint fails on 'alwaysMatch' it could still pass on one of the 'firstMatch' keys
|
|
189
212
|
if (shouldValidateCaps) {
|
|
190
|
-
requiredCaps = validateCaps(requiredCaps, constraints, {
|
|
213
|
+
requiredCaps = validateCaps(requiredCaps, constraints, {
|
|
214
|
+
skipPresenceConstraint: true,
|
|
215
|
+
});
|
|
191
216
|
}
|
|
192
217
|
|
|
193
|
-
|
|
194
218
|
// Remove the 'presence' constraint for any keys that are already present in 'requiredCaps'
|
|
195
219
|
// since we know that this constraint has already passed
|
|
196
220
|
let filteredConstraints = {...constraints};
|
|
@@ -204,14 +228,18 @@ function parseCaps (caps, constraints = {}, shouldValidateCaps = true) {
|
|
|
204
228
|
// Validate all of the first match capabilities and return an array with only the valid caps (see spec #5)
|
|
205
229
|
let validationErrors = [];
|
|
206
230
|
/** @type {Capabilities[]} */
|
|
207
|
-
let validatedFirstMatchCaps = _.compact(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
231
|
+
let validatedFirstMatchCaps = _.compact(
|
|
232
|
+
allFirstMatchCaps.map((firstMatchCaps) => {
|
|
233
|
+
try {
|
|
234
|
+
// Validate firstMatch caps
|
|
235
|
+
return shouldValidateCaps
|
|
236
|
+
? validateCaps(firstMatchCaps, filteredConstraints)
|
|
237
|
+
: firstMatchCaps;
|
|
238
|
+
} catch (e) {
|
|
239
|
+
validationErrors.push(e.message);
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
);
|
|
215
243
|
|
|
216
244
|
// Try to merge requiredCaps with first match capabilities, break once it finds its first match (see spec #6)
|
|
217
245
|
let matchedCaps = null;
|
|
@@ -228,7 +256,13 @@ function parseCaps (caps, constraints = {}, shouldValidateCaps = true) {
|
|
|
228
256
|
}
|
|
229
257
|
|
|
230
258
|
// Returns variables for testing purposes
|
|
231
|
-
return {
|
|
259
|
+
return {
|
|
260
|
+
requiredCaps,
|
|
261
|
+
allFirstMatchCaps,
|
|
262
|
+
validatedFirstMatchCaps,
|
|
263
|
+
matchedCaps,
|
|
264
|
+
validationErrors,
|
|
265
|
+
};
|
|
232
266
|
}
|
|
233
267
|
|
|
234
268
|
// Calls parseCaps and just returns the matchedCaps variable
|
|
@@ -239,14 +273,18 @@ function parseCaps (caps, constraints = {}, shouldValidateCaps = true) {
|
|
|
239
273
|
* @param {boolean} [shouldValidateCaps]
|
|
240
274
|
* @returns {Capabilities}
|
|
241
275
|
*/
|
|
242
|
-
function processCapabilities
|
|
276
|
+
function processCapabilities(w3cCaps, constraints = {}, shouldValidateCaps = true) {
|
|
243
277
|
const {matchedCaps, validationErrors} = parseCaps(w3cCaps, constraints, shouldValidateCaps);
|
|
244
278
|
|
|
245
279
|
// If we found an error throw an exception
|
|
246
280
|
if (!util.hasValue(matchedCaps)) {
|
|
247
281
|
if (_.isArray(w3cCaps.firstMatch) && w3cCaps.firstMatch.length > 1) {
|
|
248
282
|
// If there was more than one 'firstMatch' cap, indicate that we couldn't find a matching capabilities set and show all the errors
|
|
249
|
-
throw new errors.InvalidArgumentError(
|
|
283
|
+
throw new errors.InvalidArgumentError(
|
|
284
|
+
`Could not find matching capabilities from ${JSON.stringify(
|
|
285
|
+
w3cCaps
|
|
286
|
+
)}:\n ${validationErrors.join('\n')}`
|
|
287
|
+
);
|
|
250
288
|
} else {
|
|
251
289
|
// Otherwise, just show the singular error message
|
|
252
290
|
throw new errors.InvalidArgumentError(validationErrors[0]);
|
|
@@ -267,7 +305,7 @@ function processCapabilities (w3cCaps, constraints = {}, shouldValidateCaps = tr
|
|
|
267
305
|
* @param {object} originalCaps - the capabilities to analyze and promote from 'options'
|
|
268
306
|
* @return {object!} - the capabilities with 'options' promoted if necessary
|
|
269
307
|
*/
|
|
270
|
-
function promoteAppiumOptions
|
|
308
|
+
function promoteAppiumOptions(originalCaps) {
|
|
271
309
|
const appiumOptions = originalCaps[APPIUM_OPTS_CAP];
|
|
272
310
|
if (!appiumOptions) {
|
|
273
311
|
return originalCaps;
|
|
@@ -284,8 +322,10 @@ function promoteAppiumOptions (originalCaps) {
|
|
|
284
322
|
// warn if we are going to overwrite any keys on the base caps object
|
|
285
323
|
const overwrittenKeys = _.intersection(Object.keys(caps), Object.keys(appiumOptions));
|
|
286
324
|
if (overwrittenKeys.length > 0) {
|
|
287
|
-
log.warn(
|
|
288
|
-
|
|
325
|
+
log.warn(
|
|
326
|
+
`Found capabilities inside ${PREFIXED_APPIUM_OPTS_CAP} that will overwrite ` +
|
|
327
|
+
`capabilities at the top level: ${JSON.stringify(overwrittenKeys)}`
|
|
328
|
+
);
|
|
289
329
|
}
|
|
290
330
|
|
|
291
331
|
// now just apply them to the main caps object
|
|
@@ -296,10 +336,18 @@ function promoteAppiumOptions (originalCaps) {
|
|
|
296
336
|
return caps;
|
|
297
337
|
}
|
|
298
338
|
|
|
299
|
-
|
|
300
339
|
export {
|
|
301
|
-
parseCaps,
|
|
302
|
-
|
|
340
|
+
parseCaps,
|
|
341
|
+
processCapabilities,
|
|
342
|
+
validateCaps,
|
|
343
|
+
mergeCaps,
|
|
344
|
+
APPIUM_VENDOR_PREFIX,
|
|
345
|
+
APPIUM_OPTS_CAP,
|
|
346
|
+
findNonPrefixedCaps,
|
|
347
|
+
isStandardCap,
|
|
348
|
+
stripAppiumPrefixes,
|
|
349
|
+
promoteAppiumOptions,
|
|
350
|
+
PREFIXED_APPIUM_OPTS_CAP,
|
|
303
351
|
};
|
|
304
352
|
|
|
305
353
|
/**
|
|
@@ -6,7 +6,7 @@ import _ from 'lodash';
|
|
|
6
6
|
* @param {TimeoutBase} Base
|
|
7
7
|
* @returns {EventBase}
|
|
8
8
|
*/
|
|
9
|
-
export function EventMixin
|
|
9
|
+
export function EventMixin(Base) {
|
|
10
10
|
/**
|
|
11
11
|
* @implements {IEventCommands}
|
|
12
12
|
*/
|
|
@@ -18,7 +18,7 @@ export function EventMixin (Base) {
|
|
|
18
18
|
* separation
|
|
19
19
|
* @param {string} event - the event name
|
|
20
20
|
*/
|
|
21
|
-
async logCustomEvent
|
|
21
|
+
async logCustomEvent(vendor, event) {
|
|
22
22
|
this.logEvent(`${vendor}:${event}`);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ export function EventMixin (Base) {
|
|
|
28
28
|
* It returns all events if the type is not provided or empty string/array.
|
|
29
29
|
* @returns {Promise<import('@appium/types').EventHistory|Record<string,number>>} - the event history log object
|
|
30
30
|
*/
|
|
31
|
-
async getLogEvents
|
|
31
|
+
async getLogEvents(type) {
|
|
32
32
|
if (_.isEmpty(type)) {
|
|
33
33
|
return this.eventHistory;
|
|
34
34
|
}
|
|
@@ -43,7 +43,7 @@ export function EventMixin (Base) {
|
|
|
43
43
|
}
|
|
44
44
|
return acc;
|
|
45
45
|
},
|
|
46
|
-
{}
|
|
46
|
+
{}
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -8,7 +8,7 @@ import {errors} from '../../protocol';
|
|
|
8
8
|
* @param {EventBase} Base
|
|
9
9
|
* @returns {FindBase}
|
|
10
10
|
*/
|
|
11
|
-
export function FindMixin
|
|
11
|
+
export function FindMixin(Base) {
|
|
12
12
|
/**
|
|
13
13
|
* @implements {IFindCommands}
|
|
14
14
|
*/
|
|
@@ -17,7 +17,7 @@ export function FindMixin (Base) {
|
|
|
17
17
|
*
|
|
18
18
|
* @returns {Promise<Element>}
|
|
19
19
|
*/
|
|
20
|
-
async findElement
|
|
20
|
+
async findElement(strategy, selector) {
|
|
21
21
|
return await this.findElOrElsWithProcessing(strategy, selector, false);
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ export function FindMixin (Base) {
|
|
|
25
25
|
*
|
|
26
26
|
* @returns {Promise<Element[]>}
|
|
27
27
|
*/
|
|
28
|
-
async findElements
|
|
28
|
+
async findElements(strategy, selector) {
|
|
29
29
|
return await this.findElOrElsWithProcessing(strategy, selector, true);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -33,26 +33,16 @@ export function FindMixin (Base) {
|
|
|
33
33
|
*
|
|
34
34
|
* @returns {Promise<Element>}
|
|
35
35
|
*/
|
|
36
|
-
async findElementFromElement
|
|
37
|
-
return await this.findElOrElsWithProcessing(
|
|
38
|
-
strategy,
|
|
39
|
-
selector,
|
|
40
|
-
false,
|
|
41
|
-
elementId,
|
|
42
|
-
);
|
|
36
|
+
async findElementFromElement(strategy, selector, elementId) {
|
|
37
|
+
return await this.findElOrElsWithProcessing(strategy, selector, false, elementId);
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
/**
|
|
46
41
|
*
|
|
47
42
|
* @returns {Promise<Element[]>}
|
|
48
43
|
*/
|
|
49
|
-
async findElementsFromElement
|
|
50
|
-
return await this.findElOrElsWithProcessing(
|
|
51
|
-
strategy,
|
|
52
|
-
selector,
|
|
53
|
-
true,
|
|
54
|
-
elementId,
|
|
55
|
-
);
|
|
44
|
+
async findElementsFromElement(strategy, selector, elementId) {
|
|
45
|
+
return await this.findElOrElsWithProcessing(strategy, selector, true, elementId);
|
|
56
46
|
}
|
|
57
47
|
// Override the following function for your own driver, and the rest is taken
|
|
58
48
|
// care of!
|
|
@@ -66,14 +56,14 @@ export function FindMixin (Base) {
|
|
|
66
56
|
* @param {string} [context]
|
|
67
57
|
* @returns {Promise<Mult extends true ? Element[] : Element>}
|
|
68
58
|
*/
|
|
69
|
-
async findElOrEls
|
|
59
|
+
async findElOrEls(strategy, selector, mult, context) {
|
|
70
60
|
throw new errors.NotImplementedError('Not implemented yet for find.');
|
|
71
61
|
}
|
|
72
62
|
|
|
73
63
|
/**
|
|
74
64
|
* @returns {Promise<string>}
|
|
75
65
|
*/
|
|
76
|
-
async getPageSource
|
|
66
|
+
async getPageSource() {
|
|
77
67
|
throw new errors.NotImplementedError('Not implemented yet for find.');
|
|
78
68
|
}
|
|
79
69
|
/**
|
|
@@ -84,19 +74,15 @@ export function FindMixin (Base) {
|
|
|
84
74
|
* @param {string} [context]
|
|
85
75
|
* @returns {Promise<Mult extends true ? Element[] : Element>}
|
|
86
76
|
*/
|
|
87
|
-
async findElOrElsWithProcessing
|
|
77
|
+
async findElOrElsWithProcessing(strategy, selector, mult, context) {
|
|
88
78
|
this.validateLocatorStrategy(strategy);
|
|
89
79
|
try {
|
|
90
80
|
return await this.findElOrEls(strategy, selector, mult, context);
|
|
91
81
|
} catch (err) {
|
|
92
82
|
if (this.opts.printPageSourceOnFindFailure) {
|
|
93
83
|
const src = await this.getPageSource();
|
|
94
|
-
this.log.debug(
|
|
95
|
-
|
|
96
|
-
);
|
|
97
|
-
this.log.debug(
|
|
98
|
-
`Page source requested through 'printPageSourceOnFindFailure':`,
|
|
99
|
-
);
|
|
84
|
+
this.log.debug(`Error finding element${mult ? 's' : ''}: ${err.message}`);
|
|
85
|
+
this.log.debug(`Page source requested through 'printPageSourceOnFindFailure':`);
|
|
100
86
|
this.log.debug(src);
|
|
101
87
|
}
|
|
102
88
|
// still want the error to occur
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import {EventMixin} from './event';
|
|
4
|
+
import {FindMixin} from './find';
|
|
5
|
+
import {LogMixin} from './log';
|
|
6
|
+
import {SessionMixin} from './session';
|
|
7
|
+
import {SettingsMixin} from './settings';
|
|
8
|
+
import {TimeoutMixin} from './timeout';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Applies all the mixins to the `BaseDriverBase` class.
|
|
12
12
|
* Returns a `BaseDriver` class.
|
|
13
13
|
* @param {BaseDriverBase} Base
|
|
14
14
|
*/
|
|
15
|
-
export function createBaseDriverClass
|
|
15
|
+
export function createBaseDriverClass(Base) {
|
|
16
16
|
const WithTimeoutCommands = TimeoutMixin(Base);
|
|
17
17
|
const WithEventCommands = EventMixin(WithTimeoutCommands);
|
|
18
18
|
const WithFindCommands = FindMixin(WithEventCommands);
|
|
@@ -8,19 +8,18 @@ import _ from 'lodash';
|
|
|
8
8
|
* @param {FindBase} Base
|
|
9
9
|
* @returns {LogBase}
|
|
10
10
|
*/
|
|
11
|
-
export function LogMixin
|
|
11
|
+
export function LogMixin(Base) {
|
|
12
12
|
/**
|
|
13
13
|
* @implements {ILogCommands}
|
|
14
14
|
*/
|
|
15
15
|
class LogCommands extends Base {
|
|
16
|
-
|
|
17
|
-
constructor (...args) {
|
|
16
|
+
constructor(...args) {
|
|
18
17
|
super(...args);
|
|
19
18
|
/** @type {Record<string, LogType<Driver>>} */
|
|
20
19
|
this.supportedLogTypes = this.supportedLogTypes ?? {};
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
async getLogTypes
|
|
22
|
+
async getLogTypes() {
|
|
24
23
|
this.log.debug('Retrieving supported log types');
|
|
25
24
|
return _.keys(this.supportedLogTypes);
|
|
26
25
|
}
|
|
@@ -29,14 +28,14 @@ export function LogMixin (Base) {
|
|
|
29
28
|
* @this {Driver}
|
|
30
29
|
* @param {string} logType
|
|
31
30
|
*/
|
|
32
|
-
async getLog
|
|
31
|
+
async getLog(logType) {
|
|
33
32
|
this.log.debug(`Retrieving '${logType}' logs`);
|
|
34
33
|
|
|
35
34
|
if (!(await this.getLogTypes()).includes(logType)) {
|
|
36
35
|
const logsTypesWithDescriptions = _.mapValues(this.supportedLogTypes, 'description');
|
|
37
36
|
throw new Error(
|
|
38
37
|
`Unsupported log type '${logType}'. ` +
|
|
39
|
-
`Supported types: ${JSON.stringify(logsTypesWithDescriptions)}
|
|
38
|
+
`Supported types: ${JSON.stringify(logsTypesWithDescriptions)}`
|
|
40
39
|
);
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -46,7 +45,6 @@ export function LogMixin (Base) {
|
|
|
46
45
|
return LogCommands;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
|
|
50
48
|
/**
|
|
51
49
|
* @typedef {import('@appium/types').LogCommands} ILogCommands
|
|
52
50
|
* @typedef {import('@appium/types').Driver} Driver
|
|
@@ -7,7 +7,7 @@ import _ from 'lodash';
|
|
|
7
7
|
* @param {SettingsBase} Base
|
|
8
8
|
* @returns {SessionBase}
|
|
9
9
|
*/
|
|
10
|
-
export function SessionMixin
|
|
10
|
+
export function SessionMixin(Base) {
|
|
11
11
|
/**
|
|
12
12
|
* @implements {ISessionCommands}
|
|
13
13
|
*/
|
|
@@ -15,7 +15,7 @@ export function SessionMixin (Base) {
|
|
|
15
15
|
/**
|
|
16
16
|
* @returns {Promise<MultiSessionData[]>}
|
|
17
17
|
*/
|
|
18
|
-
async getSessions
|
|
18
|
+
async getSessions() {
|
|
19
19
|
let ret = [];
|
|
20
20
|
|
|
21
21
|
if (this.sessionId) {
|
|
@@ -31,7 +31,7 @@ export function SessionMixin (Base) {
|
|
|
31
31
|
/**
|
|
32
32
|
* @returns {Promise<SingularSessionData>}
|
|
33
33
|
*/
|
|
34
|
-
async getSession
|
|
34
|
+
async getSession() {
|
|
35
35
|
if (this.caps.eventTimings) {
|
|
36
36
|
return {...this.caps, events: this.eventHistory};
|
|
37
37
|
}
|
|
@@ -5,26 +5,24 @@
|
|
|
5
5
|
* @param {ReturnType<import('./log').LogMixin>} Base
|
|
6
6
|
* @returns {SettingsBase}
|
|
7
7
|
*/
|
|
8
|
-
export function SettingsMixin
|
|
8
|
+
export function SettingsMixin(Base) {
|
|
9
9
|
/**
|
|
10
10
|
* @implements {ISettingsCommands}
|
|
11
11
|
*/
|
|
12
12
|
class SettingsCommands extends Base {
|
|
13
|
-
|
|
14
|
-
async updateSettings (newSettings) {
|
|
13
|
+
async updateSettings(newSettings) {
|
|
15
14
|
if (!this.settings) {
|
|
16
15
|
this.log.errorAndThrow('Cannot update settings; settings object not found');
|
|
17
16
|
}
|
|
18
17
|
return await this.settings.update(newSettings);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
async getSettings
|
|
20
|
+
async getSettings() {
|
|
22
21
|
if (!this.settings) {
|
|
23
22
|
this.log.errorAndThrow('Cannot get settings; settings object not found');
|
|
24
23
|
}
|
|
25
24
|
return await this.settings.getSettings();
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
return SettingsCommands;
|
|
@@ -13,17 +13,14 @@ const MIN_TIMEOUT = 0;
|
|
|
13
13
|
* @param {import('../driver').BaseDriverBase} Base
|
|
14
14
|
* @returns {TimeoutBase}
|
|
15
15
|
*/
|
|
16
|
-
export function TimeoutMixin
|
|
17
|
-
|
|
16
|
+
export function TimeoutMixin(Base) {
|
|
18
17
|
/**
|
|
19
18
|
* @implements {ITimeoutCommands}
|
|
20
19
|
*/
|
|
21
20
|
class TimeoutCommands extends Base {
|
|
22
|
-
async timeouts
|
|
21
|
+
async timeouts(type, ms, script, pageLoad, implicit) {
|
|
23
22
|
if (util.hasValue(type) && util.hasValue(ms)) {
|
|
24
|
-
this.log.debug(
|
|
25
|
-
`MJSONWP timeout arguments: ${JSON.stringify({type, ms})}}`,
|
|
26
|
-
);
|
|
23
|
+
this.log.debug(`MJSONWP timeout arguments: ${JSON.stringify({type, ms})}}`);
|
|
27
24
|
|
|
28
25
|
switch (type) {
|
|
29
26
|
case 'command':
|
|
@@ -39,9 +36,7 @@ export function TimeoutMixin (Base) {
|
|
|
39
36
|
await this.scriptTimeoutMJSONWP(ms);
|
|
40
37
|
return;
|
|
41
38
|
default:
|
|
42
|
-
throw new Error(
|
|
43
|
-
`'${type}' type is not supported for MJSONWP timeout`,
|
|
44
|
-
);
|
|
39
|
+
throw new Error(`'${type}' type is not supported for MJSONWP timeout`);
|
|
45
40
|
}
|
|
46
41
|
}
|
|
47
42
|
|
|
@@ -51,7 +46,7 @@ export function TimeoutMixin (Base) {
|
|
|
51
46
|
script,
|
|
52
47
|
pageLoad,
|
|
53
48
|
implicit,
|
|
54
|
-
})}}
|
|
49
|
+
})}}`
|
|
55
50
|
);
|
|
56
51
|
if (util.hasValue(script)) {
|
|
57
52
|
await this.scriptTimeoutW3C(script);
|
|
@@ -64,7 +59,7 @@ export function TimeoutMixin (Base) {
|
|
|
64
59
|
}
|
|
65
60
|
}
|
|
66
61
|
|
|
67
|
-
async getTimeouts
|
|
62
|
+
async getTimeouts() {
|
|
68
63
|
return {
|
|
69
64
|
command: this.newCommandTimeoutMs,
|
|
70
65
|
implicit: this.implicitWaitMs,
|
|
@@ -72,42 +67,42 @@ export function TimeoutMixin (Base) {
|
|
|
72
67
|
}
|
|
73
68
|
|
|
74
69
|
// implicit
|
|
75
|
-
async implicitWaitW3C
|
|
70
|
+
async implicitWaitW3C(ms) {
|
|
76
71
|
await this.implicitWait(ms);
|
|
77
72
|
}
|
|
78
73
|
|
|
79
|
-
async implicitWaitMJSONWP
|
|
74
|
+
async implicitWaitMJSONWP(ms) {
|
|
80
75
|
await this.implicitWait(ms);
|
|
81
76
|
}
|
|
82
77
|
|
|
83
|
-
async implicitWait
|
|
78
|
+
async implicitWait(ms) {
|
|
84
79
|
await this.setImplicitWait(this.parseTimeoutArgument(ms));
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
// pageLoad
|
|
88
|
-
async pageLoadTimeoutW3C
|
|
83
|
+
async pageLoadTimeoutW3C(ms) {
|
|
89
84
|
throw new errors.NotImplementedError('Not implemented yet for pageLoad.');
|
|
90
85
|
}
|
|
91
86
|
|
|
92
|
-
async pageLoadTimeoutMJSONWP
|
|
87
|
+
async pageLoadTimeoutMJSONWP(ms) {
|
|
93
88
|
throw new errors.NotImplementedError('Not implemented yet for pageLoad.');
|
|
94
89
|
}
|
|
95
90
|
|
|
96
91
|
// script
|
|
97
|
-
async scriptTimeoutW3C
|
|
92
|
+
async scriptTimeoutW3C(ms) {
|
|
98
93
|
throw new errors.NotImplementedError('Not implemented yet for script.');
|
|
99
94
|
}
|
|
100
95
|
|
|
101
|
-
async scriptTimeoutMJSONWP
|
|
96
|
+
async scriptTimeoutMJSONWP(ms) {
|
|
102
97
|
throw new errors.NotImplementedError('Not implemented yet for script.');
|
|
103
98
|
}
|
|
104
99
|
|
|
105
100
|
// command
|
|
106
|
-
async newCommandTimeout
|
|
101
|
+
async newCommandTimeout(ms) {
|
|
107
102
|
this.setNewCommandTimeout(this.parseTimeoutArgument(ms));
|
|
108
103
|
}
|
|
109
104
|
|
|
110
|
-
setImplicitWait
|
|
105
|
+
setImplicitWait(ms) {
|
|
111
106
|
// eslint-disable-line require-await
|
|
112
107
|
this.implicitWaitMs = ms;
|
|
113
108
|
this.log.debug(`Set implicit wait to ${ms}ms`);
|
|
@@ -121,7 +116,7 @@ export function TimeoutMixin (Base) {
|
|
|
121
116
|
}
|
|
122
117
|
}
|
|
123
118
|
|
|
124
|
-
setNewCommandTimeout
|
|
119
|
+
setNewCommandTimeout(ms) {
|
|
125
120
|
this.newCommandTimeoutMs = ms;
|
|
126
121
|
this.log.debug(`Set new command timeout to ${ms}ms`);
|
|
127
122
|
if (this.managedDrivers && this.managedDrivers.length) {
|
|
@@ -134,7 +129,7 @@ export function TimeoutMixin (Base) {
|
|
|
134
129
|
}
|
|
135
130
|
}
|
|
136
131
|
|
|
137
|
-
async implicitWaitForCondition
|
|
132
|
+
async implicitWaitForCondition(condFn) {
|
|
138
133
|
this.log.debug(`Waiting up to ${this.implicitWaitMs} ms for condition`);
|
|
139
134
|
let wrappedCondFn = async (...args) => {
|
|
140
135
|
// reset command timeout
|
|
@@ -149,7 +144,7 @@ export function TimeoutMixin (Base) {
|
|
|
149
144
|
});
|
|
150
145
|
}
|
|
151
146
|
|
|
152
|
-
parseTimeoutArgument
|
|
147
|
+
parseTimeoutArgument(ms) {
|
|
153
148
|
let duration = parseInt(ms, 10);
|
|
154
149
|
if (_.isNaN(duration) || duration < MIN_TIMEOUT) {
|
|
155
150
|
throw new errors.UnknownError(`Invalid timeout value '${ms}'`);
|