appium 3.0.0-beta.0 → 3.0.0-rc.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/build/lib/appium.d.ts +14 -9
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +27 -53
- package/build/lib/appium.js.map +1 -1
- package/build/lib/cli/driver-command.js +1 -1
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.js +1 -1
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/parser.js +1 -1
- package/build/lib/cli/plugin-command.js +1 -1
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/constants.d.ts +7 -1
- package/build/lib/constants.d.ts.map +1 -1
- package/build/lib/constants.js +8 -2
- package/build/lib/constants.js.map +1 -1
- package/build/lib/extension/extension-config.js +1 -1
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/insecure-features.d.ts +18 -0
- package/build/lib/insecure-features.d.ts.map +1 -0
- package/build/lib/insecure-features.js +116 -0
- package/build/lib/insecure-features.js.map +1 -0
- package/build/lib/main.d.ts +1 -1
- package/build/lib/main.d.ts.map +1 -1
- package/build/lib/main.js +3 -1
- package/build/lib/main.js.map +1 -1
- package/build/lib/schema/cli-args.d.ts +1 -1
- package/build/lib/schema/cli-args.js +1 -1
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/schema.d.ts +1 -1
- package/build/lib/schema/schema.js +1 -1
- package/build/lib/utils.d.ts +6 -19
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +51 -118
- package/build/lib/utils.js.map +1 -1
- package/lib/appium.js +33 -69
- package/lib/cli/driver-command.js +1 -1
- package/lib/cli/extension-command.js +1 -1
- package/lib/cli/parser.js +1 -1
- package/lib/cli/plugin-command.js +1 -1
- package/lib/constants.js +8 -1
- package/lib/extension/extension-config.js +1 -1
- package/lib/insecure-features.ts +129 -0
- package/lib/main.js +4 -1
- package/lib/schema/cli-args.js +2 -2
- package/lib/schema/schema.js +1 -1
- package/lib/utils.js +56 -131
- package/package.json +16 -16
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import logger from './logger';
|
|
3
|
+
|
|
4
|
+
import type {AppiumDriver} from './appium';
|
|
5
|
+
import type {ExternalDriver} from '@appium/types';
|
|
6
|
+
|
|
7
|
+
const ALL_DRIVERS_MATCH = '*';
|
|
8
|
+
const FEATURE_NAME_SEPARATOR = ':';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Configures insecure features according to the values in `args.relaxedSecurityEnabled`,
|
|
12
|
+
* `args.allowInsecure`, and `args.denyInsecure`, and informs the user about any
|
|
13
|
+
* globally-applied features.
|
|
14
|
+
* Uses `logger` instead of `this.log` to reduce user confusion.
|
|
15
|
+
*/
|
|
16
|
+
export function configureGlobalFeatures(this: AppiumDriver) {
|
|
17
|
+
if (this.args.relaxedSecurityEnabled) {
|
|
18
|
+
logger.info(
|
|
19
|
+
`Enabling relaxed security. All insecure features will be ` +
|
|
20
|
+
`enabled unless explicitly disabled by --deny-insecure`,
|
|
21
|
+
);
|
|
22
|
+
this.relaxedSecurityEnabled = true;
|
|
23
|
+
} else if (!_.isEmpty(this.args.allowInsecure)) {
|
|
24
|
+
this.allowInsecure = validateFeatures(this.args.allowInsecure);
|
|
25
|
+
const globalAllowedFeatures = filterInsecureFeatures(this.allowInsecure);
|
|
26
|
+
if (!_.isEmpty(globalAllowedFeatures)) {
|
|
27
|
+
logger.info('Explicitly enabling insecure features:');
|
|
28
|
+
globalAllowedFeatures.forEach((a) => logger.info(` ${a}`));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (_.isEmpty(this.args.denyInsecure)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.denyInsecure = validateFeatures(this.args.denyInsecure);
|
|
35
|
+
const globalDeniedFeatures = filterInsecureFeatures(this.denyInsecure);
|
|
36
|
+
if (_.isEmpty(globalDeniedFeatures)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
logger.info('Explicitly disabling insecure features:');
|
|
40
|
+
globalDeniedFeatures.forEach((a) => logger.info(` ${a}`));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* If anything in the umbrella driver's insecure feature configuration applies to this driver,
|
|
45
|
+
* assign it to the driver instance
|
|
46
|
+
*
|
|
47
|
+
* @param driver
|
|
48
|
+
* @param driverName
|
|
49
|
+
*/
|
|
50
|
+
export function configureDriverFeatures(
|
|
51
|
+
this: AppiumDriver,
|
|
52
|
+
driver: ExternalDriver,
|
|
53
|
+
driverName: string,
|
|
54
|
+
) {
|
|
55
|
+
if (this.relaxedSecurityEnabled) {
|
|
56
|
+
this.log.info(
|
|
57
|
+
`Enabling relaxed security for this session as per the server configuration. ` +
|
|
58
|
+
`All insecure features will be enabled unless explicitly disabled by --deny-insecure`,
|
|
59
|
+
);
|
|
60
|
+
driver.relaxedSecurityEnabled = true;
|
|
61
|
+
}
|
|
62
|
+
const allowedDriverFeatures = filterInsecureFeatures(this.allowInsecure, driverName);
|
|
63
|
+
if (!_.isEmpty(allowedDriverFeatures)) {
|
|
64
|
+
this.log.info('Explicitly enabling insecure features for this session ' +
|
|
65
|
+
'as per the server configuration:',
|
|
66
|
+
);
|
|
67
|
+
allowedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
|
|
68
|
+
driver.allowInsecure = allowedDriverFeatures;
|
|
69
|
+
}
|
|
70
|
+
const deniedDriverFeatures = filterInsecureFeatures(this.denyInsecure, driverName);
|
|
71
|
+
if (_.isEmpty(deniedDriverFeatures)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.log.info('Explicitly disabling insecure features for this session ' +
|
|
75
|
+
'as per the server configuration:',
|
|
76
|
+
);
|
|
77
|
+
deniedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
|
|
78
|
+
driver.denyInsecure = deniedDriverFeatures;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Validates the list of allowed/denied server features
|
|
83
|
+
*
|
|
84
|
+
* @param features
|
|
85
|
+
*/
|
|
86
|
+
function validateFeatures(features: string[]): string[] {
|
|
87
|
+
const validator = (fullName: string) => {
|
|
88
|
+
const errMsg = `The full feature name must include both the destination automation name or the ` +
|
|
89
|
+
`'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
|
|
90
|
+
`the feature name split by a colon. Got '${fullName}' instead`;
|
|
91
|
+
|
|
92
|
+
const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
|
|
93
|
+
if (separatorPos < 0) {
|
|
94
|
+
throw new Error(errMsg);
|
|
95
|
+
}
|
|
96
|
+
const [automationName, featureName] = [
|
|
97
|
+
fullName.substring(0, separatorPos),
|
|
98
|
+
fullName.substring(separatorPos + 1)
|
|
99
|
+
];
|
|
100
|
+
if (!automationName || !featureName) {
|
|
101
|
+
throw new Error(errMsg);
|
|
102
|
+
}
|
|
103
|
+
return fullName;
|
|
104
|
+
};
|
|
105
|
+
return features.map(validator);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Filters the list of insecure features to only those that are
|
|
110
|
+
* applicable to the given driver name.
|
|
111
|
+
* Assumes that all feature names have already been validated
|
|
112
|
+
*
|
|
113
|
+
* @param features
|
|
114
|
+
* @param driverName
|
|
115
|
+
*/
|
|
116
|
+
function filterInsecureFeatures(
|
|
117
|
+
features: string[],
|
|
118
|
+
driverName: string = ALL_DRIVERS_MATCH
|
|
119
|
+
): string[] {
|
|
120
|
+
const filterFn = (fullName: string) => {
|
|
121
|
+
const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
|
|
122
|
+
if (separatorPos <= 0) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const automationName = fullName.substring(0, separatorPos);
|
|
126
|
+
return [driverName, ALL_DRIVERS_MATCH].includes(automationName);
|
|
127
|
+
};
|
|
128
|
+
return features.filter(filterFn);
|
|
129
|
+
}
|
package/lib/main.js
CHANGED
|
@@ -177,7 +177,7 @@ function determineAppiumHomeSource(appiumHomeFromArgs) {
|
|
|
177
177
|
*
|
|
178
178
|
* @template {CliCommand} [Cmd=ServerCommand]
|
|
179
179
|
* @template {CliExtensionSubcommand|void} [SubCmd=void]
|
|
180
|
-
* @param {Args<Cmd, SubCmd>} [args] - Partial args (
|
|
180
|
+
* @param {Args<Cmd, SubCmd>} [args] - Partial args (programmatic usage only)
|
|
181
181
|
* @returns {Promise<InitResult<Cmd>>}
|
|
182
182
|
* @example
|
|
183
183
|
* import {init, getSchema} from 'appium';
|
|
@@ -375,6 +375,9 @@ async function main(args) {
|
|
|
375
375
|
|
|
376
376
|
await logStartupInfo(parsedArgs);
|
|
377
377
|
|
|
378
|
+
// handle the insecure feature configuration since some features may apply globally
|
|
379
|
+
appiumDriver.configureGlobalFeatures();
|
|
380
|
+
|
|
378
381
|
const appiumHomeSourceName = determineAppiumHomeSource(args?.appiumHome);
|
|
379
382
|
logger.debug(`The ${appiumHomeSourceName}: ${appiumHome}`);
|
|
380
383
|
|
package/lib/schema/cli-args.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ArgumentTypeError} from 'argparse';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {formatErrors
|
|
3
|
+
import {formatErrors} from '../config-file';
|
|
4
4
|
import {flattenSchema, validate} from './schema';
|
|
5
5
|
import {transformers, parseCsvLine} from './cli-transformers';
|
|
6
6
|
|
|
@@ -225,7 +225,7 @@ function subSchemaToArgDef(subSchema, argSpec) {
|
|
|
225
225
|
* ArgumentDefinitions for handoff to `argparse`.
|
|
226
226
|
*
|
|
227
227
|
* @throws If schema has not been added to ajv (via `finalizeSchema()`)
|
|
228
|
-
* @returns {import('../cli/args').ArgumentDefinitions} A map of
|
|
228
|
+
* @returns {import('../cli/args').ArgumentDefinitions} A map of arrays of
|
|
229
229
|
* aliases to `argparse` arguments; empty if no schema found
|
|
230
230
|
*/
|
|
231
231
|
export function toParserArgs() {
|
package/lib/schema/schema.js
CHANGED
|
@@ -421,7 +421,7 @@ class AppiumSchema {
|
|
|
421
421
|
* name. Used when translating to `argparse` options or getting the list of
|
|
422
422
|
* default values (see {@link AppiumSchema.getDefaults}) for CLI or otherwise.
|
|
423
423
|
*
|
|
424
|
-
* The return value is an intermediate
|
|
424
|
+
* The return value is an intermediate representation used by `cli-args`
|
|
425
425
|
* module's `toParserArgs`, which converts the finalized schema to parameters
|
|
426
426
|
* used by `argparse`.
|
|
427
427
|
* @throws If {@link AppiumSchema.finalize} has not been called yet.
|
package/lib/utils.js
CHANGED
|
@@ -2,9 +2,9 @@ import _ from 'lodash';
|
|
|
2
2
|
import logger from './logger';
|
|
3
3
|
import {
|
|
4
4
|
processCapabilities,
|
|
5
|
-
PROTOCOLS,
|
|
6
5
|
STANDARD_CAPS,
|
|
7
6
|
errors,
|
|
7
|
+
isW3cCaps,
|
|
8
8
|
} from '@appium/base-driver';
|
|
9
9
|
import {inspect as dump} from 'util';
|
|
10
10
|
import {node, fs} from '@appium/support';
|
|
@@ -17,8 +17,6 @@ const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLo
|
|
|
17
17
|
export const V4_BROADCAST_IP = '0.0.0.0';
|
|
18
18
|
export const V6_BROADCAST_IP = '::';
|
|
19
19
|
export const npmPackage = fs.readPackageJsonFrom(__dirname);
|
|
20
|
-
const ALL_DRIVERS_MATCH = '*';
|
|
21
|
-
const FEATURE_NAME_SEPARATOR = ':';
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
22
|
*
|
|
@@ -61,124 +59,89 @@ export const inspect = _.flow(
|
|
|
61
59
|
* into caps that can be used by the inner drivers.
|
|
62
60
|
*
|
|
63
61
|
* @template {Constraints} C
|
|
64
|
-
* @template [J=any]
|
|
65
|
-
* @param {J} jsonwpCapabilities
|
|
66
62
|
* @param {W3CCapabilities<C>} w3cCapabilities
|
|
67
63
|
* @param {C} constraints
|
|
68
64
|
* @param {NSCapabilities<C>} [defaultCapabilities]
|
|
69
|
-
* @returns {ParsedDriverCaps<C
|
|
65
|
+
* @returns {ParsedDriverCaps<C>|InvalidCaps<C>}
|
|
70
66
|
*/
|
|
71
67
|
export function parseCapsForInnerDriver(
|
|
72
|
-
jsonwpCapabilities,
|
|
73
68
|
w3cCapabilities,
|
|
74
69
|
constraints = /** @type {C} */ ({}),
|
|
75
70
|
defaultCapabilities = {}
|
|
76
71
|
) {
|
|
77
|
-
|
|
78
|
-
const hasW3CCaps =
|
|
79
|
-
_.isPlainObject(w3cCapabilities) &&
|
|
80
|
-
(_.has(w3cCapabilities, 'alwaysMatch') || _.has(w3cCapabilities, 'firstMatch'));
|
|
81
|
-
const hasJSONWPCaps = _.isPlainObject(jsonwpCapabilities);
|
|
82
|
-
let desiredCaps = /** @type {ParsedDriverCaps<C>['desiredCaps']} */ ({});
|
|
83
|
-
/** @type {ParsedDriverCaps<C>['processedW3CCapabilities']} */
|
|
84
|
-
let processedW3CCapabilities;
|
|
85
|
-
/** @type {ParsedDriverCaps<C>['processedJsonwpCapabilities']} */
|
|
86
|
-
let processedJsonwpCapabilities;
|
|
87
|
-
|
|
88
|
-
if (!hasW3CCaps) {
|
|
72
|
+
if (!isW3cCaps(w3cCapabilities)) {
|
|
89
73
|
return /** @type {InvalidCaps<C>} */ ({
|
|
90
|
-
protocol: PROTOCOLS.W3C,
|
|
91
74
|
error: makeNonW3cCapsError(),
|
|
92
75
|
});
|
|
93
76
|
}
|
|
94
77
|
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
let desiredCaps = /** @type {ParsedDriverCaps<C>['desiredCaps']} */ ({});
|
|
79
|
+
/** @type {ParsedDriverCaps<C>['processedW3CCapabilities'] | undefined} */
|
|
80
|
+
let processedW3CCapabilities;
|
|
97
81
|
|
|
98
82
|
// Make sure we don't mutate the original arguments
|
|
99
|
-
jsonwpCapabilities = _.cloneDeep(jsonwpCapabilities);
|
|
100
83
|
w3cCapabilities = _.cloneDeep(w3cCapabilities);
|
|
101
84
|
defaultCapabilities = _.cloneDeep(defaultCapabilities);
|
|
102
85
|
|
|
103
86
|
if (!_.isEmpty(defaultCapabilities)) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
// Check if the key is already present in alwaysMatch entries
|
|
118
|
-
isCapAlreadySet =
|
|
119
|
-
isCapAlreadySet ||
|
|
120
|
-
(_.isPlainObject(w3cCapabilities.alwaysMatch) &&
|
|
121
|
-
_.has(
|
|
122
|
-
removeAppiumPrefixes(w3cCapabilities.alwaysMatch),
|
|
123
|
-
removeAppiumPrefix(defaultCapKey)
|
|
124
|
-
));
|
|
125
|
-
if (isCapAlreadySet) {
|
|
126
|
-
// Skip if the key is already present in the provided caps
|
|
127
|
-
continue;
|
|
87
|
+
for (const [defaultCapKey, defaultCapValue] of _.toPairs(defaultCapabilities)) {
|
|
88
|
+
let isCapAlreadySet = false;
|
|
89
|
+
// Check if the key is already present in firstMatch entries
|
|
90
|
+
for (const firstMatchEntry of w3cCapabilities.firstMatch ?? []) {
|
|
91
|
+
if (
|
|
92
|
+
_.isPlainObject(firstMatchEntry) &&
|
|
93
|
+
_.has(removeAppiumPrefixes(firstMatchEntry), removeAppiumPrefix(defaultCapKey))
|
|
94
|
+
) {
|
|
95
|
+
isCapAlreadySet = true;
|
|
96
|
+
break;
|
|
128
97
|
}
|
|
98
|
+
}
|
|
99
|
+
// Check if the key is already present in alwaysMatch entries
|
|
100
|
+
isCapAlreadySet =
|
|
101
|
+
isCapAlreadySet ||
|
|
102
|
+
(_.isPlainObject(w3cCapabilities.alwaysMatch) &&
|
|
103
|
+
_.has(
|
|
104
|
+
removeAppiumPrefixes(w3cCapabilities.alwaysMatch),
|
|
105
|
+
removeAppiumPrefix(defaultCapKey)
|
|
106
|
+
));
|
|
107
|
+
if (isCapAlreadySet) {
|
|
108
|
+
// Skip if the key is already present in the provided caps
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
129
111
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
112
|
+
// Only add the default capability if it is not overridden
|
|
113
|
+
if (_.isEmpty(w3cCapabilities.firstMatch)) {
|
|
114
|
+
w3cCapabilities.firstMatch = /** @type {W3CCapabilities<C>['firstMatch']} */ ([
|
|
115
|
+
{[defaultCapKey]: defaultCapValue},
|
|
116
|
+
]);
|
|
117
|
+
} else {
|
|
118
|
+
w3cCapabilities.firstMatch[0][defaultCapKey] = defaultCapValue;
|
|
138
119
|
}
|
|
139
120
|
}
|
|
140
|
-
if (hasJSONWPCaps) {
|
|
141
|
-
jsonwpCapabilities = {
|
|
142
|
-
...removeAppiumPrefixes(defaultCapabilities),
|
|
143
|
-
...jsonwpCapabilities,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
121
|
}
|
|
147
122
|
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
123
|
+
// Call the process capabilities algorithm to find matching caps on the W3C
|
|
124
|
+
// (see: https://github.com/jlipps/simple-wd-spec#processing-capabilities)
|
|
125
|
+
try {
|
|
126
|
+
desiredCaps = processCapabilities(w3cCapabilities, constraints, true);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
logger.info(`Could not parse W3C capabilities: ${error.message}`);
|
|
129
|
+
return /** @type {InvalidCaps<C>} */ ({
|
|
130
|
+
desiredCaps,
|
|
131
|
+
processedW3CCapabilities,
|
|
132
|
+
error,
|
|
133
|
+
});
|
|
151
134
|
}
|
|
152
135
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
desiredCaps = processCapabilities(w3cCapabilities, constraints, true);
|
|
159
|
-
} catch (error) {
|
|
160
|
-
logger.info(`Could not parse W3C capabilities: ${error.message}`);
|
|
161
|
-
return /** @type {InvalidCaps<C,J>} */ ({
|
|
162
|
-
desiredCaps,
|
|
163
|
-
processedJsonwpCapabilities,
|
|
164
|
-
processedW3CCapabilities,
|
|
165
|
-
protocol,
|
|
166
|
-
error,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Create a new w3c capabilities payload that contains only the matching caps in `alwaysMatch`
|
|
171
|
-
processedW3CCapabilities = {
|
|
172
|
-
alwaysMatch: {...insertAppiumPrefixes(desiredCaps)},
|
|
173
|
-
firstMatch: [{}],
|
|
174
|
-
};
|
|
175
|
-
}
|
|
136
|
+
// Create a new w3c capabilities payload that contains only the matching caps in `alwaysMatch`
|
|
137
|
+
processedW3CCapabilities = {
|
|
138
|
+
alwaysMatch: {...insertAppiumPrefixes(desiredCaps)},
|
|
139
|
+
firstMatch: [{}],
|
|
140
|
+
};
|
|
176
141
|
|
|
177
|
-
return /** @type {ParsedDriverCaps<C
|
|
142
|
+
return /** @type {ParsedDriverCaps<C>} */ ({
|
|
178
143
|
desiredCaps,
|
|
179
|
-
processedJsonwpCapabilities,
|
|
180
144
|
processedW3CCapabilities,
|
|
181
|
-
protocol,
|
|
182
145
|
});
|
|
183
146
|
}
|
|
184
147
|
|
|
@@ -381,7 +344,7 @@ export function isPluginCommandArgs(args) {
|
|
|
381
344
|
*
|
|
382
345
|
* @param {4|6|null} family Either 4 to include ipv4 addresses only,
|
|
383
346
|
* 6 to include ipv6 addresses only, or null to include all of them
|
|
384
|
-
* @returns {os.NetworkInterfaceInfo[]} The list of matched
|
|
347
|
+
* @returns {os.NetworkInterfaceInfo[]} The list of matched interfaces
|
|
385
348
|
*/
|
|
386
349
|
export function fetchInterfaces (family = null) {
|
|
387
350
|
let familyValue = null;
|
|
@@ -416,8 +379,7 @@ export function adler32(str, seed = null) {
|
|
|
416
379
|
c = str.charCodeAt(i++);
|
|
417
380
|
if (c < 0x80) {
|
|
418
381
|
a += c;
|
|
419
|
-
}
|
|
420
|
-
else if (c < 0x800) {
|
|
382
|
+
} else if (c < 0x800) {
|
|
421
383
|
a += 192 | ((c >> 6) & 31);
|
|
422
384
|
b += a;
|
|
423
385
|
--M;
|
|
@@ -463,37 +425,6 @@ export function isBroadcastIp(address) {
|
|
|
463
425
|
return [V4_BROADCAST_IP, V6_BROADCAST_IP, `[${V6_BROADCAST_IP}]`].includes(address);
|
|
464
426
|
}
|
|
465
427
|
|
|
466
|
-
/**
|
|
467
|
-
* Validates the list of allowed/denied server features
|
|
468
|
-
*
|
|
469
|
-
* @param {string[]} features
|
|
470
|
-
* @returns {string[]}
|
|
471
|
-
*/
|
|
472
|
-
export function validateFeatures(features) {
|
|
473
|
-
const validator = (/** @type {string} */ fullName) => {
|
|
474
|
-
const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
|
|
475
|
-
// TODO: This is for the backward compatibility with Appium2
|
|
476
|
-
// TODO: In Appium3 the separator will be mandatory
|
|
477
|
-
if (separatorPos < 0) {
|
|
478
|
-
return `${ALL_DRIVERS_MATCH}${FEATURE_NAME_SEPARATOR}${fullName}`;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
const [automationName, featureName] = [
|
|
482
|
-
fullName.substring(0, separatorPos),
|
|
483
|
-
fullName.substring(separatorPos + 1)
|
|
484
|
-
];
|
|
485
|
-
if (!automationName || !featureName) {
|
|
486
|
-
throw new Error(
|
|
487
|
-
`The full feature name must include both the destination automation name or the ` +
|
|
488
|
-
`'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
|
|
489
|
-
`the feature name split by a colon, got '${fullName}' instead`
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
return fullName;
|
|
493
|
-
};
|
|
494
|
-
return features.map(validator);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
428
|
/**
|
|
498
429
|
* @typedef {import('@appium/types').StringRecord} StringRecord
|
|
499
430
|
* @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
|
|
@@ -501,23 +432,17 @@ export function validateFeatures(features) {
|
|
|
501
432
|
|
|
502
433
|
/**
|
|
503
434
|
* @template {Constraints} [C=BaseDriverCapConstraints]
|
|
504
|
-
* @template [J=any]
|
|
505
435
|
* @typedef ParsedDriverCaps
|
|
506
436
|
* @property {Capabilities<C>} desiredCaps
|
|
507
|
-
* @property {
|
|
508
|
-
* @property {J} [processedJsonwpCapabilities]
|
|
509
|
-
* @property {W3CCapabilities<C>} [processedW3CCapabilities]
|
|
437
|
+
* @property {W3CCapabilities<C>} processedW3CCapabilities
|
|
510
438
|
*/
|
|
511
439
|
|
|
512
440
|
/**
|
|
513
441
|
* @todo protocol is more specific
|
|
514
442
|
* @template {Constraints} [C=BaseDriverCapConstraints]
|
|
515
|
-
* @template [J=any]
|
|
516
443
|
* @typedef InvalidCaps
|
|
517
444
|
* @property {Error} error
|
|
518
|
-
* @property {string} protocol
|
|
519
445
|
* @property {Capabilities<C>} [desiredCaps]
|
|
520
|
-
* @property {J} [processedJsonwpCapabilities]
|
|
521
446
|
* @property {W3CCapabilities<C>} [processedW3CCapabilities]
|
|
522
447
|
*/
|
|
523
448
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-rc.1",
|
|
4
4
|
"description": "Automation for Apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -55,25 +55,25 @@
|
|
|
55
55
|
"postinstall": "node ./scripts/autoinstall-extensions.js",
|
|
56
56
|
"publish:docs": "cross-env APPIUM_DOCS_PUBLISH=1 npm run build:docs",
|
|
57
57
|
"test": "npm run test:unit",
|
|
58
|
-
"test:e2e": "mocha --timeout 1m --slow 30s \"./test/e2e/**/*.spec.js\"",
|
|
58
|
+
"test:e2e": "mocha --exit --timeout 1m --slow 30s \"./test/e2e/**/*.spec.js\"",
|
|
59
59
|
"test:smoke": "cross-env APPIUM_HOME=./local_appium_home node ./index.js driver install uiautomator2 && cross-env APPIUM_HOME=./local_appium_home node ./index.js driver list",
|
|
60
60
|
"test:unit": "mocha \"./test/unit/**/*.spec.js\""
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@appium/base-driver": "^10.0.0-beta.
|
|
64
|
-
"@appium/base-plugin": "^3.0.0-beta.
|
|
65
|
-
"@appium/docutils": "^1.0
|
|
66
|
-
"@appium/logger": "^1.
|
|
63
|
+
"@appium/base-driver": "^10.0.0-beta.2",
|
|
64
|
+
"@appium/base-plugin": "^3.0.0-beta.2",
|
|
65
|
+
"@appium/docutils": "^1.1.0",
|
|
66
|
+
"@appium/logger": "^1.7.0",
|
|
67
67
|
"@appium/schema": "^0.8.1",
|
|
68
|
-
"@appium/support": "^6.0
|
|
69
|
-
"@appium/types": "^0.
|
|
68
|
+
"@appium/support": "^6.1.0",
|
|
69
|
+
"@appium/types": "^0.26.0",
|
|
70
70
|
"@sidvind/better-ajv-errors": "3.0.1",
|
|
71
71
|
"ajv": "8.17.1",
|
|
72
72
|
"ajv-formats": "3.0.1",
|
|
73
73
|
"argparse": "2.0.1",
|
|
74
74
|
"async-lock": "1.4.1",
|
|
75
75
|
"asyncbox": "3.0.0",
|
|
76
|
-
"axios": "1.
|
|
76
|
+
"axios": "1.9.0",
|
|
77
77
|
"bluebird": "3.7.2",
|
|
78
78
|
"lilconfig": "3.1.3",
|
|
79
79
|
"lodash": "4.17.21",
|
|
@@ -81,22 +81,22 @@
|
|
|
81
81
|
"ora": "5.4.1",
|
|
82
82
|
"package-changed": "3.0.0",
|
|
83
83
|
"resolve-from": "5.0.0",
|
|
84
|
-
"semver": "7.7.
|
|
84
|
+
"semver": "7.7.2",
|
|
85
85
|
"source-map-support": "0.5.21",
|
|
86
|
-
"teen_process": "2.3.
|
|
87
|
-
"type-fest": "4.
|
|
86
|
+
"teen_process": "2.3.2",
|
|
87
|
+
"type-fest": "4.41.0",
|
|
88
88
|
"winston": "3.17.0",
|
|
89
89
|
"wrap-ansi": "7.0.0",
|
|
90
|
-
"ws": "8.18.
|
|
91
|
-
"yaml": "2.
|
|
90
|
+
"ws": "8.18.2",
|
|
91
|
+
"yaml": "2.8.0"
|
|
92
92
|
},
|
|
93
93
|
"engines": {
|
|
94
|
-
"node": "^20.
|
|
94
|
+
"node": "^20.19.0 || >=22.12.0",
|
|
95
95
|
"npm": ">=10"
|
|
96
96
|
},
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public",
|
|
99
99
|
"tag": "beta"
|
|
100
100
|
},
|
|
101
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "92680d9b4a95da18a812187773240a51b52f5f29"
|
|
102
102
|
}
|