appium 3.4.2 → 3.5.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 +3 -0
- package/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +73 -51
- package/build/lib/appium.js.map +1 -1
- package/build/lib/bidi-commands.d.ts.map +1 -1
- package/build/lib/bidi-commands.js +36 -31
- package/build/lib/bidi-commands.js.map +1 -1
- package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -1
- package/build/lib/bootstrap/appium-initializer.js +13 -13
- package/build/lib/bootstrap/appium-initializer.js.map +1 -1
- package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -1
- package/build/lib/bootstrap/appium-main-runner.js +2 -2
- package/build/lib/bootstrap/appium-main-runner.js.map +1 -1
- package/build/lib/bootstrap/config-file.d.ts.map +1 -1
- package/build/lib/bootstrap/config-file.js +11 -11
- package/build/lib/bootstrap/config-file.js.map +1 -1
- package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -1
- package/build/lib/bootstrap/grid-v3-register.js +9 -6
- package/build/lib/bootstrap/grid-v3-register.js.map +1 -1
- package/build/lib/bootstrap/main-helpers.d.ts +1 -1
- package/build/lib/bootstrap/main-helpers.d.ts.map +1 -1
- package/build/lib/bootstrap/main-helpers.js +19 -20
- package/build/lib/bootstrap/main-helpers.js.map +1 -1
- package/build/lib/bootstrap/node-helpers.d.ts +1 -1
- package/build/lib/bootstrap/node-helpers.d.ts.map +1 -1
- package/build/lib/bootstrap/node-helpers.js +8 -16
- package/build/lib/bootstrap/node-helpers.js.map +1 -1
- package/build/lib/bootstrap/startup-config.d.ts.map +1 -1
- package/build/lib/bootstrap/startup-config.js +32 -30
- package/build/lib/bootstrap/startup-config.js.map +1 -1
- package/build/lib/cli/args.d.ts +3 -2
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +2 -5
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.d.ts +1 -2
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +7 -8
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +2 -2
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +105 -71
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js.map +1 -1
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +21 -14
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.d.ts +1 -1
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +5 -5
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/setup-command.d.ts +1 -1
- package/build/lib/cli/setup-command.d.ts.map +1 -1
- package/build/lib/cli/setup-command.js +14 -19
- package/build/lib/cli/setup-command.js.map +1 -1
- package/build/lib/cli/utils.d.ts.map +1 -1
- package/build/lib/cli/utils.js +3 -2
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/doctor/doctor.d.ts +0 -1
- package/build/lib/doctor/doctor.d.ts.map +1 -1
- package/build/lib/doctor/doctor.js +12 -17
- package/build/lib/doctor/doctor.js.map +1 -1
- package/build/lib/extension/driver-config.d.ts.map +1 -1
- package/build/lib/extension/driver-config.js +11 -12
- package/build/lib/extension/driver-config.js.map +1 -1
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +30 -30
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/extension/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +28 -41
- package/build/lib/extension/index.js.map +1 -1
- package/build/lib/extension/manifest.d.ts +3 -2
- package/build/lib/extension/manifest.d.ts.map +1 -1
- package/build/lib/extension/manifest.js +20 -24
- package/build/lib/extension/manifest.js.map +1 -1
- package/build/lib/extension/plugin-config.d.ts.map +1 -1
- package/build/lib/extension/plugin-config.js +7 -9
- package/build/lib/extension/plugin-config.js.map +1 -1
- package/build/lib/helpers/build.d.ts +0 -1
- package/build/lib/helpers/build.d.ts.map +1 -1
- package/build/lib/helpers/build.js +2 -4
- package/build/lib/helpers/build.js.map +1 -1
- package/build/lib/helpers/capability.d.ts.map +1 -1
- package/build/lib/helpers/capability.js +27 -22
- package/build/lib/helpers/capability.js.map +1 -1
- package/build/lib/helpers/network.d.ts.map +1 -1
- package/build/lib/helpers/network.js +4 -3
- package/build/lib/helpers/network.js.map +1 -1
- package/build/lib/insecure-features.d.ts.map +1 -1
- package/build/lib/insecure-features.js +9 -13
- package/build/lib/insecure-features.js.map +1 -1
- package/build/lib/inspector-commands.d.ts.map +1 -1
- package/build/lib/inspector-commands.js +29 -28
- package/build/lib/inspector-commands.js.map +1 -1
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +8 -7
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/schema/arg-spec.d.ts.map +1 -1
- package/build/lib/schema/arg-spec.js +5 -8
- package/build/lib/schema/arg-spec.js.map +1 -1
- package/build/lib/schema/cli-args.d.ts.map +1 -1
- package/build/lib/schema/cli-args.js +20 -19
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/cli-transformers.d.ts.map +1 -1
- package/build/lib/schema/cli-transformers.js.map +1 -1
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +28 -21
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils/hash.d.ts +5 -0
- package/build/lib/utils/hash.d.ts.map +1 -0
- package/build/lib/{utils.js → utils/hash.js} +3 -21
- package/build/lib/utils/hash.js.map +1 -0
- package/build/lib/utils/index.d.ts +8 -0
- package/build/lib/utils/index.d.ts.map +1 -0
- package/build/lib/utils/index.js +31 -0
- package/build/lib/utils/index.js.map +1 -0
- package/build/lib/utils/is-package-changed.d.ts +16 -0
- package/build/lib/utils/is-package-changed.d.ts.map +1 -0
- package/build/lib/utils/is-package-changed.js +62 -0
- package/build/lib/utils/is-package-changed.js.map +1 -0
- package/build/lib/utils/object.d.ts +120 -0
- package/build/lib/utils/object.d.ts.map +1 -0
- package/build/lib/utils/object.js +288 -0
- package/build/lib/utils/object.js.map +1 -0
- package/build/lib/{extension → utils}/package-changed.d.ts +0 -1
- package/build/lib/utils/package-changed.d.ts.map +1 -0
- package/build/lib/{extension → utils}/package-changed.js +3 -4
- package/build/lib/utils/package-changed.js.map +1 -0
- package/build/lib/utils/package-json.d.ts +9 -0
- package/build/lib/utils/package-json.d.ts.map +1 -0
- package/build/lib/utils/package-json.js +32 -0
- package/build/lib/utils/package-json.js.map +1 -0
- package/build/lib/utils/resolve-from.d.ts +11 -0
- package/build/lib/utils/resolve-from.d.ts.map +1 -0
- package/build/lib/utils/resolve-from.js +41 -0
- package/build/lib/utils/resolve-from.js.map +1 -0
- package/build/types/cli.d.ts.map +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/manifest/base.d.ts.map +1 -1
- package/build/types/manifest/v3.d.ts.map +1 -1
- package/build/types/manifest/v4.d.ts.map +1 -1
- package/lib/appium.ts +96 -61
- package/lib/bidi-commands.ts +107 -61
- package/lib/bootstrap/appium-initializer.ts +27 -19
- package/lib/bootstrap/appium-main-runner.ts +8 -4
- package/lib/bootstrap/config-file.ts +33 -16
- package/lib/bootstrap/grid-v3-register.ts +26 -19
- package/lib/bootstrap/main-helpers.ts +25 -19
- package/lib/bootstrap/node-helpers.ts +20 -24
- package/lib/bootstrap/startup-config.ts +42 -39
- package/lib/cli/args.ts +3 -4
- package/lib/cli/driver-command.ts +19 -13
- package/lib/cli/extension-command.ts +214 -149
- package/lib/cli/extension.ts +4 -6
- package/lib/cli/parser.ts +32 -30
- package/lib/cli/plugin-command.ts +20 -9
- package/lib/cli/setup-command.ts +54 -39
- package/lib/cli/utils.ts +4 -3
- package/lib/doctor/doctor.ts +15 -17
- package/lib/extension/driver-config.ts +22 -17
- package/lib/extension/extension-config.ts +76 -69
- package/lib/extension/index.ts +60 -51
- package/lib/extension/manifest.ts +35 -33
- package/lib/extension/plugin-config.ts +15 -10
- package/lib/helpers/build.ts +6 -5
- package/lib/helpers/capability.ts +40 -35
- package/lib/helpers/network.ts +6 -5
- package/lib/insecure-features.ts +16 -14
- package/lib/inspector-commands.ts +72 -40
- package/lib/logsink.ts +22 -26
- package/lib/schema/arg-spec.ts +9 -8
- package/lib/schema/cli-args-guards.ts +4 -4
- package/lib/schema/cli-args.ts +25 -21
- package/lib/schema/cli-transformers.ts +6 -2
- package/lib/schema/format-errors.ts +1 -1
- package/lib/schema/schema.ts +52 -38
- package/lib/{utils.ts → utils/hash.ts} +2 -19
- package/lib/utils/index.ts +23 -0
- package/lib/utils/is-package-changed.ts +78 -0
- package/lib/utils/object.ts +312 -0
- package/lib/{extension → utils}/package-changed.ts +6 -7
- package/lib/utils/package-json.ts +36 -0
- package/lib/utils/resolve-from.ts +40 -0
- package/package.json +16 -19
- package/scripts/autoinstall-extensions.js +8 -13
- package/tsconfig.json +8 -2
- package/types/cli.ts +18 -18
- package/types/index.ts +2 -2
- package/types/manifest/base.ts +2 -2
- package/types/manifest/v3.ts +2 -2
- package/types/manifest/v4.ts +2 -2
- package/build/lib/extension/package-changed.d.ts.map +0 -1
- package/build/lib/extension/package-changed.js.map +0 -1
- package/build/lib/utils.d.ts +0 -13
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js.map +0 -1
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {env, fs} from '@appium/support';
|
|
3
|
-
import _ from 'lodash';
|
|
1
|
+
import {env, fs, util} from '@appium/support';
|
|
4
2
|
import path from 'node:path';
|
|
5
3
|
import * as YAML from 'yaml';
|
|
6
4
|
import type {DriverType, ExtensionType, PluginType} from '@appium/types';
|
|
7
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
ExtManifest,
|
|
7
|
+
ExtPackageJson,
|
|
8
|
+
ExtRecord,
|
|
9
|
+
InternalMetadata,
|
|
10
|
+
ManifestData,
|
|
11
|
+
} from 'appium/types';
|
|
8
12
|
import {CURRENT_SCHEMA_REV, DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
|
|
9
13
|
import {INSTALL_TYPE_DEV, INSTALL_TYPE_NPM} from './extension-config';
|
|
10
|
-
import {packageDidChange} from '
|
|
14
|
+
import {packageDidChange} from '../utils';
|
|
11
15
|
import {migrate} from './manifest-migrations';
|
|
12
16
|
|
|
13
17
|
const CONFIG_DATA_DRIVER_KEY = `${DRIVER_TYPE}s` as const;
|
|
@@ -30,7 +34,7 @@ export class Manifest {
|
|
|
30
34
|
*
|
|
31
35
|
* @param appiumHome - `APPIUM_HOME` path used as the cache key
|
|
32
36
|
*/
|
|
33
|
-
static getInstance =
|
|
37
|
+
static getInstance = util.memoize((appiumHome: string): Manifest => new Manifest(appiumHome));
|
|
34
38
|
|
|
35
39
|
#data!: ManifestData;
|
|
36
40
|
readonly #appiumHome: string;
|
|
@@ -40,7 +44,7 @@ export class Manifest {
|
|
|
40
44
|
|
|
41
45
|
private constructor(appiumHome: string) {
|
|
42
46
|
this.#appiumHome = appiumHome;
|
|
43
|
-
this.#data =
|
|
47
|
+
this.#data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/** `APPIUM_HOME` directory this manifest is tied to. */
|
|
@@ -111,7 +115,7 @@ export class Manifest {
|
|
|
111
115
|
data = YAML.parse(yaml) as ManifestData;
|
|
112
116
|
} catch (err: any) {
|
|
113
117
|
if (err.code === 'ENOENT') {
|
|
114
|
-
data =
|
|
118
|
+
data = structuredClone(INITIAL_MANIFEST_DATA) as ManifestData;
|
|
115
119
|
shouldWrite = true;
|
|
116
120
|
} else {
|
|
117
121
|
throw new Error(
|
|
@@ -119,7 +123,7 @@ export class Manifest {
|
|
|
119
123
|
`cache file (${manifestPathResolved}). It may be invalid YAML. Specific error: ${
|
|
120
124
|
err.message
|
|
121
125
|
}`,
|
|
122
|
-
{cause: err}
|
|
126
|
+
{cause: err},
|
|
123
127
|
);
|
|
124
128
|
}
|
|
125
129
|
}
|
|
@@ -166,9 +170,9 @@ export class Manifest {
|
|
|
166
170
|
} catch (err: any) {
|
|
167
171
|
throw new Error(
|
|
168
172
|
`Appium could not create the directory for the manifest file: ${path.dirname(
|
|
169
|
-
manifestPathResolved
|
|
173
|
+
manifestPathResolved,
|
|
170
174
|
)}. Original error: ${err.message}`,
|
|
171
|
-
{cause: err}
|
|
175
|
+
{cause: err},
|
|
172
176
|
);
|
|
173
177
|
}
|
|
174
178
|
try {
|
|
@@ -179,7 +183,7 @@ export class Manifest {
|
|
|
179
183
|
`Appium could not write to manifest at ${manifestPathResolved} using APPIUM_HOME ${
|
|
180
184
|
this.#appiumHome
|
|
181
185
|
}. Please ensure it is writable. Original error: ${err.message}`,
|
|
182
|
-
{cause: err}
|
|
186
|
+
{cause: err},
|
|
183
187
|
);
|
|
184
188
|
}
|
|
185
189
|
})();
|
|
@@ -212,9 +216,7 @@ export class Manifest {
|
|
|
212
216
|
}
|
|
213
217
|
};
|
|
214
218
|
|
|
215
|
-
const queue: Promise<void>[] = [
|
|
216
|
-
onMatch(path.join(this.#appiumHome, 'package.json'), true),
|
|
217
|
-
];
|
|
219
|
+
const queue: Promise<void>[] = [onMatch(path.join(this.#appiumHome, 'package.json'), true)];
|
|
218
220
|
|
|
219
221
|
const filepaths = await fs.glob('node_modules/{*,@*/*}/package.json', {
|
|
220
222
|
cwd: this.#appiumHome,
|
|
@@ -224,7 +226,7 @@ export class Manifest {
|
|
|
224
226
|
queue.push(onMatch(filepath));
|
|
225
227
|
}
|
|
226
228
|
|
|
227
|
-
await
|
|
229
|
+
await Promise.all(queue);
|
|
228
230
|
|
|
229
231
|
return didChange;
|
|
230
232
|
}
|
|
@@ -241,7 +243,7 @@ export class Manifest {
|
|
|
241
243
|
addExtensionFromPackage(
|
|
242
244
|
pkgJson: ExtPackageJson<ExtensionType>,
|
|
243
245
|
pkgPath: string,
|
|
244
|
-
installType: typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_DEV = INSTALL_TYPE_NPM
|
|
246
|
+
installType: typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_DEV = INSTALL_TYPE_NPM,
|
|
245
247
|
): boolean {
|
|
246
248
|
const extensionPath = path.dirname(pkgPath);
|
|
247
249
|
|
|
@@ -255,31 +257,31 @@ export class Manifest {
|
|
|
255
257
|
};
|
|
256
258
|
|
|
257
259
|
if (isDriver(pkgJson)) {
|
|
258
|
-
const driverName = pkgJson.appium
|
|
260
|
+
const {driverName, ...appiumDriverMeta} = pkgJson.appium;
|
|
259
261
|
const value = {
|
|
260
|
-
...
|
|
262
|
+
...appiumDriverMeta,
|
|
261
263
|
...internal,
|
|
262
264
|
};
|
|
263
|
-
if (!
|
|
265
|
+
if (!util.isEqual(value, this.#data.drivers[driverName])) {
|
|
264
266
|
this.setExtension(DRIVER_TYPE, driverName, value);
|
|
265
267
|
return true;
|
|
266
268
|
}
|
|
267
269
|
return false;
|
|
268
270
|
}
|
|
269
271
|
if (isPlugin(pkgJson)) {
|
|
270
|
-
const pluginName = pkgJson.appium
|
|
272
|
+
const {pluginName, ...appiumPluginMeta} = pkgJson.appium;
|
|
271
273
|
const value = {
|
|
272
|
-
...
|
|
274
|
+
...appiumPluginMeta,
|
|
273
275
|
...internal,
|
|
274
276
|
};
|
|
275
|
-
if (!
|
|
277
|
+
if (!util.isEqual(value, this.#data.plugins[pluginName])) {
|
|
276
278
|
this.setExtension(PLUGIN_TYPE, pluginName, value);
|
|
277
279
|
return true;
|
|
278
280
|
}
|
|
279
281
|
return false;
|
|
280
282
|
}
|
|
281
283
|
throw new TypeError(
|
|
282
|
-
`The extension in ${extensionPath} is neither a valid ${DRIVER_TYPE} nor a valid ${PLUGIN_TYPE}
|
|
284
|
+
`The extension in ${extensionPath} is neither a valid ${DRIVER_TYPE} nor a valid ${PLUGIN_TYPE}.`,
|
|
283
285
|
);
|
|
284
286
|
}
|
|
285
287
|
|
|
@@ -294,9 +296,9 @@ export class Manifest {
|
|
|
294
296
|
setExtension<ExtType extends ExtensionType>(
|
|
295
297
|
extType: ExtType,
|
|
296
298
|
extName: string,
|
|
297
|
-
extData: ExtManifest<ExtType
|
|
299
|
+
extData: ExtManifest<ExtType>,
|
|
298
300
|
): ExtManifest<ExtType> {
|
|
299
|
-
const data =
|
|
301
|
+
const data = structuredClone(extData) as ExtManifest<ExtType>;
|
|
300
302
|
if (extType === DRIVER_TYPE) {
|
|
301
303
|
this.#data.drivers[extName] = data as unknown as ExtManifest<DriverType>;
|
|
302
304
|
} else {
|
|
@@ -337,7 +339,7 @@ export class Manifest {
|
|
|
337
339
|
throw new Error(
|
|
338
340
|
`Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${
|
|
339
341
|
this.appiumHome
|
|
340
|
-
}, manifest file: ${resolved}
|
|
342
|
+
}, manifest file: ${resolved}`,
|
|
341
343
|
);
|
|
342
344
|
}
|
|
343
345
|
}
|
|
@@ -348,10 +350,10 @@ export class Manifest {
|
|
|
348
350
|
|
|
349
351
|
function isExtension(value: unknown): value is ExtPackageJson<ExtensionType> {
|
|
350
352
|
return (
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
353
|
+
util.isPlainObject(value) &&
|
|
354
|
+
util.isPlainObject((value as {appium?: unknown}).appium) &&
|
|
355
|
+
typeof (value as {name?: unknown}).name === 'string' &&
|
|
356
|
+
typeof (value as {version?: unknown}).version === 'string'
|
|
355
357
|
);
|
|
356
358
|
}
|
|
357
359
|
|
|
@@ -359,7 +361,7 @@ function isDriver(value: unknown): value is ExtPackageJson<DriverType> {
|
|
|
359
361
|
return (
|
|
360
362
|
isExtension(value) &&
|
|
361
363
|
'driverName' in value.appium &&
|
|
362
|
-
|
|
364
|
+
typeof (value.appium as {driverName?: unknown}).driverName === 'string'
|
|
363
365
|
);
|
|
364
366
|
}
|
|
365
367
|
|
|
@@ -367,6 +369,6 @@ function isPlugin(value: unknown): value is ExtPackageJson<PluginType> {
|
|
|
367
369
|
return (
|
|
368
370
|
isExtension(value) &&
|
|
369
371
|
'pluginName' in value.appium &&
|
|
370
|
-
|
|
372
|
+
typeof (value.appium as {pluginName?: unknown}).pluginName === 'string'
|
|
371
373
|
);
|
|
372
374
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import type {PluginType} from '@appium/types';
|
|
3
3
|
import type {ExtManifest, ExtName, ExtRecord} from 'appium/types';
|
|
4
4
|
import {PLUGIN_TYPE} from '../constants';
|
|
@@ -17,7 +17,7 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
|
|
|
17
17
|
const instance = new PluginConfig(manifest);
|
|
18
18
|
if (PluginConfig.getInstance(manifest)) {
|
|
19
19
|
throw new Error(
|
|
20
|
-
`Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it
|
|
20
|
+
`Manifest with APPIUM_HOME ${manifest.appiumHome} already has a PluginConfig; use PluginConfig.getInstance() to retrieve it.`,
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
PluginConfig._instances.set(manifest, instance);
|
|
@@ -34,7 +34,7 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
|
|
|
34
34
|
|
|
35
35
|
public override extensionDesc(
|
|
36
36
|
pluginName: ExtName<PluginType>,
|
|
37
|
-
{version}: ExtManifest<PluginType
|
|
37
|
+
{version}: ExtManifest<PluginType>,
|
|
38
38
|
): string {
|
|
39
39
|
return `${String(pluginName)}@${version}`;
|
|
40
40
|
}
|
|
@@ -42,21 +42,26 @@ export class PluginConfig extends ExtensionConfig<PluginType> {
|
|
|
42
42
|
override print(activeNames: ExtName<PluginType>[] = []): void {
|
|
43
43
|
const pluginNames = Object.keys(this.installedExtensions);
|
|
44
44
|
|
|
45
|
-
if (
|
|
45
|
+
if (util.isEmpty(pluginNames)) {
|
|
46
46
|
log.info(
|
|
47
|
-
`No plugins have been installed. Use the "appium plugin" ` +
|
|
47
|
+
`No plugins have been installed. Use the "appium plugin" ` +
|
|
48
|
+
'command to install the one(s) you want to use.',
|
|
48
49
|
);
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
log.info(`Available plugins:`);
|
|
53
|
-
for (const [pluginName, pluginData] of
|
|
54
|
-
const activeTxt =
|
|
55
|
-
log.info(
|
|
54
|
+
for (const [pluginName, pluginData] of Object.entries(this.installedExtensions)) {
|
|
55
|
+
const activeTxt = activeNames.includes(pluginName as ExtName<PluginType>) ? ' (ACTIVE)' : '';
|
|
56
|
+
log.info(
|
|
57
|
+
` - ${this.extensionDesc(pluginName as ExtName<PluginType>, pluginData)}${activeTxt}`,
|
|
58
|
+
);
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
if (
|
|
59
|
-
log.info(
|
|
61
|
+
if (util.isEmpty(activeNames)) {
|
|
62
|
+
log.info(
|
|
63
|
+
'No plugins activated. Use the --use-plugins flag with names of plugins to activate',
|
|
64
|
+
);
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
}
|
package/lib/helpers/build.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import axios from 'axios';
|
|
3
2
|
import {exec} from 'teen_process';
|
|
4
|
-
import {system, fs} from '@appium/support';
|
|
3
|
+
import {system, fs, util} from '@appium/support';
|
|
5
4
|
import type {BuildInfo} from 'appium/types';
|
|
6
5
|
import {npmPackage} from '../utils';
|
|
7
6
|
|
|
8
7
|
export const APPIUM_VER = npmPackage.version;
|
|
9
|
-
export const rootDir = fs.findRoot(__dirname);
|
|
10
8
|
|
|
11
9
|
const GIT_BINARY = `git${system.isWindows() ? '.exe' : ''}`;
|
|
12
10
|
const GITHUB_API = 'https://api.github.com/repos/appium/appium';
|
|
13
11
|
|
|
14
|
-
const getFullGitPath =
|
|
12
|
+
const getFullGitPath = util.memoize(async function getFullGitPath(): Promise<string | null> {
|
|
15
13
|
try {
|
|
16
14
|
return await fs.which(GIT_BINARY);
|
|
17
15
|
} catch {
|
|
@@ -54,7 +52,10 @@ export async function getGitRev(useGithubApiFallback = false): Promise<string |
|
|
|
54
52
|
return null;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
async function getGitTimestamp(
|
|
55
|
+
async function getGitTimestamp(
|
|
56
|
+
commitSha: string,
|
|
57
|
+
useGithubApiFallback = false,
|
|
58
|
+
): Promise<string | null> {
|
|
58
59
|
const fullGitPath = await getFullGitPath();
|
|
59
60
|
if (fullGitPath) {
|
|
60
61
|
try {
|
|
@@ -5,14 +5,10 @@ import type {
|
|
|
5
5
|
NSCapabilities,
|
|
6
6
|
W3CCapabilities,
|
|
7
7
|
} from '@appium/types';
|
|
8
|
-
import
|
|
8
|
+
import {util} from '@appium/support';
|
|
9
9
|
import {log as logger} from '../logger';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
STANDARD_CAPS,
|
|
13
|
-
errors,
|
|
14
|
-
isW3cCaps,
|
|
15
|
-
} from '@appium/base-driver';
|
|
10
|
+
import {processCapabilities, STANDARD_CAPS, errors, isW3cCaps} from '@appium/base-driver';
|
|
11
|
+
import {mapKeys} from '../utils';
|
|
16
12
|
|
|
17
13
|
const W3C_APPIUM_PREFIX = 'appium';
|
|
18
14
|
const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLowerCase()));
|
|
@@ -36,7 +32,7 @@ export interface InvalidCaps<C extends Constraints = BaseDriverCapConstraints> {
|
|
|
36
32
|
export function makeNonW3cCapsError(): Error {
|
|
37
33
|
return new errors.SessionNotCreatedError(
|
|
38
34
|
'Session capabilities format must comply to the W3C standard. Make sure your client is up to date. ' +
|
|
39
|
-
'See https://www.w3.org/TR/webdriver/#new-session for more details.'
|
|
35
|
+
'See https://www.w3.org/TR/webdriver/#new-session for more details.',
|
|
40
36
|
);
|
|
41
37
|
}
|
|
42
38
|
|
|
@@ -48,7 +44,7 @@ export function makeNonW3cCapsError(): Error {
|
|
|
48
44
|
export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapConstraints>(
|
|
49
45
|
w3cCapabilities: W3CCapabilities<C>,
|
|
50
46
|
constraints: C = {} as C,
|
|
51
|
-
defaultCapabilities: NSCapabilities<C> = {}
|
|
47
|
+
defaultCapabilities: NSCapabilities<C> = {},
|
|
52
48
|
): ParsedDriverCaps<C> | InvalidCaps<C> {
|
|
53
49
|
if (!isW3cCaps(w3cCapabilities)) {
|
|
54
50
|
return {error: makeNonW3cCapsError()};
|
|
@@ -58,16 +54,16 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
|
|
|
58
54
|
// eslint-disable-next-line prefer-const -- assigned in success path after try
|
|
59
55
|
let processedW3CCapabilities: W3CCapabilities<C> | undefined;
|
|
60
56
|
|
|
61
|
-
w3cCapabilities =
|
|
62
|
-
defaultCapabilities =
|
|
57
|
+
w3cCapabilities = structuredClone(w3cCapabilities);
|
|
58
|
+
defaultCapabilities = structuredClone(defaultCapabilities);
|
|
63
59
|
|
|
64
|
-
if (!
|
|
65
|
-
for (const [defaultCapKey, defaultCapValue] of
|
|
60
|
+
if (!util.isEmpty(defaultCapabilities)) {
|
|
61
|
+
for (const [defaultCapKey, defaultCapValue] of Object.entries(defaultCapabilities)) {
|
|
66
62
|
let isCapAlreadySet = false;
|
|
67
63
|
for (const firstMatchEntry of w3cCapabilities.firstMatch ?? []) {
|
|
68
64
|
if (
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
util.isPlainObject(firstMatchEntry) &&
|
|
66
|
+
hasOwnCapability(firstMatchEntry as Record<string, unknown>, defaultCapKey)
|
|
71
67
|
) {
|
|
72
68
|
isCapAlreadySet = true;
|
|
73
69
|
break;
|
|
@@ -75,17 +71,16 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
|
|
|
75
71
|
}
|
|
76
72
|
isCapAlreadySet =
|
|
77
73
|
isCapAlreadySet ||
|
|
78
|
-
(
|
|
79
|
-
|
|
80
|
-
removeAppiumPrefixes(w3cCapabilities.alwaysMatch),
|
|
81
|
-
removeAppiumPrefix(defaultCapKey)
|
|
82
|
-
));
|
|
74
|
+
(util.isPlainObject(w3cCapabilities.alwaysMatch) &&
|
|
75
|
+
hasOwnCapability(w3cCapabilities.alwaysMatch as Record<string, unknown>, defaultCapKey));
|
|
83
76
|
if (isCapAlreadySet) {
|
|
84
77
|
continue;
|
|
85
78
|
}
|
|
86
79
|
|
|
87
|
-
if (
|
|
88
|
-
w3cCapabilities.firstMatch = [
|
|
80
|
+
if (util.isEmpty(w3cCapabilities.firstMatch)) {
|
|
81
|
+
w3cCapabilities.firstMatch = [
|
|
82
|
+
{[defaultCapKey]: defaultCapValue},
|
|
83
|
+
] as W3CCapabilities<C>['firstMatch'];
|
|
89
84
|
} else {
|
|
90
85
|
(w3cCapabilities.firstMatch[0] as Record<string, unknown>)[defaultCapKey] = defaultCapValue;
|
|
91
86
|
}
|
|
@@ -118,12 +113,12 @@ export function parseCapsForInnerDriver<C extends Constraints = BaseDriverCapCon
|
|
|
118
113
|
* Prefixes capability keys with `appium:` where appropriate.
|
|
119
114
|
*/
|
|
120
115
|
export function insertAppiumPrefixes<C extends Constraints = BaseDriverCapConstraints>(
|
|
121
|
-
caps: Capabilities<C
|
|
116
|
+
caps: Capabilities<C>,
|
|
122
117
|
): NSCapabilities<C> {
|
|
123
|
-
return
|
|
124
|
-
STANDARD_CAPS_LOWERCASE.has(key.toLowerCase()) || key.includes(':')
|
|
125
|
-
? key
|
|
126
|
-
: `${W3C_APPIUM_PREFIX}:${key}
|
|
118
|
+
return mapKeys(caps as Record<string, unknown>, (_, key) =>
|
|
119
|
+
STANDARD_CAPS_LOWERCASE.has(String(key).toLowerCase()) || String(key).includes(':')
|
|
120
|
+
? String(key)
|
|
121
|
+
: `${W3C_APPIUM_PREFIX}:${key}`,
|
|
127
122
|
) as NSCapabilities<C>;
|
|
128
123
|
}
|
|
129
124
|
|
|
@@ -131,9 +126,11 @@ export function insertAppiumPrefixes<C extends Constraints = BaseDriverCapConstr
|
|
|
131
126
|
* Removes `appium:` prefix from capability keys.
|
|
132
127
|
*/
|
|
133
128
|
export function removeAppiumPrefixes<C extends Constraints = BaseDriverCapConstraints>(
|
|
134
|
-
caps: NSCapabilities<C
|
|
129
|
+
caps: NSCapabilities<C>,
|
|
135
130
|
): Capabilities<C> {
|
|
136
|
-
return
|
|
131
|
+
return mapKeys(caps as Record<string, unknown>, (_, key) =>
|
|
132
|
+
removeAppiumPrefix(String(key)),
|
|
133
|
+
) as Capabilities<C>;
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
/**
|
|
@@ -142,16 +139,18 @@ export function removeAppiumPrefixes<C extends Constraints = BaseDriverCapConstr
|
|
|
142
139
|
*
|
|
143
140
|
* @returns Parsed settings object; empty if none found.
|
|
144
141
|
*/
|
|
145
|
-
export function pullSettings(
|
|
146
|
-
|
|
142
|
+
export function pullSettings(
|
|
143
|
+
caps: Record<string, unknown> | null | undefined,
|
|
144
|
+
): Record<string, unknown> {
|
|
145
|
+
if (!util.isPlainObject(caps) || util.isEmpty(caps)) {
|
|
147
146
|
return {};
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
const result: Record<string, unknown> = {};
|
|
151
150
|
const singleSettings: Record<string, unknown> = {};
|
|
152
|
-
for (const [key, value] of
|
|
151
|
+
for (const [key, value] of Object.entries(caps)) {
|
|
153
152
|
let match: RegExpExecArray | null;
|
|
154
|
-
if (/^(s|appium:s)ettings$/.test(key) &&
|
|
153
|
+
if (/^(s|appium:s)ettings$/.test(key) && util.isPlainObject(value)) {
|
|
155
154
|
Object.assign(result, value);
|
|
156
155
|
delete caps[key];
|
|
157
156
|
} else if ((match = /^(s|appium:s)ettings\[(\S+)\]$/.exec(key))) {
|
|
@@ -159,7 +158,7 @@ export function pullSettings(caps: Record<string, unknown> | null | undefined):
|
|
|
159
158
|
delete caps[key];
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
|
-
if (!
|
|
161
|
+
if (!util.isEmpty(singleSettings)) {
|
|
163
162
|
Object.assign(result, singleSettings);
|
|
164
163
|
}
|
|
165
164
|
return result;
|
|
@@ -167,5 +166,11 @@ export function pullSettings(caps: Record<string, unknown> | null | undefined):
|
|
|
167
166
|
|
|
168
167
|
function removeAppiumPrefix(key: string): string {
|
|
169
168
|
const prefix = `${W3C_APPIUM_PREFIX}:`;
|
|
170
|
-
return
|
|
169
|
+
return key.startsWith(prefix) ? key.substring(prefix.length) : key;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** True when `caps` has an own property matching `capKey` (with or without `appium:` prefix). */
|
|
173
|
+
function hasOwnCapability(caps: Record<string, unknown>, capKey: string): boolean {
|
|
174
|
+
const targetKey = removeAppiumPrefix(capKey);
|
|
175
|
+
return Object.keys(caps).some((key) => removeAppiumPrefix(key) === targetKey);
|
|
171
176
|
}
|
package/lib/helpers/network.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import os from 'node:os';
|
|
3
2
|
|
|
4
3
|
export const V4_BROADCAST_IP = '0.0.0.0';
|
|
@@ -16,10 +15,12 @@ export function fetchInterfaces(family: 4 | 6 | null = null): os.NetworkInterfac
|
|
|
16
15
|
} else if (family === 6) {
|
|
17
16
|
familyValue = [6, 'IPv6'];
|
|
18
17
|
}
|
|
19
|
-
const ifaces =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
const ifaces = Object.values(os.networkInterfaces()).filter(
|
|
19
|
+
Boolean,
|
|
20
|
+
) as os.NetworkInterfaceInfo[][];
|
|
21
|
+
return ifaces
|
|
22
|
+
.flat()
|
|
23
|
+
.filter((info) => !familyValue || familyValue.includes(info.family as 4 | 6 | string));
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
package/lib/insecure-features.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import {log as logger} from './logger';
|
|
3
3
|
|
|
4
4
|
import type {AppiumDriver} from './appium';
|
|
@@ -20,20 +20,20 @@ export function configureGlobalFeatures(this: AppiumDriver) {
|
|
|
20
20
|
`enabled unless explicitly disabled by --deny-insecure`,
|
|
21
21
|
);
|
|
22
22
|
this.relaxedSecurityEnabled = true;
|
|
23
|
-
} else if (!
|
|
23
|
+
} else if (!util.isEmpty(this.args.allowInsecure)) {
|
|
24
24
|
this.allowInsecure = validateFeatures(this.args.allowInsecure);
|
|
25
25
|
const globalAllowedFeatures = filterInsecureFeatures(this.allowInsecure);
|
|
26
|
-
if (!
|
|
26
|
+
if (!util.isEmpty(globalAllowedFeatures)) {
|
|
27
27
|
logger.info('Explicitly enabling insecure features:');
|
|
28
28
|
globalAllowedFeatures.forEach((a) => logger.info(` ${a}`));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
if (
|
|
31
|
+
if (util.isEmpty(this.args.denyInsecure)) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
this.denyInsecure = validateFeatures(this.args.denyInsecure);
|
|
35
35
|
const globalDeniedFeatures = filterInsecureFeatures(this.denyInsecure);
|
|
36
|
-
if (
|
|
36
|
+
if (util.isEmpty(globalDeniedFeatures)) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
logger.info('Explicitly disabling insecure features:');
|
|
@@ -60,19 +60,20 @@ export function configureDriverFeatures(
|
|
|
60
60
|
driver.relaxedSecurityEnabled = true;
|
|
61
61
|
}
|
|
62
62
|
const allowedDriverFeatures = filterInsecureFeatures(this.allowInsecure, driverName);
|
|
63
|
-
if (!
|
|
64
|
-
this.log.info(
|
|
65
|
-
'
|
|
63
|
+
if (!util.isEmpty(allowedDriverFeatures)) {
|
|
64
|
+
this.log.info(
|
|
65
|
+
'Explicitly enabling insecure features for this session ' +
|
|
66
|
+
'as per the server configuration:',
|
|
66
67
|
);
|
|
67
68
|
allowedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
|
|
68
69
|
driver.allowInsecure = allowedDriverFeatures;
|
|
69
70
|
}
|
|
70
71
|
const deniedDriverFeatures = filterInsecureFeatures(this.denyInsecure, driverName);
|
|
71
|
-
if (
|
|
72
|
+
if (util.isEmpty(deniedDriverFeatures)) {
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
|
-
this.log.info(
|
|
75
|
-
'as per the server configuration:',
|
|
75
|
+
this.log.info(
|
|
76
|
+
'Explicitly disabling insecure features for this session ' + 'as per the server configuration:',
|
|
76
77
|
);
|
|
77
78
|
deniedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
|
|
78
79
|
driver.denyInsecure = deniedDriverFeatures;
|
|
@@ -85,7 +86,8 @@ export function configureDriverFeatures(
|
|
|
85
86
|
*/
|
|
86
87
|
function validateFeatures(features: string[]): string[] {
|
|
87
88
|
const validator = (fullName: string) => {
|
|
88
|
-
const errMsg =
|
|
89
|
+
const errMsg =
|
|
90
|
+
`The full feature name must include both the destination automation name or the ` +
|
|
89
91
|
`'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
|
|
90
92
|
`the feature name split by a colon. Got '${fullName}' instead`;
|
|
91
93
|
|
|
@@ -95,7 +97,7 @@ function validateFeatures(features: string[]): string[] {
|
|
|
95
97
|
}
|
|
96
98
|
const [automationName, featureName] = [
|
|
97
99
|
fullName.substring(0, separatorPos),
|
|
98
|
-
fullName.substring(separatorPos + 1)
|
|
100
|
+
fullName.substring(separatorPos + 1),
|
|
99
101
|
];
|
|
100
102
|
if (!automationName || !featureName) {
|
|
101
103
|
throw new Error(errMsg);
|
|
@@ -115,7 +117,7 @@ function validateFeatures(features: string[]): string[] {
|
|
|
115
117
|
*/
|
|
116
118
|
function filterInsecureFeatures(
|
|
117
119
|
features: string[],
|
|
118
|
-
driverName: string = ALL_DRIVERS_MATCH
|
|
120
|
+
driverName: string = ALL_DRIVERS_MATCH,
|
|
119
121
|
): string[] {
|
|
120
122
|
const filterFn = (fullName: string) => {
|
|
121
123
|
const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
|