appium-android-driver 14.0.2 → 14.0.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/CHANGELOG.md +12 -0
- package/build/lib/commands/app-management.d.ts +1 -1
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +2 -4
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/bidi/models.d.ts +1 -1
- package/build/lib/commands/bidi/models.d.ts.map +1 -1
- package/build/lib/commands/bidi/models.js +1 -1
- package/build/lib/commands/bidi/models.js.map +1 -1
- package/build/lib/commands/bluetooth.d.ts.map +1 -1
- package/build/lib/commands/bluetooth.js.map +1 -1
- package/build/lib/commands/context/cache.d.ts +1 -1
- package/build/lib/commands/context/cache.d.ts.map +1 -1
- package/build/lib/commands/context/cache.js.map +1 -1
- package/build/lib/commands/context/exports.d.ts.map +1 -1
- package/build/lib/commands/context/exports.js +3 -4
- package/build/lib/commands/context/exports.js.map +1 -1
- package/build/lib/commands/context/helpers.d.ts.map +1 -1
- package/build/lib/commands/context/helpers.js +21 -26
- package/build/lib/commands/context/helpers.js.map +1 -1
- package/build/lib/commands/device/common.d.ts +1 -1
- package/build/lib/commands/device/common.d.ts.map +1 -1
- package/build/lib/commands/device/common.js +8 -16
- package/build/lib/commands/device/common.js.map +1 -1
- package/build/lib/commands/device/emulator-actions.d.ts.map +1 -1
- package/build/lib/commands/device/emulator-actions.js +1 -1
- package/build/lib/commands/device/emulator-actions.js.map +1 -1
- package/build/lib/commands/device/emulator-console.d.ts.map +1 -1
- package/build/lib/commands/device/emulator-console.js.map +1 -1
- package/build/lib/commands/device/utils.d.ts.map +1 -1
- package/build/lib/commands/device/utils.js +5 -6
- package/build/lib/commands/device/utils.js.map +1 -1
- package/build/lib/commands/deviceidle.d.ts.map +1 -1
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +2 -4
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +6 -20
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +1 -1
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +1 -1
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts.map +1 -1
- package/build/lib/commands/geolocation.js +5 -12
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/gestures.d.ts.map +1 -1
- package/build/lib/commands/gestures.js.map +1 -1
- package/build/lib/commands/image-injection.d.ts.map +1 -1
- package/build/lib/commands/image-injection.js +2 -2
- package/build/lib/commands/image-injection.js.map +1 -1
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +1 -7
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +2 -3
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/legacy.d.ts.map +1 -1
- package/build/lib/commands/legacy.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts.map +1 -1
- package/build/lib/commands/lock/exports.js.map +1 -1
- package/build/lib/commands/lock/helpers.d.ts.map +1 -1
- package/build/lib/commands/lock/helpers.js +3 -10
- package/build/lib/commands/lock/helpers.js.map +1 -1
- package/build/lib/commands/log.d.ts +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +6 -8
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +2 -2
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/misc.d.ts.map +1 -1
- package/build/lib/commands/misc.js.map +1 -1
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +4 -11
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/nfc.d.ts.map +1 -1
- package/build/lib/commands/nfc.js.map +1 -1
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +4 -21
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +4 -7
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +2 -2
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/resources.d.ts.map +1 -1
- package/build/lib/commands/resources.js.map +1 -1
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +1 -6
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +6 -9
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +1 -1
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/time.d.ts.map +1 -1
- package/build/lib/commands/time.js +1 -1
- package/build/lib/commands/time.js.map +1 -1
- package/build/lib/commands/types.d.ts +4 -4
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/doctor/checks.d.ts.map +1 -1
- package/build/lib/doctor/checks.js +2 -2
- package/build/lib/doctor/checks.js.map +1 -1
- package/build/lib/driver.d.ts +8 -8
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +14 -20
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +1 -10
- package/build/lib/execute-method-map.js.map +1 -1
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +1 -1
- package/build/lib/index.js.map +1 -1
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +1 -1
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.ts +15 -43
- package/lib/commands/appearance.ts +1 -5
- package/lib/commands/bidi/models.ts +5 -12
- package/lib/commands/bluetooth.ts +1 -0
- package/lib/commands/context/cache.ts +2 -1
- package/lib/commands/context/exports.ts +17 -40
- package/lib/commands/context/helpers.ts +37 -88
- package/lib/commands/device/common.ts +16 -29
- package/lib/commands/device/emulator-actions.ts +12 -49
- package/lib/commands/device/emulator-console.ts +1 -0
- package/lib/commands/device/utils.ts +7 -16
- package/lib/commands/deviceidle.ts +1 -0
- package/lib/commands/element.ts +6 -20
- package/lib/commands/execute.ts +6 -13
- package/lib/commands/file-actions.ts +17 -50
- package/lib/commands/find.ts +4 -6
- package/lib/commands/geolocation.ts +9 -17
- package/lib/commands/gestures.ts +2 -1
- package/lib/commands/image-injection.ts +9 -19
- package/lib/commands/ime.ts +2 -7
- package/lib/commands/intent.ts +3 -3
- package/lib/commands/keyboard.ts +4 -14
- package/lib/commands/legacy.ts +1 -0
- package/lib/commands/lock/exports.ts +5 -10
- package/lib/commands/lock/helpers.ts +17 -52
- package/lib/commands/log.ts +12 -22
- package/lib/commands/media-projection.ts +9 -21
- package/lib/commands/memory.ts +2 -5
- package/lib/commands/misc.ts +3 -5
- package/lib/commands/network.ts +9 -27
- package/lib/commands/nfc.ts +1 -0
- package/lib/commands/performance.ts +12 -48
- package/lib/commands/permissions.ts +10 -22
- package/lib/commands/recordscreen.ts +16 -41
- package/lib/commands/resources.ts +3 -9
- package/lib/commands/shell.ts +3 -7
- package/lib/commands/streamscreen.ts +17 -37
- package/lib/commands/system-bars.ts +7 -13
- package/lib/commands/time.ts +4 -8
- package/lib/commands/types.ts +9 -10
- package/lib/doctor/checks.ts +11 -18
- package/lib/driver.ts +43 -65
- package/lib/execute-method-map.ts +1 -10
- package/lib/index.ts +1 -1
- package/lib/method-map.ts +1 -0
- package/lib/utils.ts +4 -6
- package/package.json +24 -38
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {BiDiLogLevel, LogEntryAddedEvent, ContextUpdatedEvent} from './types.js';
|
|
2
|
-
import {NATIVE_WIN} from '../context/helpers.js';
|
|
3
|
-
import {
|
|
4
|
-
CONTEXT_UPDATED_EVENT,
|
|
5
|
-
LOG_ENTRY_ADDED_EVENT,
|
|
6
|
-
CONTEXT_UPDATED_EVENT_OBSOLETE,
|
|
7
|
-
} from './constants.js';
|
|
8
1
|
import type {LogEntry} from 'appium-adb';
|
|
9
2
|
|
|
3
|
+
import {NATIVE_WIN} from '../context/helpers.js';
|
|
4
|
+
import {CONTEXT_UPDATED_EVENT, LOG_ENTRY_ADDED_EVENT, CONTEXT_UPDATED_EVENT_OBSOLETE} from './constants.js';
|
|
5
|
+
import type {BiDiLogLevel, LogEntryAddedEvent, ContextUpdatedEvent} from './types.js';
|
|
6
|
+
|
|
10
7
|
function toContextUpdatedEvent(method: string, contextName: string): ContextUpdatedEvent {
|
|
11
8
|
return {
|
|
12
9
|
method,
|
|
@@ -33,11 +30,7 @@ export const makeObsoleteContextUpdatedEvent = (contextName: string) =>
|
|
|
33
30
|
* @param context - Active session context name
|
|
34
31
|
* @param type - Log entry classification passed through to the event
|
|
35
32
|
*/
|
|
36
|
-
export function makeLogEntryAddedEvent(
|
|
37
|
-
entry: LogEntry,
|
|
38
|
-
context: string,
|
|
39
|
-
type: string,
|
|
40
|
-
): LogEntryAddedEvent {
|
|
33
|
+
export function makeLogEntryAddedEvent(entry: LogEntry, context: string, type: string): LogEntryAddedEvent {
|
|
41
34
|
return {
|
|
42
35
|
context,
|
|
43
36
|
method: LOG_ENTRY_ADDED_EVENT,
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import {util} from '@appium/support';
|
|
2
|
+
import type {StringRecord} from '@appium/types';
|
|
2
3
|
import {Chromedriver} from 'appium-chromedriver';
|
|
3
4
|
import {errors, PROTOCOLS} from 'appium/driver.js';
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
import type {AndroidDriver} from '../../driver.js';
|
|
7
|
+
import {APP_STATE} from '../app-management.js';
|
|
8
|
+
import {BIDI_EVENT_NAME} from '../bidi/constants.js';
|
|
9
|
+
import {makeContextUpdatedEvent, makeObsoleteContextUpdatedEvent} from '../bidi/models.js';
|
|
10
|
+
import type {WebviewsMapping} from '../types.js';
|
|
5
11
|
import {
|
|
6
12
|
CHROMIUM_WIN,
|
|
7
13
|
KNOWN_CHROME_PACKAGE_NAMES,
|
|
@@ -15,11 +21,6 @@ import {
|
|
|
15
21
|
setupNewChromedriver,
|
|
16
22
|
shouldDismissChromeWelcome,
|
|
17
23
|
} from './helpers.js';
|
|
18
|
-
import {APP_STATE} from '../app-management.js';
|
|
19
|
-
import {BIDI_EVENT_NAME} from '../bidi/constants.js';
|
|
20
|
-
import {makeContextUpdatedEvent, makeObsoleteContextUpdatedEvent} from '../bidi/models.js';
|
|
21
|
-
import type {AndroidDriver} from '../../driver.js';
|
|
22
|
-
import type {WebviewsMapping} from '../types.js';
|
|
23
24
|
|
|
24
25
|
// https://github.com/appium/appium/issues/20710
|
|
25
26
|
const DEFAULT_NATIVE_WINDOW_HANDLE = '1';
|
|
@@ -83,10 +84,7 @@ export async function setContext(this: AndroidDriver, name?: string | null): Pro
|
|
|
83
84
|
* @param waitForWebviewMs - Optional timeout in milliseconds to wait for webviews to appear
|
|
84
85
|
* @returns An array of webview mapping objects containing detailed information about each webview
|
|
85
86
|
*/
|
|
86
|
-
export async function mobileGetContexts(
|
|
87
|
-
this: AndroidDriver,
|
|
88
|
-
waitForWebviewMs?: number,
|
|
89
|
-
): Promise<WebviewsMapping[]> {
|
|
87
|
+
export async function mobileGetContexts(this: AndroidDriver, waitForWebviewMs?: number): Promise<WebviewsMapping[]> {
|
|
90
88
|
const _opts = {
|
|
91
89
|
androidDeviceSocket: this.opts.androidDeviceSocket,
|
|
92
90
|
ensureWebviewsHavePages: true,
|
|
@@ -256,10 +254,7 @@ export async function startChromedriverProxy(
|
|
|
256
254
|
opts.chromeAndroidPackage = androidPackage[1];
|
|
257
255
|
}
|
|
258
256
|
if (!opts.extractChromeAndroidPackageFromContextName) {
|
|
259
|
-
if (
|
|
260
|
-
this.opts.enableWebviewDetailsCollection !== undefined &&
|
|
261
|
-
!this.opts.enableWebviewDetailsCollection
|
|
262
|
-
) {
|
|
257
|
+
if (this.opts.enableWebviewDetailsCollection !== undefined && !this.opts.enableWebviewDetailsCollection) {
|
|
263
258
|
// When enableWebviewDetailsCollection capability is explicitly disabled, try to identify
|
|
264
259
|
// chromeAndroidPackage based on contexts, known chrome variant packages and queryAppState result
|
|
265
260
|
// since webviewsMapping does not have info object
|
|
@@ -269,11 +264,7 @@ export async function startChromedriverProxy(
|
|
|
269
264
|
continue;
|
|
270
265
|
}
|
|
271
266
|
const appState = await this.queryAppState(knownPackage);
|
|
272
|
-
if (
|
|
273
|
-
[APP_STATE.RUNNING_IN_BACKGROUND, APP_STATE.RUNNING_IN_FOREGROUND].includes(
|
|
274
|
-
appState as any,
|
|
275
|
-
)
|
|
276
|
-
) {
|
|
267
|
+
if ([APP_STATE.RUNNING_IN_BACKGROUND, APP_STATE.RUNNING_IN_FOREGROUND].includes(appState as any)) {
|
|
277
268
|
opts.chromeAndroidPackage = knownPackage;
|
|
278
269
|
this.log.debug(
|
|
279
270
|
`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
@@ -286,9 +277,7 @@ export async function startChromedriverProxy(
|
|
|
286
277
|
for (const wm of webviewsMapping) {
|
|
287
278
|
if (wm.webviewName === context && wm?.info?.['Android-Package'] !== undefined) {
|
|
288
279
|
// XXX: should be a type guard here
|
|
289
|
-
opts.chromeAndroidPackage = (wm.info as NonNullable<WebviewsMapping['info']>)[
|
|
290
|
-
'Android-Package'
|
|
291
|
-
];
|
|
280
|
+
opts.chromeAndroidPackage = (wm.info as NonNullable<WebviewsMapping['info']>)['Android-Package'];
|
|
292
281
|
this.log.debug(
|
|
293
282
|
`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
294
283
|
`for context '${context}' by CDP`,
|
|
@@ -308,9 +297,7 @@ export async function startChromedriverProxy(
|
|
|
308
297
|
try {
|
|
309
298
|
await this.onChromedriverStop(context);
|
|
310
299
|
} catch (err) {
|
|
311
|
-
this.log.warn(
|
|
312
|
-
`Error handling chromedriver stop event for context ${context}: ${(err as Error).message}`,
|
|
313
|
-
);
|
|
300
|
+
this.log.warn(`Error handling chromedriver stop event for context ${context}: ${(err as Error).message}`);
|
|
314
301
|
}
|
|
315
302
|
}
|
|
316
303
|
});
|
|
@@ -320,9 +307,7 @@ export async function startChromedriverProxy(
|
|
|
320
307
|
// hook up the local variables so we can proxy this biz
|
|
321
308
|
this.chromedriver = cd;
|
|
322
309
|
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
323
|
-
this.proxyCommand = this.chromedriver.jwproxy.command.bind(
|
|
324
|
-
this.chromedriver.jwproxy,
|
|
325
|
-
) as typeof this.proxyCommand;
|
|
310
|
+
this.proxyCommand = this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy) as typeof this.proxyCommand;
|
|
326
311
|
this.jwpProxyActive = true;
|
|
327
312
|
}
|
|
328
313
|
|
|
@@ -353,9 +338,7 @@ export async function onChromedriverStop(this: AndroidDriver, context: string):
|
|
|
353
338
|
} else {
|
|
354
339
|
// if a Chromedriver in the non-active context barfs, we don't really
|
|
355
340
|
// care, we'll just make a new one next time we need the context.
|
|
356
|
-
this.log.warn(
|
|
357
|
-
"Chromedriver quit unexpectedly, but it wasn't the active " + 'context, ignoring',
|
|
358
|
-
);
|
|
341
|
+
this.log.warn("Chromedriver quit unexpectedly, but it wasn't the active context, ignoring");
|
|
359
342
|
delete this.sessionChromedrivers[context];
|
|
360
343
|
}
|
|
361
344
|
}
|
|
@@ -411,9 +394,7 @@ export async function notifyBiDiContextChange(this: AndroidDriver): Promise<void
|
|
|
411
394
|
*/
|
|
412
395
|
export async function mobileGetChromeCapabilities(this: AndroidDriver): Promise<StringRecord> {
|
|
413
396
|
if (!this.isWebContext()) {
|
|
414
|
-
throw new errors.InvalidContextError(
|
|
415
|
-
'mobile: getChromeCapabilities can only be called in a webview context',
|
|
416
|
-
);
|
|
397
|
+
throw new errors.InvalidContextError('mobile: getChromeCapabilities can only be called in a webview context');
|
|
417
398
|
}
|
|
418
399
|
|
|
419
400
|
const currentContext = await this.getCurrentContext();
|
|
@@ -455,9 +436,7 @@ export async function startChromeSession(this: AndroidDriver): Promise<void> {
|
|
|
455
436
|
try {
|
|
456
437
|
await this.onChromedriverStop(CHROMIUM_WIN);
|
|
457
438
|
} catch (err) {
|
|
458
|
-
this.log.warn(
|
|
459
|
-
`Error handling chromedriver stop event for context ${CHROMIUM_WIN}: ${(err as Error).message}`,
|
|
460
|
-
);
|
|
439
|
+
this.log.warn(`Error handling chromedriver stop event for context ${CHROMIUM_WIN}: ${(err as Error).message}`);
|
|
461
440
|
}
|
|
462
441
|
}
|
|
463
442
|
});
|
|
@@ -468,9 +447,7 @@ export async function startChromeSession(this: AndroidDriver): Promise<void> {
|
|
|
468
447
|
this.curContext = CHROMIUM_WIN;
|
|
469
448
|
this.sessionChromedrivers[CHROMIUM_WIN] = chromedriver;
|
|
470
449
|
this.proxyReqRes = chromedriver.proxyReq.bind(chromedriver);
|
|
471
|
-
this.proxyCommand = chromedriver.jwproxy.command.bind(
|
|
472
|
-
chromedriver.jwproxy,
|
|
473
|
-
) as typeof this.proxyCommand;
|
|
450
|
+
this.proxyCommand = chromedriver.jwproxy.command.bind(chromedriver.jwproxy) as typeof this.proxyCommand;
|
|
474
451
|
this.jwpProxyActive = true;
|
|
475
452
|
|
|
476
453
|
if (shouldDismissChromeWelcome.bind(this)()) {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import dns from 'node:dns/promises';
|
|
2
|
+
import http from 'node:http';
|
|
3
3
|
import net from 'node:net';
|
|
4
|
-
import {findAPortNotInUse} from 'portscanner';
|
|
5
|
-
import {sleep} from 'asyncbox';
|
|
6
4
|
import os from 'node:os';
|
|
7
5
|
import path from 'node:path';
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
import {util, timing} from '@appium/support';
|
|
8
|
+
import type {StringRecord} from '@appium/types';
|
|
9
9
|
import {Chromedriver} from 'appium-chromedriver';
|
|
10
10
|
import type {ChromedriverOpts} from 'appium-chromedriver';
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
11
|
+
import {sleep} from 'asyncbox';
|
|
12
|
+
import axios from 'axios';
|
|
13
|
+
import {findAPortNotInUse} from 'portscanner';
|
|
14
|
+
|
|
13
15
|
import type {AndroidDriver, AndroidDriverOpts} from '../../driver.js';
|
|
14
16
|
import type {
|
|
15
17
|
GetWebviewsOpts,
|
|
@@ -20,7 +22,7 @@ import type {
|
|
|
20
22
|
WebviewProc,
|
|
21
23
|
DetailCollectionOptions,
|
|
22
24
|
} from '../types.js';
|
|
23
|
-
import
|
|
25
|
+
import {toDetailsCacheKey, getWebviewDetails, WEBVIEWS_DETAILS_CACHE} from './cache.js';
|
|
24
26
|
|
|
25
27
|
// https://cs.chromium.org/chromium/src/chrome/browser/devtools/device/android_device_info_query.cc
|
|
26
28
|
export const CHROME_BROWSER_PACKAGE_ACTIVITY = {
|
|
@@ -74,10 +76,10 @@ const WEBVIEW_PKG_PATTERN = new RegExp(`^${WEBVIEW_BASE}([^\\d\\s][\\w.]*)`);
|
|
|
74
76
|
const WEBVIEW_WAIT_INTERVAL_MS = 200;
|
|
75
77
|
const CDP_REQ_TIMEOUT = 2000; // ms
|
|
76
78
|
const DEVTOOLS_PORTS_RANGE = [10900, 11000] as const;
|
|
77
|
-
const DEVTOOLS_PORT_ALLOCATION_GUARD = util.getLockFileGuard(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
79
|
+
const DEVTOOLS_PORT_ALLOCATION_GUARD = util.getLockFileGuard(path.resolve(os.tmpdir(), 'android_devtools_port_guard'), {
|
|
80
|
+
timeout: 7,
|
|
81
|
+
tryRecovery: true,
|
|
82
|
+
});
|
|
81
83
|
|
|
82
84
|
// #region Exported Functions
|
|
83
85
|
|
|
@@ -91,9 +93,8 @@ export function getChromePkg(
|
|
|
91
93
|
browser: string,
|
|
92
94
|
): (typeof CHROME_BROWSER_PACKAGE_ACTIVITY)[keyof typeof CHROME_BROWSER_PACKAGE_ACTIVITY] {
|
|
93
95
|
return (
|
|
94
|
-
CHROME_BROWSER_PACKAGE_ACTIVITY[
|
|
95
|
-
|
|
96
|
-
] || CHROME_BROWSER_PACKAGE_ACTIVITY.default
|
|
96
|
+
CHROME_BROWSER_PACKAGE_ACTIVITY[browser.toLowerCase() as keyof typeof CHROME_BROWSER_PACKAGE_ACTIVITY] ||
|
|
97
|
+
CHROME_BROWSER_PACKAGE_ACTIVITY.default
|
|
97
98
|
);
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -118,19 +119,14 @@ export function parseWebviewNames(
|
|
|
118
119
|
const result: string[] = [];
|
|
119
120
|
for (const {webview, pages, proc, webviewName} of webviewsMapping) {
|
|
120
121
|
if (ensureWebviewsHavePages && !pages?.length) {
|
|
121
|
-
this.log.info(
|
|
122
|
-
`Skipping the webview '${webview}' at '${proc}' ` +
|
|
123
|
-
`since it has reported having zero pages`,
|
|
124
|
-
);
|
|
122
|
+
this.log.info(`Skipping the webview '${webview}' at '${proc}' since it has reported having zero pages`);
|
|
125
123
|
continue;
|
|
126
124
|
}
|
|
127
125
|
if (webviewName) {
|
|
128
126
|
result.push(webviewName);
|
|
129
127
|
}
|
|
130
128
|
}
|
|
131
|
-
this.log.debug(
|
|
132
|
-
`Found ${util.pluralize('webview', result.length, true)}: ${JSON.stringify(result)}`,
|
|
133
|
-
);
|
|
129
|
+
this.log.debug(`Found ${util.pluralize('webview', result.length, true)}: ${JSON.stringify(result)}`);
|
|
134
130
|
return result;
|
|
135
131
|
}
|
|
136
132
|
|
|
@@ -150,10 +146,7 @@ export function parseWebviewNames(
|
|
|
150
146
|
* @param opts - Options for webview discovery including device socket, port, and collection settings
|
|
151
147
|
* @returns An array of webview mapping objects
|
|
152
148
|
*/
|
|
153
|
-
export async function getWebViewsMapping(
|
|
154
|
-
this: AndroidDriver,
|
|
155
|
-
opts: GetWebviewsOpts = {},
|
|
156
|
-
): Promise<WebviewsMapping[]> {
|
|
149
|
+
export async function getWebViewsMapping(this: AndroidDriver, opts: GetWebviewsOpts = {}): Promise<WebviewsMapping[]> {
|
|
157
150
|
const {
|
|
158
151
|
androidDeviceSocket = null,
|
|
159
152
|
ensureWebviewsHavePages = true,
|
|
@@ -241,9 +234,7 @@ export async function setupNewChromedriver(
|
|
|
241
234
|
): Promise<Chromedriver> {
|
|
242
235
|
// TODO: Remove the legacy
|
|
243
236
|
if ((opts as any).chromeDriverPort) {
|
|
244
|
-
this.log.warn(
|
|
245
|
-
`The 'chromeDriverPort' capability is deprecated. Please use 'chromedriverPort' instead`,
|
|
246
|
-
);
|
|
237
|
+
this.log.warn(`The 'chromeDriverPort' capability is deprecated. Please use 'chromedriverPort' instead`);
|
|
247
238
|
opts.chromedriverPort = (opts as any).chromeDriverPort;
|
|
248
239
|
}
|
|
249
240
|
|
|
@@ -256,10 +247,7 @@ export async function setupNewChromedriver(
|
|
|
256
247
|
|
|
257
248
|
const details = context ? getWebviewDetails(this.adb, context) : undefined;
|
|
258
249
|
if (!util.isEmpty(details)) {
|
|
259
|
-
this.log.debug(
|
|
260
|
-
'Passing web view details to the Chromedriver constructor: ' +
|
|
261
|
-
JSON.stringify(details, null, 2),
|
|
262
|
-
);
|
|
250
|
+
this.log.debug('Passing web view details to the Chromedriver constructor: ' + JSON.stringify(details, null, 2));
|
|
263
251
|
}
|
|
264
252
|
|
|
265
253
|
const chromedriverOpts: ChromedriverOpts & {details?: WebViewDetails} = {
|
|
@@ -297,17 +285,13 @@ export async function setupNewChromedriver(
|
|
|
297
285
|
// Strip the prefix and store it
|
|
298
286
|
for (const opt of Object.keys(opts)) {
|
|
299
287
|
if (opt.endsWith(':loggingPrefs')) {
|
|
300
|
-
this.log.warn(
|
|
301
|
-
`Merging '${opt}' into 'chromeLoggingPrefs'. This may cause unexpected behavior`,
|
|
302
|
-
);
|
|
288
|
+
this.log.warn(`Merging '${opt}' into 'chromeLoggingPrefs'. This may cause unexpected behavior`);
|
|
303
289
|
merge(opts.chromeLoggingPrefs, (opts as Record<string, any>)[opt]);
|
|
304
290
|
}
|
|
305
291
|
}
|
|
306
292
|
|
|
307
293
|
const caps = createChromedriverCaps.bind(this)(opts, curDeviceId, details) as any;
|
|
308
|
-
this.log.debug(
|
|
309
|
-
`Before starting chromedriver, androidPackage is '${caps.chromeOptions.androidPackage}'`,
|
|
310
|
-
);
|
|
294
|
+
this.log.debug(`Before starting chromedriver, androidPackage is '${caps.chromeOptions.androidPackage}'`);
|
|
311
295
|
// Optionally pre-grant all runtime permissions to the resolved Chrome package before Chrome
|
|
312
296
|
// is launched, so the session is not interrupted by a native permission dialog (geolocation,
|
|
313
297
|
// camera, file access, ...). Because the grant is requested explicitly, failures propagate.
|
|
@@ -453,9 +437,7 @@ function createChromedriverCaps(
|
|
|
453
437
|
const caps: any = {chromeOptions: {}};
|
|
454
438
|
|
|
455
439
|
const androidPackage =
|
|
456
|
-
opts.chromeOptions?.androidPackage ||
|
|
457
|
-
opts.appPackage ||
|
|
458
|
-
webViewDetails?.info?.['Android-Package'];
|
|
440
|
+
opts.chromeOptions?.androidPackage || opts.appPackage || webViewDetails?.info?.['Android-Package'];
|
|
459
441
|
if (androidPackage) {
|
|
460
442
|
// chromedriver raises an invalid argument error when androidPackage is 'null'
|
|
461
443
|
|
|
@@ -497,9 +479,7 @@ function createChromedriverCaps(
|
|
|
497
479
|
|
|
498
480
|
if (util.isPlainObject(opts.loggingPrefs) || util.isPlainObject(opts.chromeLoggingPrefs)) {
|
|
499
481
|
if (opts.loggingPrefs) {
|
|
500
|
-
this.log.warn(
|
|
501
|
-
`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`,
|
|
502
|
-
);
|
|
482
|
+
this.log.warn(`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`);
|
|
503
483
|
}
|
|
504
484
|
caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
|
|
505
485
|
}
|
|
@@ -523,9 +503,7 @@ function createChromedriverCaps(
|
|
|
523
503
|
caps.webSocketUrl = opts.webSocketUrl;
|
|
524
504
|
}
|
|
525
505
|
|
|
526
|
-
this.log.debug(
|
|
527
|
-
'Precalculated Chromedriver capabilities: ' + JSON.stringify(caps.chromeOptions, null, 2),
|
|
528
|
-
);
|
|
506
|
+
this.log.debug('Precalculated Chromedriver capabilities: ' + JSON.stringify(caps.chromeOptions, null, 2));
|
|
529
507
|
|
|
530
508
|
const protectedCapNames: string[] = [];
|
|
531
509
|
for (const [opt, val] of Object.entries(opts.chromeOptions)) {
|
|
@@ -536,10 +514,7 @@ function createChromedriverCaps(
|
|
|
536
514
|
}
|
|
537
515
|
}
|
|
538
516
|
if (!util.isEmpty(protectedCapNames)) {
|
|
539
|
-
this.log.info(
|
|
540
|
-
'The following Chromedriver capabilities cannot be overridden ' +
|
|
541
|
-
'by the provided chromeOptions:',
|
|
542
|
-
);
|
|
517
|
+
this.log.info('The following Chromedriver capabilities cannot be overridden by the provided chromeOptions:');
|
|
543
518
|
for (const optName of protectedCapNames) {
|
|
544
519
|
this.log.info(` ${optName} (${JSON.stringify(opts.chromeOptions[optName])})`);
|
|
545
520
|
}
|
|
@@ -570,14 +545,9 @@ async function allocateDevtoolsChannel(
|
|
|
570
545
|
endPort = webviewDevtoolsPort + (endPort - startPort);
|
|
571
546
|
startPort = webviewDevtoolsPort;
|
|
572
547
|
}
|
|
573
|
-
this.log.debug(
|
|
574
|
-
`Forwarding remote port ${remotePort} to a local ` + `port in range ${startPort}..${endPort}`,
|
|
575
|
-
);
|
|
548
|
+
this.log.debug(`Forwarding remote port ${remotePort} to a local port in range ${startPort}..${endPort}`);
|
|
576
549
|
if (!webviewDevtoolsPort) {
|
|
577
|
-
this.log.debug(
|
|
578
|
-
`You could use the 'webviewDevtoolsPort' capability to customize ` +
|
|
579
|
-
`the starting port number`,
|
|
580
|
-
);
|
|
550
|
+
this.log.debug(`You could use the 'webviewDevtoolsPort' capability to customize the starting port number`);
|
|
581
551
|
}
|
|
582
552
|
const port = await DEVTOOLS_PORT_ALLOCATION_GUARD(async () => {
|
|
583
553
|
let localPort: number;
|
|
@@ -616,11 +586,7 @@ async function collectWebviewsDetails(
|
|
|
616
586
|
return;
|
|
617
587
|
}
|
|
618
588
|
|
|
619
|
-
const {
|
|
620
|
-
webviewDevtoolsPort = null,
|
|
621
|
-
ensureWebviewsHavePages = null,
|
|
622
|
-
enableWebviewDetailsCollection = null,
|
|
623
|
-
} = opts;
|
|
589
|
+
const {webviewDevtoolsPort = null, ensureWebviewsHavePages = null, enableWebviewDetailsCollection = null} = opts;
|
|
624
590
|
|
|
625
591
|
if (!ensureWebviewsHavePages) {
|
|
626
592
|
this.log.info(
|
|
@@ -642,9 +608,7 @@ async function collectWebviewsDetails(
|
|
|
642
608
|
}
|
|
643
609
|
|
|
644
610
|
// Connect to each devtools socket and retrieve web view details
|
|
645
|
-
this.log.debug(
|
|
646
|
-
`Collecting CDP data of ${util.pluralize('webview', webviewsMapping.length, true)}`,
|
|
647
|
-
);
|
|
611
|
+
this.log.debug(`Collecting CDP data of ${util.pluralize('webview', webviewsMapping.length, true)}`);
|
|
648
612
|
const detailCollectors: Promise<void>[] = [];
|
|
649
613
|
for (const item of webviewsMapping) {
|
|
650
614
|
detailCollectors.push(
|
|
@@ -652,10 +616,7 @@ async function collectWebviewsDetails(
|
|
|
652
616
|
let port: number | undefined;
|
|
653
617
|
let host: string | undefined;
|
|
654
618
|
try {
|
|
655
|
-
[host, port] = (await allocateDevtoolsChannel.bind(this)(
|
|
656
|
-
item.proc,
|
|
657
|
-
webviewDevtoolsPort,
|
|
658
|
-
)) as [string, number];
|
|
619
|
+
[host, port] = (await allocateDevtoolsChannel.bind(this)(item.proc, webviewDevtoolsPort)) as [string, number];
|
|
659
620
|
if (enableWebviewDetailsCollection) {
|
|
660
621
|
item.info = await cdpInfo(host, port);
|
|
661
622
|
}
|
|
@@ -664,9 +625,7 @@ async function collectWebviewsDetails(
|
|
|
664
625
|
}
|
|
665
626
|
} catch (e) {
|
|
666
627
|
const err = e as Error;
|
|
667
|
-
this.log.info(
|
|
668
|
-
`CDP data for '${item.webview}' cannot be collected. Original error: ${err.message}`,
|
|
669
|
-
);
|
|
628
|
+
this.log.info(`CDP data for '${item.webview}' cannot be collected. Original error: ${err.message}`);
|
|
670
629
|
} finally {
|
|
671
630
|
if (port) {
|
|
672
631
|
try {
|
|
@@ -753,10 +712,7 @@ async function getPotentialWebviewProcs(this: AndroidDriver): Promise<string[]>
|
|
|
753
712
|
* @param deviceSocket - The explicitly-named device socket to use, or null to find all webviews
|
|
754
713
|
* @returns An array of webview process objects with proc and webview properties
|
|
755
714
|
*/
|
|
756
|
-
async function webviewsFromProcs(
|
|
757
|
-
this: AndroidDriver,
|
|
758
|
-
deviceSocket: string | null = null,
|
|
759
|
-
): Promise<WebviewProc[]> {
|
|
715
|
+
async function webviewsFromProcs(this: AndroidDriver, deviceSocket: string | null = null): Promise<WebviewProc[]> {
|
|
760
716
|
const socketNames = await getPotentialWebviewProcs.bind(this)();
|
|
761
717
|
const webviews: WebviewProc[] = [];
|
|
762
718
|
for (const socketName of socketNames) {
|
|
@@ -826,8 +782,7 @@ async function getChromedriverPort(this: AndroidDriver, portSpec?: PortSpec): Pr
|
|
|
826
782
|
|
|
827
783
|
if (foundPort === null) {
|
|
828
784
|
throw new Error(
|
|
829
|
-
`Could not find a free port for chromedriver using
|
|
830
|
-
`chromedriverPorts spec ${JSON.stringify(portSpec)}`,
|
|
785
|
+
`Could not find a free port for chromedriver using chromedriverPorts spec ${JSON.stringify(portSpec)}`,
|
|
831
786
|
);
|
|
832
787
|
}
|
|
833
788
|
|
|
@@ -846,11 +801,7 @@ function isChromedriverAutodownloadEnabled(this: AndroidDriver): boolean {
|
|
|
846
801
|
return false;
|
|
847
802
|
}
|
|
848
803
|
|
|
849
|
-
function cacheChromedriverCaps(
|
|
850
|
-
this: AndroidDriver,
|
|
851
|
-
sessionCaps: Record<string, any>,
|
|
852
|
-
context?: string,
|
|
853
|
-
): void {
|
|
804
|
+
function cacheChromedriverCaps(this: AndroidDriver, sessionCaps: Record<string, any>, context?: string): void {
|
|
854
805
|
if (!context) {
|
|
855
806
|
return;
|
|
856
807
|
}
|
|
@@ -872,9 +823,7 @@ function cacheChromedriverCaps(
|
|
|
872
823
|
*/
|
|
873
824
|
function isCompatibleCdpHost(host: string): boolean {
|
|
874
825
|
return (
|
|
875
|
-
['localhost', 'localhost.localdomain'].includes(host) ||
|
|
876
|
-
host.endsWith('.localhost') ||
|
|
877
|
-
Boolean(net.isIP(host))
|
|
826
|
+
['localhost', 'localhost.localdomain'].includes(host) || host.endsWith('.localhost') || Boolean(net.isIP(host))
|
|
878
827
|
);
|
|
879
828
|
}
|
|
880
829
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import * as semver from 'semver';
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
import type {ADB} from 'appium-adb';
|
|
4
|
+
import {retryInterval} from 'asyncbox';
|
|
4
5
|
import {SETTINGS_HELPER_ID} from 'io.appium.settings';
|
|
6
|
+
import * as semver from 'semver';
|
|
7
|
+
|
|
8
|
+
import type {AndroidDriver} from '../../driver.js';
|
|
9
|
+
import {GET_SERVER_LOGS_FEATURE, nativeLogEntryToSeleniumEntry} from '../../utils.js';
|
|
10
|
+
import {setMockLocationApp} from '../geolocation.js';
|
|
5
11
|
import {hideKeyboardCompletely, initUnicodeKeyboard} from '../keyboard.js';
|
|
6
|
-
import {createBaseADB, prepareEmulator, pushSettingsApp} from './utils.js';
|
|
7
12
|
import {adjustTimeZone} from '../time.js';
|
|
8
|
-
import {retryInterval} from 'asyncbox';
|
|
9
|
-
import {GET_SERVER_LOGS_FEATURE, nativeLogEntryToSeleniumEntry} from '../../utils.js';
|
|
10
|
-
import type {AndroidDriver} from '../../driver.js';
|
|
11
13
|
import type {ADBDeviceInfo, ADBLaunchInfo} from '../types.js';
|
|
12
|
-
import
|
|
14
|
+
import {createBaseADB, prepareEmulator, pushSettingsApp} from './utils.js';
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Gets device information from capabilities, including UDID and emulator port.
|
|
@@ -38,9 +40,7 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
|
|
|
38
40
|
// udid was given, lets try to init with that device
|
|
39
41
|
if (udid) {
|
|
40
42
|
if (!devices?.some((device) => device.udid === udid)) {
|
|
41
|
-
throw this.log.errorWithException(
|
|
42
|
-
`Device ${udid} was not in the list of connected devices`,
|
|
43
|
-
);
|
|
43
|
+
throw this.log.errorWithException(`Device ${udid} was not in the list of connected devices`);
|
|
44
44
|
}
|
|
45
45
|
emPort = adb.getPortFromEmulatorString(udid);
|
|
46
46
|
} else if (this.opts.platformVersion) {
|
|
@@ -71,11 +71,9 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
|
|
|
71
71
|
const semverDO = deviceOS;
|
|
72
72
|
|
|
73
73
|
const bothVersionsCanBeCoerced = semver.valid(deviceOS) && semver.valid(platformVersion);
|
|
74
|
-
const bothVersionsAreStrings =
|
|
75
|
-
typeof deviceOS === 'string' && typeof platformVersion === 'string';
|
|
74
|
+
const bothVersionsAreStrings = typeof deviceOS === 'string' && typeof platformVersion === 'string';
|
|
76
75
|
if (
|
|
77
|
-
(bothVersionsCanBeCoerced &&
|
|
78
|
-
(semverDO as semver.SemVer).version === (semverPV as semver.SemVer).version) ||
|
|
76
|
+
(bothVersionsCanBeCoerced && (semverDO as semver.SemVer).version === (semverPV as semver.SemVer).version) ||
|
|
79
77
|
(bothVersionsAreStrings && deviceOS.toLowerCase() === platformVersion.toLowerCase())
|
|
80
78
|
) {
|
|
81
79
|
// Got an exact match - proceed immediately
|
|
@@ -95,8 +93,7 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
|
|
|
95
93
|
(pvMajor === dvMajor && pvMinor === dvMinor)) &&
|
|
96
94
|
// Got a partial match - make sure we consider the most recent
|
|
97
95
|
// device version available on the host system
|
|
98
|
-
((partialMatchCandidate &&
|
|
99
|
-
semver.gt(deviceOS, Object.values(partialMatchCandidate)[0])) ||
|
|
96
|
+
((partialMatchCandidate && semver.gt(deviceOS, Object.values(partialMatchCandidate)[0])) ||
|
|
100
97
|
!partialMatchCandidate)
|
|
101
98
|
) {
|
|
102
99
|
partialMatchCandidate = {[device.udid]: deviceOS};
|
|
@@ -168,9 +165,7 @@ export async function getLaunchInfo(this: AndroidDriver): Promise<ADBLaunchInfo
|
|
|
168
165
|
let apkPackage: string | undefined;
|
|
169
166
|
let apkActivity: string | undefined;
|
|
170
167
|
if (appOpt) {
|
|
171
|
-
this.log.debug(
|
|
172
|
-
`Parsing package and activity from the '${path.basename(appOpt)}' file manifest`,
|
|
173
|
-
);
|
|
168
|
+
this.log.debug(`Parsing package and activity from the '${path.basename(appOpt)}' file manifest`);
|
|
174
169
|
({apkPackage, apkActivity} = await this.adb.packageAndLaunchActivityFromManifest(appOpt));
|
|
175
170
|
} else if (appPackage) {
|
|
176
171
|
this.log.debug(`Parsing activity from the installed '${appPackage}' package manifest`);
|
|
@@ -238,18 +233,10 @@ export async function initDevice(this: AndroidDriver): Promise<void> {
|
|
|
238
233
|
`device provisioning, or unset the capability to let the driver install it.`,
|
|
239
234
|
);
|
|
240
235
|
}
|
|
241
|
-
this.log.info(
|
|
242
|
-
`'skipSettingsAppReinstall' is set; using the already-installed Appium Settings helper app as-is.`,
|
|
243
|
-
);
|
|
236
|
+
this.log.info(`'skipSettingsAppReinstall' is set; using the already-installed Appium Settings helper app as-is.`);
|
|
244
237
|
} else {
|
|
245
238
|
const shouldThrowError = Boolean(
|
|
246
|
-
language ||
|
|
247
|
-
locale ||
|
|
248
|
-
localeScript ||
|
|
249
|
-
unicodeKeyboard ||
|
|
250
|
-
hideKeyboard ||
|
|
251
|
-
disableWindowAnimation ||
|
|
252
|
-
!skipUnlock,
|
|
239
|
+
language || locale || localeScript || unicodeKeyboard || hideKeyboard || disableWindowAnimation || !skipUnlock,
|
|
253
240
|
);
|
|
254
241
|
await pushSettingsApp.bind(this)(shouldThrowError);
|
|
255
242
|
}
|