appium-android-driver 13.3.1 → 13.3.3
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.map +1 -1
- package/build/lib/commands/app-management.js +13 -12
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/bidi/models.d.ts.map +1 -1
- package/build/lib/commands/bidi/models.js +1 -5
- 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 +1 -5
- package/build/lib/commands/bluetooth.js.map +1 -1
- package/build/lib/commands/context/exports.d.ts.map +1 -1
- package/build/lib/commands/context/exports.js +11 -15
- 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 +43 -22
- package/build/lib/commands/context/helpers.js.map +1 -1
- package/build/lib/commands/device/common.d.ts.map +1 -1
- package/build/lib/commands/device/common.js +9 -8
- package/build/lib/commands/device/common.js.map +1 -1
- package/build/lib/commands/device/utils.d.ts.map +1 -1
- package/build/lib/commands/device/utils.js +2 -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 +2 -6
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +2 -6
- 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 +2 -3
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +4 -7
- 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 +3 -4
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/image-injection.d.ts.map +1 -1
- package/build/lib/commands/image-injection.js +1 -2
- package/build/lib/commands/image-injection.js.map +1 -1
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +14 -18
- 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 +6 -6
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts.map +1 -1
- package/build/lib/commands/lock/exports.js +1 -5
- 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 +5 -9
- package/build/lib/commands/lock/helpers.js.map +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +9 -9
- 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 +5 -6
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +12 -16
- 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 +1 -5
- 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 +7 -12
- 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 +21 -23
- 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 +10 -11
- 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 +6 -10
- 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 +7 -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 +14 -15
- 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 +19 -21
- 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 +23 -8
- package/build/lib/commands/time.js.map +1 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +2 -6
- package/build/lib/driver.js.map +1 -1
- package/build/lib/logger.d.ts +2 -1
- package/build/lib/logger.d.ts.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +9 -12
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.ts +19 -9
- package/lib/commands/bidi/models.ts +1 -2
- package/lib/commands/bluetooth.ts +1 -2
- package/lib/commands/context/exports.ts +12 -14
- package/lib/commands/context/helpers.ts +47 -22
- package/lib/commands/device/common.ts +10 -8
- package/lib/commands/device/utils.ts +2 -3
- package/lib/commands/deviceidle.ts +2 -3
- package/lib/commands/execute.ts +2 -3
- package/lib/commands/file-actions.ts +2 -3
- package/lib/commands/find.ts +4 -5
- package/lib/commands/geolocation.ts +3 -4
- package/lib/commands/image-injection.ts +1 -2
- package/lib/commands/intent.ts +14 -15
- package/lib/commands/keyboard.ts +6 -3
- package/lib/commands/lock/exports.ts +1 -2
- package/lib/commands/lock/helpers.ts +5 -6
- package/lib/commands/log.ts +9 -9
- package/lib/commands/media-projection.ts +5 -6
- package/lib/commands/network.ts +12 -13
- package/lib/commands/nfc.ts +1 -2
- package/lib/commands/performance.ts +7 -11
- package/lib/commands/permissions.ts +23 -20
- package/lib/commands/recordscreen.ts +10 -11
- package/lib/commands/resources.ts +7 -8
- package/lib/commands/shell.ts +7 -3
- package/lib/commands/streamscreen.ts +14 -16
- package/lib/commands/system-bars.ts +20 -20
- package/lib/commands/time.ts +26 -8
- package/lib/driver.ts +2 -4
- package/lib/logger.ts +2 -1
- package/lib/utils.ts +9 -9
- package/package.json +2 -5
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {fs, logger, system, util} from '@appium/support';
|
|
2
2
|
import {waitForCondition} from 'asyncbox';
|
|
3
|
-
import _ from 'lodash';
|
|
4
3
|
import {spawn} from 'node:child_process';
|
|
5
4
|
import http from 'node:http';
|
|
6
5
|
import net from 'node:net';
|
|
@@ -89,10 +88,9 @@ export async function mobileStartScreenStreaming(
|
|
|
89
88
|
): Promise<void> {
|
|
90
89
|
this.assertFeatureEnabled(ADB_SCREEN_STREAMING_FEATURE);
|
|
91
90
|
|
|
92
|
-
if (
|
|
91
|
+
if (this._screenStreamingProps === undefined) {
|
|
93
92
|
await verifyStreamingRequirements(this.adb);
|
|
94
|
-
}
|
|
95
|
-
if (!_.isEmpty(this._screenStreamingProps)) {
|
|
93
|
+
} else {
|
|
96
94
|
this.log.info(
|
|
97
95
|
`The screen streaming session is already running. ` +
|
|
98
96
|
`Stop it first in order to start a new one.`,
|
|
@@ -246,8 +244,8 @@ export async function mobileStartScreenStreaming(
|
|
|
246
244
|
* If no streaming session is active, this method returns without error.
|
|
247
245
|
*/
|
|
248
246
|
export async function mobileStopScreenStreaming(this: AndroidDriver): Promise<void> {
|
|
249
|
-
if (
|
|
250
|
-
if (
|
|
247
|
+
if (!this._screenStreamingProps) {
|
|
248
|
+
if (this._screenStreamingProps !== undefined) {
|
|
251
249
|
this.log.debug(`Screen streaming is not running. There is nothing to stop`);
|
|
252
250
|
}
|
|
253
251
|
return;
|
|
@@ -287,7 +285,7 @@ export async function mobileStopScreenStreaming(this: AndroidDriver): Promise<vo
|
|
|
287
285
|
function createStreamingLogger(streamName: string, udid: string): AppiumLogger {
|
|
288
286
|
return logger.getLogger(
|
|
289
287
|
`${streamName}@` +
|
|
290
|
-
|
|
288
|
+
util.truncateString(udid, {
|
|
291
289
|
length: 8,
|
|
292
290
|
omission: '',
|
|
293
291
|
}),
|
|
@@ -295,7 +293,7 @@ function createStreamingLogger(streamName: string, udid: string): AppiumLogger {
|
|
|
295
293
|
}
|
|
296
294
|
|
|
297
295
|
async function verifyStreamingRequirements(adb: ADB): Promise<void> {
|
|
298
|
-
if (!
|
|
296
|
+
if (!(await adb.shell(['which', SCREENRECORD_BINARY])).trim()) {
|
|
299
297
|
throw new Error(
|
|
300
298
|
`The required '${SCREENRECORD_BINARY}' binary is not available on the device under test`,
|
|
301
299
|
);
|
|
@@ -319,11 +317,11 @@ async function verifyStreamingRequirements(adb: ADB): Promise<void> {
|
|
|
319
317
|
await Promise.all(gstreamerCheckPromises);
|
|
320
318
|
|
|
321
319
|
const moduleCheckPromises: Promise<void>[] = [];
|
|
322
|
-
for (const [name, modName] of
|
|
320
|
+
for (const [name, modName] of Object.entries(REQUIRED_GST_PLUGINS)) {
|
|
323
321
|
moduleCheckPromises.push(
|
|
324
322
|
(async () => {
|
|
325
323
|
const {stdout} = await exec(GST_INSPECT_BINARY, [name]);
|
|
326
|
-
if (!
|
|
324
|
+
if (!stdout?.includes(modName)) {
|
|
327
325
|
throw new Error(
|
|
328
326
|
`The required GStreamer plugin '${name}' from '${modName}' module is not installed. ` +
|
|
329
327
|
`See ${GST_TUTORIAL_URL} for more details on how to install it.`,
|
|
@@ -366,9 +364,9 @@ async function initDeviceStreamingProc(
|
|
|
366
364
|
opts: {width?: string | number; height?: string | number; bitRate?: string | number} = {},
|
|
367
365
|
): Promise<ReturnType<typeof spawn>> {
|
|
368
366
|
const {width, height, bitRate} = opts;
|
|
369
|
-
const adjustedWidth =
|
|
370
|
-
const adjustedHeight =
|
|
371
|
-
const adjustedBitrate =
|
|
367
|
+
const adjustedWidth = width === undefined ? deviceInfo.width : parseInt(String(width), 10);
|
|
368
|
+
const adjustedHeight = height === undefined ? deviceInfo.height : parseInt(String(height), 10);
|
|
369
|
+
const adjustedBitrate = bitRate === undefined ? DEFAULT_BITRATE : parseInt(String(bitRate), 10);
|
|
372
370
|
let screenRecordCmd =
|
|
373
371
|
SCREENRECORD_BINARY +
|
|
374
372
|
` --output-format=h264` +
|
|
@@ -396,7 +394,7 @@ async function initDeviceStreamingProc(
|
|
|
396
394
|
const deviceStreamingLogger = createStreamingLogger(SCREENRECORD_BINARY, deviceInfo.udid);
|
|
397
395
|
const errorsListener = (chunk: Buffer | string) => {
|
|
398
396
|
const stderr = chunk.toString();
|
|
399
|
-
if (
|
|
397
|
+
if (stderr?.trim()) {
|
|
400
398
|
deviceStreamingLogger.debug(stderr);
|
|
401
399
|
}
|
|
402
400
|
};
|
|
@@ -404,7 +402,7 @@ async function initDeviceStreamingProc(
|
|
|
404
402
|
|
|
405
403
|
const startupListener = (chunk: Buffer | string) => {
|
|
406
404
|
if (!isStarted) {
|
|
407
|
-
isStarted = !
|
|
405
|
+
isStarted = !util.isEmpty(chunk);
|
|
408
406
|
}
|
|
409
407
|
};
|
|
410
408
|
deviceStreaming.stdout.on('data', startupListener);
|
|
@@ -477,7 +475,7 @@ async function initGstreamerPipeline(
|
|
|
477
475
|
});
|
|
478
476
|
const gstreamerLogger = createStreamingLogger('gst', deviceInfo.udid);
|
|
479
477
|
const gstOutputListener = (stdout: string, stderr: string) => {
|
|
480
|
-
if (
|
|
478
|
+
if ((stderr || stdout)?.trim()) {
|
|
481
479
|
gstreamerLogger.debug(stderr || stdout);
|
|
482
480
|
}
|
|
483
481
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {errors} from 'appium/driver';
|
|
2
|
-
import _ from 'lodash';
|
|
3
2
|
import type {StringRecord} from '@appium/types';
|
|
4
3
|
import type {AndroidDriver} from '../driver';
|
|
5
4
|
import type {StatusBarCommand, WindowProperties} from './types';
|
|
5
|
+
import {util} from '@appium/support';
|
|
6
6
|
|
|
7
7
|
const WINDOW_TITLE_PATTERN = /^\s+Window\s#\d+\sWindow\{[0-9a-f]+\s\w+\s([\w-]+)\}:$/;
|
|
8
8
|
const FRAME_PATTERN = /\bm?[Ff]rame=\[([0-9.-]+),([0-9.-]+)\]\[([0-9.-]+),([0-9.-]+)\]/;
|
|
@@ -64,15 +64,15 @@ export async function mobilePerformStatusBarCommand(
|
|
|
64
64
|
component?: string,
|
|
65
65
|
): Promise<string> {
|
|
66
66
|
const toStatusBarCommandCallable =
|
|
67
|
-
(cmd: string, argsCallable?: () => string[] | string) => async (): Promise<string> =>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
(cmd: string, argsCallable?: () => string[] | string) => async (): Promise<string> => {
|
|
68
|
+
let argsCallableArray = argsCallable ? argsCallable() : [];
|
|
69
|
+
if (!Array.isArray(argsCallableArray)) {
|
|
70
|
+
argsCallableArray = [argsCallableArray];
|
|
71
|
+
}
|
|
72
|
+
return await this.adb.shell(['cmd', 'statusbar', cmd, ...argsCallableArray]);
|
|
73
|
+
};
|
|
74
74
|
const tileCommandArgsCallable = () => component as string;
|
|
75
|
-
const statusBarCommands =
|
|
75
|
+
const statusBarCommands = Object.fromEntries(
|
|
76
76
|
(
|
|
77
77
|
[
|
|
78
78
|
['expandNotifications', ['expand-notifications']],
|
|
@@ -90,7 +90,7 @@ export async function mobilePerformStatusBarCommand(
|
|
|
90
90
|
if (!action) {
|
|
91
91
|
throw new errors.InvalidArgumentError(
|
|
92
92
|
`The '${command}' status bar command is unknown. Only the following commands ` +
|
|
93
|
-
`are supported: ${
|
|
93
|
+
`are supported: ${Object.keys(statusBarCommands)}`,
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
96
|
return await action();
|
|
@@ -110,7 +110,7 @@ export function parseWindowProperties(
|
|
|
110
110
|
name: string,
|
|
111
111
|
props: string[],
|
|
112
112
|
): WindowProperties {
|
|
113
|
-
const result =
|
|
113
|
+
const result = structuredClone(DEFAULT_WINDOW_PROPERTIES);
|
|
114
114
|
const propLines = props.join('\n');
|
|
115
115
|
const frameMatch = FRAME_PATTERN.exec(propLines);
|
|
116
116
|
if (!frameMatch) {
|
|
@@ -142,29 +142,29 @@ export function parseWindowProperties(
|
|
|
142
142
|
export function parseWindows(this: AndroidDriver, lines: string): SystemBarsResult {
|
|
143
143
|
const windows: StringRecord<string[]> = {};
|
|
144
144
|
let currentWindowName: string | null = null;
|
|
145
|
-
for (const line of lines.split('\n').map(
|
|
146
|
-
const match = WINDOW_TITLE_PATTERN.exec(line);
|
|
145
|
+
for (const line of lines.split('\n').map((line) => String(line)?.trimEnd())) {
|
|
146
|
+
const match = WINDOW_TITLE_PATTERN.exec(line as any);
|
|
147
147
|
if (match) {
|
|
148
148
|
currentWindowName = match[1];
|
|
149
149
|
windows[currentWindowName] = [];
|
|
150
150
|
continue;
|
|
151
151
|
}
|
|
152
|
-
if (
|
|
152
|
+
if (String(line)?.trim()?.length === 0) {
|
|
153
153
|
currentWindowName = null;
|
|
154
154
|
continue;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
if (currentWindowName &&
|
|
157
|
+
if (currentWindowName && Array.isArray(windows[currentWindowName])) {
|
|
158
158
|
windows[currentWindowName].push(line);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
if (
|
|
161
|
+
if (util.isEmpty(windows)) {
|
|
162
162
|
this.log.debug(lines);
|
|
163
163
|
throw new Error('Cannot parse any window information from the dumpsys output');
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
const result: SystemBarsResult = {};
|
|
167
|
-
for (const [name, props] of
|
|
167
|
+
for (const [name, props] of Object.entries(windows)) {
|
|
168
168
|
if (
|
|
169
169
|
name.startsWith(STATUS_BAR_WINDOW_NAME_PREFIX) ||
|
|
170
170
|
props.some((line: string) => STATUS_BAR_TYPE_PATTERN.test(line))
|
|
@@ -182,14 +182,14 @@ export function parseWindows(this: AndroidDriver, lines: string): SystemBarsResu
|
|
|
182
182
|
['statusBar', STATUS_BAR_WINDOW_NAME_PREFIX],
|
|
183
183
|
['navigationBar', NAVIGATION_BAR_WINDOW_NAME_PREFIX],
|
|
184
184
|
] as const
|
|
185
|
-
).filter(([name]) =>
|
|
185
|
+
).filter(([name]) => result[name as keyof SystemBarsResult] == null);
|
|
186
186
|
for (const [window, namePrefix] of unmatchedWindows) {
|
|
187
187
|
this.log.info(
|
|
188
188
|
`No windows have been found whose title matches to ` +
|
|
189
189
|
`'${namePrefix}'. Assuming it is invisible. ` +
|
|
190
|
-
`Only the following windows are available: ${
|
|
190
|
+
`Only the following windows are available: ${Object.keys(windows)}`,
|
|
191
191
|
);
|
|
192
|
-
result[window as keyof SystemBarsResult] =
|
|
192
|
+
result[window as keyof SystemBarsResult] = structuredClone(DEFAULT_WINDOW_PROPERTIES);
|
|
193
193
|
}
|
|
194
194
|
return result;
|
|
195
195
|
}
|
package/lib/commands/time.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import utc from 'dayjs/plugin/utc';
|
|
3
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
2
4
|
import type {AndroidDriver} from '../driver';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
dayjs.extend(utc);
|
|
7
|
+
dayjs.extend(customParseFormat);
|
|
8
|
+
|
|
9
|
+
const DATETIME_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* Gets the current device time.
|
|
@@ -11,20 +16,20 @@ const MOMENT_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ';
|
|
|
11
16
|
*/
|
|
12
17
|
export async function getDeviceTime(
|
|
13
18
|
this: AndroidDriver,
|
|
14
|
-
format: string =
|
|
19
|
+
format: string = DATETIME_FORMAT_ISO8601,
|
|
15
20
|
): Promise<string> {
|
|
16
21
|
this.log.debug(
|
|
17
|
-
|
|
22
|
+
`Attempting to capture Android device date and time. The format specifier is '${format}'`,
|
|
18
23
|
);
|
|
19
24
|
const deviceTimestamp = (await this.adb.shell(['date', '+%Y-%m-%dT%T%z'])).trim();
|
|
20
25
|
this.log.debug(`Got device timestamp: ${deviceTimestamp}`);
|
|
21
|
-
const parsedTimestamp =
|
|
26
|
+
const parsedTimestamp = dayjs.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
|
|
22
27
|
if (!parsedTimestamp.isValid()) {
|
|
23
28
|
this.log.warn('Cannot parse the returned timestamp. Returning as is');
|
|
24
29
|
return deviceTimestamp;
|
|
25
30
|
}
|
|
26
|
-
|
|
27
|
-
return parsedTimestamp.utcOffset(
|
|
31
|
+
const offset = parseOffset(deviceTimestamp);
|
|
32
|
+
return parsedTimestamp.utcOffset(offset).format(format);
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
/**
|
|
@@ -45,7 +50,7 @@ export async function mobileGetDeviceTime(this: AndroidDriver, format?: string):
|
|
|
45
50
|
* @throws {Error} If the time zone identifier is not known.
|
|
46
51
|
*/
|
|
47
52
|
export async function adjustTimeZone(this: AndroidDriver, zoneName: string): Promise<void> {
|
|
48
|
-
if (!
|
|
53
|
+
if (!isValidTimeZone(zoneName)) {
|
|
49
54
|
throw new Error(
|
|
50
55
|
`The provided time zone identifier '${zoneName}' is not known. ` +
|
|
51
56
|
`Please choose a valid TZ identifier from https://en.wikipedia.org/wiki/List_of_tz_database_time_zones`,
|
|
@@ -59,3 +64,16 @@ export async function adjustTimeZone(this: AndroidDriver, zoneName: string): Pro
|
|
|
59
64
|
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/apex/jobscheduler/framework/java/android/app/IAlarmManager.aidl;l=1?q=IAlarmManager
|
|
60
65
|
await this.adb.shell(['service', 'call', 'alarm', '3', 's16', zoneName]);
|
|
61
66
|
}
|
|
67
|
+
|
|
68
|
+
function parseOffset(timestamp: string): number {
|
|
69
|
+
const m = timestamp.match(/([+-])(\d{2})(\d{2})$/);
|
|
70
|
+
if (!m) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
const sign = m[1] === '+' ? 1 : -1;
|
|
74
|
+
return sign * (Number(m[2]) * 60 + Number(m[3]));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isValidTimeZone(zoneName: string): boolean {
|
|
78
|
+
return Intl.supportedValuesOf('timeZone').includes(zoneName);
|
|
79
|
+
}
|
package/lib/driver.ts
CHANGED
|
@@ -7,7 +7,6 @@ import type {
|
|
|
7
7
|
StringRecord,
|
|
8
8
|
W3CDriverCaps,
|
|
9
9
|
} from '@appium/types';
|
|
10
|
-
import _ from 'lodash';
|
|
11
10
|
import type {ADB, LogcatListener} from 'appium-adb';
|
|
12
11
|
import type {default as AppiumChromedriver} from 'appium-chromedriver';
|
|
13
12
|
import {BaseDriver} from 'appium/driver';
|
|
@@ -462,7 +461,7 @@ class AndroidDriver
|
|
|
462
461
|
'accessibility id',
|
|
463
462
|
'-android uiautomator',
|
|
464
463
|
];
|
|
465
|
-
this.desiredCapConstraints =
|
|
464
|
+
this.desiredCapConstraints = structuredClone(ANDROID_DRIVER_CONSTRAINTS);
|
|
466
465
|
this.sessionChromedrivers = {};
|
|
467
466
|
this.jwpProxyActive = false;
|
|
468
467
|
|
|
@@ -483,8 +482,7 @@ class AndroidDriver
|
|
|
483
482
|
}
|
|
484
483
|
|
|
485
484
|
get isChromeSession(): boolean {
|
|
486
|
-
return
|
|
487
|
-
Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY),
|
|
485
|
+
return Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY).includes(
|
|
488
486
|
(this.opts.browserName || '').toLowerCase(),
|
|
489
487
|
);
|
|
490
488
|
}
|
package/lib/logger.ts
CHANGED
package/lib/utils.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
1
|
import {errors} from 'appium/driver';
|
|
3
2
|
import type {LogEntry} from 'appium-adb';
|
|
4
3
|
import type {AndroidDriver} from './driver';
|
|
4
|
+
import {util} from '@appium/support';
|
|
5
5
|
|
|
6
6
|
export type {LogEntry};
|
|
7
7
|
|
|
@@ -29,8 +29,8 @@ export function requireArgs(
|
|
|
29
29
|
argNames: string | string[],
|
|
30
30
|
opts: Record<string, any>,
|
|
31
31
|
): Record<string, any> {
|
|
32
|
-
for (const argName of
|
|
33
|
-
if (!
|
|
32
|
+
for (const argName of Array.isArray(argNames) ? argNames : [argNames]) {
|
|
33
|
+
if (util.isPlainObject(opts) && !Object.hasOwn(opts, argName)) {
|
|
34
34
|
throw new errors.InvalidArgumentError(`'${argName}' argument must be provided`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -48,9 +48,9 @@ export function parseArray(cap: string | string[]): string[] {
|
|
|
48
48
|
parsedCaps = JSON.parse(cap as string);
|
|
49
49
|
} catch {}
|
|
50
50
|
|
|
51
|
-
if (
|
|
51
|
+
if (Array.isArray(parsedCaps)) {
|
|
52
52
|
return parsedCaps;
|
|
53
|
-
} else if (
|
|
53
|
+
} else if (typeof cap === 'string') {
|
|
54
54
|
return [cap];
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -62,12 +62,12 @@ export function parseArray(cap: string | string[]): string[] {
|
|
|
62
62
|
* @returns
|
|
63
63
|
*/
|
|
64
64
|
export async function removeAllSessionWebSocketHandlers(this: AndroidDriver): Promise<void> {
|
|
65
|
-
if (!this.sessionId ||
|
|
65
|
+
if (!this.sessionId || typeof this.server?.getWebSocketHandlers !== 'function') {
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
const activeHandlers = await this.server.getWebSocketHandlers(this.sessionId);
|
|
70
|
-
for (const pathname of
|
|
70
|
+
for (const pathname of Object.keys(activeHandlers)) {
|
|
71
71
|
await this.server.removeWebSocketHandler(pathname);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -78,8 +78,8 @@ export async function removeAllSessionWebSocketHandlers(this: AndroidDriver): Pr
|
|
|
78
78
|
* @returns
|
|
79
79
|
*/
|
|
80
80
|
export function nativeLogEntryToSeleniumEntry(x: LogEntryWithPrefix): LogEntry {
|
|
81
|
-
const msg =
|
|
82
|
-
return toLogRecord(x.timestamp ?? Date.now(),
|
|
81
|
+
const msg = util.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
|
|
82
|
+
return toLogRecord(x.timestamp ?? Date.now(), msg.replace(COLOR_CODE_PATTERN, ''));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-android-driver",
|
|
3
|
-
"version": "13.3.
|
|
3
|
+
"version": "13.3.3",
|
|
4
4
|
"description": "Android UiAutomator and Chrome support for Appium",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"appium",
|
|
@@ -52,11 +52,9 @@
|
|
|
52
52
|
"appium-chromedriver": "^8.4.4",
|
|
53
53
|
"asyncbox": "^6.1.0",
|
|
54
54
|
"axios": "^1.16.0",
|
|
55
|
+
"dayjs": "^1.11.21",
|
|
55
56
|
"io.appium.settings": "^7.1.3",
|
|
56
|
-
"lodash": "^4.17.4",
|
|
57
57
|
"lru-cache": "^11.1.0",
|
|
58
|
-
"moment": "^2.24.0",
|
|
59
|
-
"moment-timezone": "^0.x",
|
|
60
58
|
"portscanner": "^2.2.0",
|
|
61
59
|
"semver": "^7.0.0",
|
|
62
60
|
"teen_process": "^4.0.7",
|
|
@@ -70,7 +68,6 @@
|
|
|
70
68
|
"@semantic-release/git": "^10.0.1",
|
|
71
69
|
"@types/chai": "^5.2.3",
|
|
72
70
|
"@types/chai-as-promised": "^8.0.2",
|
|
73
|
-
"@types/lodash": "^4.14.194",
|
|
74
71
|
"@types/mocha": "^10.0.1",
|
|
75
72
|
"@types/node": "^26.0.0",
|
|
76
73
|
"@types/portscanner": "^2.1.1",
|