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
package/lib/appium.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import type WebSocket from 'ws';
|
|
3
2
|
import type {
|
|
4
3
|
AppiumServer,
|
|
@@ -11,6 +10,7 @@ import type {
|
|
|
11
10
|
PluginCommand,
|
|
12
11
|
Protocol,
|
|
13
12
|
RouteMatcher,
|
|
13
|
+
IAppiumIpc,
|
|
14
14
|
StringRecord,
|
|
15
15
|
TimestampedMultiSessionData,
|
|
16
16
|
W3CDriverCaps,
|
|
@@ -46,6 +46,8 @@ import * as bidiCommands from './bidi-commands';
|
|
|
46
46
|
import * as insecureFeatures from './insecure-features';
|
|
47
47
|
import * as inspectorCommands from './inspector-commands';
|
|
48
48
|
import type {DriverConfig} from './extension/driver-config';
|
|
49
|
+
import {AppiumIpc} from '@appium/base-driver';
|
|
50
|
+
import {compact, pickBy, pull} from './utils';
|
|
49
51
|
|
|
50
52
|
const desiredCapabilityConstraints = {
|
|
51
53
|
automationName: {
|
|
@@ -74,6 +76,11 @@ type SessionHandlerCreateResult = SessionHandlerResult<
|
|
|
74
76
|
|
|
75
77
|
type SessionHandlerDeleteResult = SessionHandlerResult<void>;
|
|
76
78
|
|
|
79
|
+
/** @internal Not part of {@link ExternalDriver}; used only when wiring session IPC. */
|
|
80
|
+
type IpcAssignable = {
|
|
81
|
+
assignIpc?: (ipc: IAppiumIpc) => Promise<void>;
|
|
82
|
+
};
|
|
83
|
+
|
|
77
84
|
/**
|
|
78
85
|
* Umbrella driver: owns the session table, loads platform drivers and plugins, and routes
|
|
79
86
|
* commands to the right session driver or plugin chain.
|
|
@@ -93,6 +100,8 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
93
100
|
|
|
94
101
|
readonly sessionPlugins: Record<string, Plugin[]> = {};
|
|
95
102
|
|
|
103
|
+
readonly sessionIpcs: Record<string, AppiumIpc> = {};
|
|
104
|
+
|
|
96
105
|
sessionlessPlugins: Plugin[] = [];
|
|
97
106
|
|
|
98
107
|
/** Set during server init before listen; tests may assign a mock after construction. */
|
|
@@ -182,7 +191,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
182
191
|
};
|
|
183
192
|
return {
|
|
184
193
|
...statusObj,
|
|
185
|
-
build:
|
|
194
|
+
build: structuredClone(getBuildInfo()),
|
|
186
195
|
};
|
|
187
196
|
}
|
|
188
197
|
|
|
@@ -201,7 +210,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
201
210
|
*/
|
|
202
211
|
async getAppiumSessions(): Promise<TimestampedMultiSessionData[]> {
|
|
203
212
|
this.assertFeatureEnabled(SESSION_DISCOVERY_FEATURE);
|
|
204
|
-
return
|
|
213
|
+
return Object.entries(this.sessions).map(([id, driver]) => ({
|
|
205
214
|
id,
|
|
206
215
|
created: driver.sessionCreationTimestampMs,
|
|
207
216
|
capabilities: driver.caps as DriverCaps<AppiumDriverConstraints>,
|
|
@@ -212,7 +221,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
212
221
|
printNewSessionAnnouncement(
|
|
213
222
|
driverName: string,
|
|
214
223
|
driverVersion?: string,
|
|
215
|
-
driverBaseVersion?: string
|
|
224
|
+
driverBaseVersion?: string,
|
|
216
225
|
): void {
|
|
217
226
|
this.log.info(
|
|
218
227
|
driverVersion
|
|
@@ -246,15 +255,18 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
246
255
|
*/
|
|
247
256
|
getCliArgsForDriver(extName: string): StringRecord | undefined {
|
|
248
257
|
const allCliArgsForExt = this.args.driver?.[extName] as StringRecord | undefined;
|
|
249
|
-
if (
|
|
258
|
+
if (util.isEmpty(allCliArgsForExt)) {
|
|
250
259
|
return undefined;
|
|
251
260
|
}
|
|
252
261
|
|
|
253
262
|
const defaults = getDefaultsForExtension(DRIVER_TYPE, extName);
|
|
254
|
-
const cliArgs =
|
|
263
|
+
const cliArgs = util.isEmpty(defaults)
|
|
255
264
|
? allCliArgsForExt
|
|
256
|
-
:
|
|
257
|
-
|
|
265
|
+
: pickBy(
|
|
266
|
+
allCliArgsForExt as Record<string, unknown>,
|
|
267
|
+
(value, key) => !util.isEqual(defaults[key as string], value),
|
|
268
|
+
);
|
|
269
|
+
return util.isEmpty(cliArgs) ? undefined : (cliArgs as StringRecord);
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
/**
|
|
@@ -265,12 +277,12 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
265
277
|
async createSession(
|
|
266
278
|
w3cCapabilities1: W3CAppiumDriverCaps,
|
|
267
279
|
w3cCapabilities2?: W3CAppiumDriverCaps,
|
|
268
|
-
w3cCapabilities3?: W3CAppiumDriverCaps
|
|
280
|
+
w3cCapabilities3?: W3CAppiumDriverCaps,
|
|
269
281
|
): Promise<SessionHandlerCreateResult> {
|
|
270
|
-
const defaultCapabilities =
|
|
282
|
+
const defaultCapabilities = structuredClone(this.args.defaultCapabilities);
|
|
271
283
|
const defaultSettings = pullSettings((defaultCapabilities ?? {}) as StringRecord);
|
|
272
|
-
const w3cCapabilities =
|
|
273
|
-
[w3cCapabilities3, w3cCapabilities2, w3cCapabilities1].find(isW3cCaps)
|
|
284
|
+
const w3cCapabilities = structuredClone(
|
|
285
|
+
[w3cCapabilities3, w3cCapabilities2, w3cCapabilities1].find(isW3cCaps),
|
|
274
286
|
);
|
|
275
287
|
if (!w3cCapabilities) {
|
|
276
288
|
throw makeNonW3cCapsError();
|
|
@@ -291,7 +303,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
291
303
|
const parsedCaps = parseCapsForInnerDriver<AppiumDriverConstraints>(
|
|
292
304
|
promoteAppiumOptions(w3cCapabilities),
|
|
293
305
|
this.desiredCapConstraints,
|
|
294
|
-
defaultCapabilities ? promoteAppiumOptionsForObject(defaultCapabilities) : undefined
|
|
306
|
+
defaultCapabilities ? promoteAppiumOptionsForObject(defaultCapabilities) : undefined,
|
|
295
307
|
);
|
|
296
308
|
|
|
297
309
|
if ('error' in parsedCaps && parsedCaps.error) {
|
|
@@ -321,14 +333,14 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
321
333
|
// We also want to assign any new Bidi Commands that the driver has specified, including all
|
|
322
334
|
// the standard bidi commands. But add a method existence guard since some old driver class
|
|
323
335
|
// instances might not have this method
|
|
324
|
-
if (
|
|
336
|
+
if (typeof driverInstance.updateBidiCommands === 'function') {
|
|
325
337
|
driverInstance.updateBidiCommands(InnerDriver.newBidiCommands ?? {});
|
|
326
338
|
}
|
|
327
339
|
|
|
328
340
|
// Likewise, any driver-specific CLI args that were passed in should be assigned directly to
|
|
329
341
|
// the driver so that they cannot be mimicked by a malicious user sending in capabilities
|
|
330
342
|
const cliArgs = this.getCliArgsForDriver(driverName);
|
|
331
|
-
if (
|
|
343
|
+
if (cliArgs !== undefined) {
|
|
332
344
|
(driverInstance as ExternalDriver & {cliArgs?: StringRecord}).cliArgs = cliArgs;
|
|
333
345
|
}
|
|
334
346
|
|
|
@@ -348,7 +360,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
348
360
|
throw new errors.SessionNotCreatedError(msg);
|
|
349
361
|
}
|
|
350
362
|
this.pendingDrivers[InnerDriver.name] = this.pendingDrivers[InnerDriver.name] || [];
|
|
351
|
-
otherPendingDriversData =
|
|
363
|
+
otherPendingDriversData = compact(
|
|
352
364
|
this.pendingDrivers[InnerDriver.name].map((drv) => drv.driverData),
|
|
353
365
|
);
|
|
354
366
|
this.pendingDrivers[InnerDriver.name].push(driverInstance);
|
|
@@ -358,11 +370,22 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
358
370
|
processedW3CCapabilities as never,
|
|
359
371
|
processedW3CCapabilities,
|
|
360
372
|
processedW3CCapabilities,
|
|
361
|
-
[...runningDriversData, ...otherPendingDriversData]
|
|
373
|
+
[...runningDriversData, ...otherPendingDriversData],
|
|
362
374
|
)) as [string, DriverCaps<AppiumDriverConstraints> & {webSocketUrl?: string | boolean}];
|
|
363
375
|
this.sessions[innerSessionId] = driverInstance;
|
|
376
|
+
// create an IPC channel for the driver and all plugins on this session
|
|
377
|
+
this.sessionIpcs[innerSessionId] = new AppiumIpc({
|
|
378
|
+
maxObjSize: this.args.maxIpcDataSize,
|
|
379
|
+
maxTopics: this.args.maxIpcTopics,
|
|
380
|
+
log: driverInstance.log,
|
|
381
|
+
});
|
|
382
|
+
const extDriver = driverInstance as unknown as IpcAssignable;
|
|
383
|
+
if (typeof extDriver.assignIpc === 'function') {
|
|
384
|
+
// TODO remove this existence guard as a breaking change in Appium 3
|
|
385
|
+
await extDriver.assignIpc(this.sessionIpcs[innerSessionId]);
|
|
386
|
+
}
|
|
364
387
|
} finally {
|
|
365
|
-
|
|
388
|
+
pull(this.pendingDrivers[InnerDriver.name], driverInstance);
|
|
366
389
|
}
|
|
367
390
|
|
|
368
391
|
this.attachUnexpectedShutdownHandler(driverInstance, innerSessionId);
|
|
@@ -376,7 +399,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
376
399
|
await driverInstance.startNewCommandTimeout();
|
|
377
400
|
|
|
378
401
|
// apply initial values to Appium settings (if provided)
|
|
379
|
-
if (driverInstance.isW3CProtocol() && !
|
|
402
|
+
if (driverInstance.isW3CProtocol() && !util.isEmpty(w3cSettings)) {
|
|
380
403
|
this.log.info(
|
|
381
404
|
`Applying the initial values to Appium settings parsed from W3C caps: ` +
|
|
382
405
|
JSON.stringify(w3cSettings),
|
|
@@ -394,7 +417,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
394
417
|
const bidiUrl = `${scheme}://${host}:${port}${basePath}${BIDI_BASE_PATH}/${innerSessionId}`;
|
|
395
418
|
this.log.info(
|
|
396
419
|
`Upstream driver responded with webSocketUrl ${dCaps.webSocketUrl}, will rewrite to ` +
|
|
397
|
-
|
|
420
|
+
`${bidiUrl} for response to client`,
|
|
398
421
|
);
|
|
399
422
|
// @ts-ignore webSocketUrl gets sent by the client as a boolean, but then it is supposed
|
|
400
423
|
// to come back from the server as a string. TODO figure out how to express this in our
|
|
@@ -424,7 +447,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
424
447
|
|
|
425
448
|
if (this.sessionPlugins[innerSessionId]) {
|
|
426
449
|
for (const plugin of this.sessionPlugins[innerSessionId]) {
|
|
427
|
-
if (
|
|
450
|
+
if (typeof plugin.onUnexpectedShutdown === 'function') {
|
|
428
451
|
this.log.debug(
|
|
429
452
|
`Plugin ${plugin.name} defines an unexpected shutdown handler; calling it now`,
|
|
430
453
|
);
|
|
@@ -442,11 +465,10 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
442
465
|
}
|
|
443
466
|
|
|
444
467
|
this.log.info(`Removing session '${innerSessionId}' from our master session list`);
|
|
445
|
-
|
|
446
|
-
delete this.sessionPlugins[innerSessionId];
|
|
468
|
+
this.deleteLinkedSessionObjects(innerSessionId);
|
|
447
469
|
};
|
|
448
470
|
|
|
449
|
-
if (
|
|
471
|
+
if (typeof driver.onUnexpectedShutdown === 'function') {
|
|
450
472
|
driver.onUnexpectedShutdown(onShutdown);
|
|
451
473
|
} else {
|
|
452
474
|
this.log.warn(
|
|
@@ -462,8 +484,8 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
462
484
|
* @remarks `InnerDriver` is expected to be the driver class; only `.name` is read.
|
|
463
485
|
*/
|
|
464
486
|
async curSessionDataForDriver(InnerDriver: {name: string}): Promise<DriverData[]> {
|
|
465
|
-
const data =
|
|
466
|
-
|
|
487
|
+
const data = compact(
|
|
488
|
+
Object.values(this.sessions)
|
|
467
489
|
.filter((s) => s.constructor.name === InnerDriver.name)
|
|
468
490
|
.map((s) => s.driverData),
|
|
469
491
|
);
|
|
@@ -489,20 +511,13 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
489
511
|
let dstSession: ExternalDriver | undefined;
|
|
490
512
|
if (this.sessions[sessionId]) {
|
|
491
513
|
const curConstructorName = this.sessions[sessionId].constructor.name;
|
|
492
|
-
otherSessionsData =
|
|
514
|
+
otherSessionsData = Object.entries(this.sessions)
|
|
493
515
|
.filter(
|
|
494
516
|
([key, value]) => value.constructor.name === curConstructorName && key !== sessionId,
|
|
495
517
|
)
|
|
496
518
|
.map(([, value]) => value.driverData);
|
|
497
519
|
dstSession = this.sessions[sessionId];
|
|
498
520
|
protocol = dstSession.protocol;
|
|
499
|
-
this.log.info(`Removing session ${sessionId} from our master session list`);
|
|
500
|
-
// regardless of whether the deleteSession completes successfully or not
|
|
501
|
-
// make the session unavailable, because who knows what state it might
|
|
502
|
-
// be in otherwise
|
|
503
|
-
delete this.sessions[sessionId];
|
|
504
|
-
delete this.sessionPlugins[sessionId];
|
|
505
|
-
|
|
506
521
|
this.cleanupBidiSockets(sessionId);
|
|
507
522
|
}
|
|
508
523
|
// this may not be correct, but if `dstSession` was falsy, the call to `deleteSession()` would
|
|
@@ -510,6 +525,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
510
525
|
if (!dstSession) {
|
|
511
526
|
throw new Error('Session not found');
|
|
512
527
|
}
|
|
528
|
+
|
|
513
529
|
return {
|
|
514
530
|
protocol,
|
|
515
531
|
value: await dstSession.deleteSession(sessionId, otherSessionsData),
|
|
@@ -521,6 +537,12 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
521
537
|
protocol,
|
|
522
538
|
error: e instanceof Error ? e : new Error(msg),
|
|
523
539
|
};
|
|
540
|
+
} finally {
|
|
541
|
+
// regardless of whether the deleteSession completes successfully or not
|
|
542
|
+
// make the session unavailable, because who knows what state it might
|
|
543
|
+
// be in otherwise
|
|
544
|
+
this.log.info(`Removing session ${sessionId} from our master session list`);
|
|
545
|
+
this.deleteLinkedSessionObjects(sessionId);
|
|
524
546
|
}
|
|
525
547
|
}
|
|
526
548
|
|
|
@@ -529,7 +551,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
529
551
|
* when `force` is true.
|
|
530
552
|
*/
|
|
531
553
|
async deleteAllSessions(opts: {force?: boolean; reason?: string} = {}): Promise<void> {
|
|
532
|
-
const sessionsCount =
|
|
554
|
+
const sessionsCount = Object.keys(this.sessions).length;
|
|
533
555
|
if (0 === sessionsCount) {
|
|
534
556
|
this.log.debug('There are no active sessions for cleanup');
|
|
535
557
|
return;
|
|
@@ -538,10 +560,10 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
538
560
|
const {force = false, reason} = opts;
|
|
539
561
|
this.log.debug(`Cleaning up ${util.pluralize('active session', sessionsCount, true)}`);
|
|
540
562
|
const cleanupPromises = force
|
|
541
|
-
?
|
|
563
|
+
? Object.values(this.sessions).map((drv) =>
|
|
542
564
|
drv.startUnexpectedShutdown(reason ? new Error(reason) : undefined),
|
|
543
565
|
)
|
|
544
|
-
:
|
|
566
|
+
: Object.keys(this.sessions).map((id) => this.deleteSession(id));
|
|
545
567
|
for (const cleanupPromise of cleanupPromises) {
|
|
546
568
|
try {
|
|
547
569
|
await cleanupPromise;
|
|
@@ -570,7 +592,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
570
592
|
));
|
|
571
593
|
}
|
|
572
594
|
|
|
573
|
-
if (
|
|
595
|
+
if (util.isEmpty(this.sessionlessPlugins)) {
|
|
574
596
|
this.sessionlessPlugins = this.createPluginInstances();
|
|
575
597
|
}
|
|
576
598
|
return this.sessionlessPlugins;
|
|
@@ -583,9 +605,10 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
583
605
|
pluginsToHandleCmd(cmd: string, sessionId: string | null = null): Plugin[] {
|
|
584
606
|
// to handle a given command, a plugin should either implement that command as a plugin
|
|
585
607
|
// instance method or it should implement a generic 'handle' method
|
|
586
|
-
return this.pluginsForSession(sessionId).filter(
|
|
587
|
-
(p
|
|
588
|
-
|
|
608
|
+
return this.pluginsForSession(sessionId).filter((p) => {
|
|
609
|
+
const pluginMethod = (p as Plugin & Record<string, unknown>)[cmd];
|
|
610
|
+
return typeof pluginMethod === 'function' || typeof p.handle === 'function';
|
|
611
|
+
});
|
|
589
612
|
}
|
|
590
613
|
|
|
591
614
|
/**
|
|
@@ -598,7 +621,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
598
621
|
const cliArgs = this.getCliArgsForPlugin(name);
|
|
599
622
|
const plugin = new PluginClass(name, cliArgs, driverId);
|
|
600
623
|
const extPlugin = plugin as Plugin & ExtensionCore;
|
|
601
|
-
if (
|
|
624
|
+
if (typeof extPlugin.updateBidiCommands === 'function') {
|
|
602
625
|
extPlugin.updateBidiCommands(PluginClass.newBidiCommands ?? {});
|
|
603
626
|
}
|
|
604
627
|
pluginInstances.push(plugin);
|
|
@@ -627,7 +650,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
627
650
|
// if a plugin override proxying for this command and that is why we are here instead of just
|
|
628
651
|
// letting the protocol proxy the command entirely, determine that, get the request object for
|
|
629
652
|
// use later on, then clean up the args
|
|
630
|
-
const reqForProxy =
|
|
653
|
+
const reqForProxy = args.at(-1)?.reqForProxy;
|
|
631
654
|
if (reqForProxy) {
|
|
632
655
|
args.pop();
|
|
633
656
|
}
|
|
@@ -640,7 +663,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
640
663
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
641
664
|
let driver: this | ExternalDriver = this;
|
|
642
665
|
if (isSessionCmd) {
|
|
643
|
-
sessionId =
|
|
666
|
+
sessionId = args.at(-1) as string;
|
|
644
667
|
dstSession = this.sessions[sessionId] ?? null;
|
|
645
668
|
if (!dstSession) {
|
|
646
669
|
throw new Error(`The session with id '${sessionId}' does not exist`);
|
|
@@ -754,7 +777,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
754
777
|
// previously sessionless to use the new sessionId, so that plugins can share state between
|
|
755
778
|
// their createSession method and other instance methods
|
|
756
779
|
if (cmd === CREATE_SESSION_COMMAND && this.sessionlessPlugins.length && !res.error) {
|
|
757
|
-
const newSessionId =
|
|
780
|
+
const newSessionId = (res.value as unknown[])[0] as string;
|
|
758
781
|
this.log.info(
|
|
759
782
|
`Promoting ${this.sessionlessPlugins.length} sessionless plugins to be attached ` +
|
|
760
783
|
`to session ID ${newSessionId}`,
|
|
@@ -762,11 +785,17 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
762
785
|
this.sessionPlugins[newSessionId] = this.sessionlessPlugins;
|
|
763
786
|
const promoted = this.sessionPlugins[newSessionId] as (Plugin & ExtensionCore)[];
|
|
764
787
|
for (const p of promoted) {
|
|
765
|
-
if (
|
|
788
|
+
if (typeof p.updateLogPrefix === 'function') {
|
|
766
789
|
p.updateLogPrefix(
|
|
767
|
-
`${generateDriverLogPrefix(p)} <${generateDriverLogPrefix(this.sessions[newSessionId])}
|
|
790
|
+
`${generateDriverLogPrefix(p)} <${generateDriverLogPrefix(this.sessions[newSessionId])}>`,
|
|
768
791
|
);
|
|
769
792
|
}
|
|
793
|
+
// we also want to assign the IPC channel for this session to the plugins
|
|
794
|
+
const extPlugin = p as unknown as IpcAssignable;
|
|
795
|
+
if (typeof extPlugin.assignIpc === 'function') {
|
|
796
|
+
// TODO remove this existence guard as a breaking change in Appium 4
|
|
797
|
+
await extPlugin.assignIpc(this.sessionIpcs[newSessionId]);
|
|
798
|
+
}
|
|
770
799
|
}
|
|
771
800
|
this.sessionlessPlugins = [];
|
|
772
801
|
}
|
|
@@ -806,7 +835,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
806
835
|
cmdHandledBy[plugin.name] = true; // if we make it here, this plugin has attempted to handle cmd
|
|
807
836
|
// first attempt to handle the command via a command-specific handler on the plugin
|
|
808
837
|
const cmdHandler = (plugin as Plugin & Record<string, unknown>)[cmd];
|
|
809
|
-
if (
|
|
838
|
+
if (typeof cmdHandler === 'function') {
|
|
810
839
|
// Command methods must run with plugin as `this` (detached property access drops binding).
|
|
811
840
|
return await (cmdHandler as PluginCommand).call(
|
|
812
841
|
plugin,
|
|
@@ -815,7 +844,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
815
844
|
...args,
|
|
816
845
|
);
|
|
817
846
|
}
|
|
818
|
-
if (
|
|
847
|
+
if (typeof plugin.handle !== 'function') {
|
|
819
848
|
throw new Error(`Plugin ${plugin.name} cannot handle command '${cmd}'`);
|
|
820
849
|
}
|
|
821
850
|
return await plugin.handle(_next, driver as ExternalDriver, cmd, ...args);
|
|
@@ -828,7 +857,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
828
857
|
/** After a command with plugins, logs which handlers ran vs. were skipped (debugging aid). */
|
|
829
858
|
logPluginHandlerReport(
|
|
830
859
|
plugins: Plugin[],
|
|
831
|
-
{cmd, cmdHandledBy}: {cmd: string; cmdHandledBy: Record<string, boolean>}
|
|
860
|
+
{cmd, cmdHandledBy}: {cmd: string; cmdHandledBy: Record<string, boolean>},
|
|
832
861
|
): void {
|
|
833
862
|
if (!plugins.length) {
|
|
834
863
|
return;
|
|
@@ -874,7 +903,7 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
874
903
|
// Sadly, we don't know exactly what kind of object will be returned. It will either be a bare
|
|
875
904
|
// object, or a protocol-aware object with protocol and error/value keys. So we need to sniff
|
|
876
905
|
// it and make sure we don't double-wrap it if it's the latter kind.
|
|
877
|
-
if (
|
|
906
|
+
if (util.isPlainObject(cmdRes) && 'protocol' in cmdRes) {
|
|
878
907
|
Object.assign(res, cmdRes);
|
|
879
908
|
} else {
|
|
880
909
|
res.value = cmdRes;
|
|
@@ -887,21 +916,28 @@ export class AppiumDriver extends DriverCore<AppiumDriverConstraints> {
|
|
|
887
916
|
/** Whether the inner session driver is actively proxying for this session id. */
|
|
888
917
|
override proxyActive(sessionId: string): boolean {
|
|
889
918
|
const dstSession = this.sessions[sessionId];
|
|
890
|
-
return
|
|
919
|
+
return typeof dstSession?.proxyActive === 'function' && dstSession.proxyActive(sessionId);
|
|
891
920
|
}
|
|
892
921
|
|
|
893
922
|
/** URL patterns the session driver does not want proxied; empty if no session or no list. */
|
|
894
923
|
override getProxyAvoidList(sessionId: string): RouteMatcher[] {
|
|
895
924
|
const dstSession = this.sessions[sessionId];
|
|
896
|
-
return
|
|
925
|
+
return typeof dstSession?.getProxyAvoidList === 'function'
|
|
926
|
+
? dstSession.getProxyAvoidList()
|
|
927
|
+
: [];
|
|
897
928
|
}
|
|
898
929
|
|
|
899
930
|
/** Whether the session driver supports proxying for this session. */
|
|
900
931
|
override canProxy(sessionId: string): boolean {
|
|
901
932
|
const dstSession = this.sessions[sessionId];
|
|
902
|
-
return
|
|
933
|
+
return typeof dstSession?.canProxy === 'function' && dstSession.canProxy(sessionId);
|
|
903
934
|
}
|
|
904
935
|
|
|
936
|
+
private deleteLinkedSessionObjects(sessionId: string): void {
|
|
937
|
+
delete this.sessions[sessionId];
|
|
938
|
+
delete this.sessionPlugins[sessionId];
|
|
939
|
+
delete this.sessionIpcs[sessionId];
|
|
940
|
+
}
|
|
905
941
|
}
|
|
906
942
|
|
|
907
943
|
/**
|
|
@@ -923,11 +959,10 @@ export class NoDriverProxyCommandError extends Error {
|
|
|
923
959
|
|
|
924
960
|
/** True if `cmd` should run on the umbrella driver instead of only on the session’s inner driver. */
|
|
925
961
|
function isAppiumDriverCommand(cmd: string): boolean {
|
|
926
|
-
return
|
|
927
|
-
||
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
962
|
+
return (
|
|
963
|
+
!isSessionCommand(cmd) ||
|
|
964
|
+
[DELETE_SESSION_COMMAND, LIST_DRIVER_COMMANDS_COMMAND, LIST_DRIVER_EXTENSIONS_COMMAND].includes(
|
|
965
|
+
cmd,
|
|
966
|
+
)
|
|
967
|
+
);
|
|
932
968
|
}
|
|
933
|
-
|