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.
Files changed (130) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/app-management.d.ts.map +1 -1
  3. package/build/lib/commands/app-management.js +13 -12
  4. package/build/lib/commands/app-management.js.map +1 -1
  5. package/build/lib/commands/bidi/models.d.ts.map +1 -1
  6. package/build/lib/commands/bidi/models.js +1 -5
  7. package/build/lib/commands/bidi/models.js.map +1 -1
  8. package/build/lib/commands/bluetooth.d.ts.map +1 -1
  9. package/build/lib/commands/bluetooth.js +1 -5
  10. package/build/lib/commands/bluetooth.js.map +1 -1
  11. package/build/lib/commands/context/exports.d.ts.map +1 -1
  12. package/build/lib/commands/context/exports.js +11 -15
  13. package/build/lib/commands/context/exports.js.map +1 -1
  14. package/build/lib/commands/context/helpers.d.ts.map +1 -1
  15. package/build/lib/commands/context/helpers.js +43 -22
  16. package/build/lib/commands/context/helpers.js.map +1 -1
  17. package/build/lib/commands/device/common.d.ts.map +1 -1
  18. package/build/lib/commands/device/common.js +9 -8
  19. package/build/lib/commands/device/common.js.map +1 -1
  20. package/build/lib/commands/device/utils.d.ts.map +1 -1
  21. package/build/lib/commands/device/utils.js +2 -6
  22. package/build/lib/commands/device/utils.js.map +1 -1
  23. package/build/lib/commands/deviceidle.d.ts.map +1 -1
  24. package/build/lib/commands/deviceidle.js +2 -6
  25. package/build/lib/commands/deviceidle.js.map +1 -1
  26. package/build/lib/commands/execute.d.ts.map +1 -1
  27. package/build/lib/commands/execute.js +2 -6
  28. package/build/lib/commands/execute.js.map +1 -1
  29. package/build/lib/commands/file-actions.d.ts.map +1 -1
  30. package/build/lib/commands/file-actions.js +2 -3
  31. package/build/lib/commands/file-actions.js.map +1 -1
  32. package/build/lib/commands/find.d.ts.map +1 -1
  33. package/build/lib/commands/find.js +4 -7
  34. package/build/lib/commands/find.js.map +1 -1
  35. package/build/lib/commands/geolocation.d.ts.map +1 -1
  36. package/build/lib/commands/geolocation.js +3 -4
  37. package/build/lib/commands/geolocation.js.map +1 -1
  38. package/build/lib/commands/image-injection.d.ts.map +1 -1
  39. package/build/lib/commands/image-injection.js +1 -2
  40. package/build/lib/commands/image-injection.js.map +1 -1
  41. package/build/lib/commands/intent.d.ts.map +1 -1
  42. package/build/lib/commands/intent.js +14 -18
  43. package/build/lib/commands/intent.js.map +1 -1
  44. package/build/lib/commands/keyboard.d.ts.map +1 -1
  45. package/build/lib/commands/keyboard.js +6 -6
  46. package/build/lib/commands/keyboard.js.map +1 -1
  47. package/build/lib/commands/lock/exports.d.ts.map +1 -1
  48. package/build/lib/commands/lock/exports.js +1 -5
  49. package/build/lib/commands/lock/exports.js.map +1 -1
  50. package/build/lib/commands/lock/helpers.d.ts.map +1 -1
  51. package/build/lib/commands/lock/helpers.js +5 -9
  52. package/build/lib/commands/lock/helpers.js.map +1 -1
  53. package/build/lib/commands/log.d.ts.map +1 -1
  54. package/build/lib/commands/log.js +9 -9
  55. package/build/lib/commands/log.js.map +1 -1
  56. package/build/lib/commands/media-projection.d.ts.map +1 -1
  57. package/build/lib/commands/media-projection.js +5 -6
  58. package/build/lib/commands/media-projection.js.map +1 -1
  59. package/build/lib/commands/network.d.ts.map +1 -1
  60. package/build/lib/commands/network.js +12 -16
  61. package/build/lib/commands/network.js.map +1 -1
  62. package/build/lib/commands/nfc.d.ts.map +1 -1
  63. package/build/lib/commands/nfc.js +1 -5
  64. package/build/lib/commands/nfc.js.map +1 -1
  65. package/build/lib/commands/performance.d.ts.map +1 -1
  66. package/build/lib/commands/performance.js +7 -12
  67. package/build/lib/commands/performance.js.map +1 -1
  68. package/build/lib/commands/permissions.d.ts.map +1 -1
  69. package/build/lib/commands/permissions.js +21 -23
  70. package/build/lib/commands/permissions.js.map +1 -1
  71. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  72. package/build/lib/commands/recordscreen.js +10 -11
  73. package/build/lib/commands/recordscreen.js.map +1 -1
  74. package/build/lib/commands/resources.d.ts.map +1 -1
  75. package/build/lib/commands/resources.js +6 -10
  76. package/build/lib/commands/resources.js.map +1 -1
  77. package/build/lib/commands/shell.d.ts.map +1 -1
  78. package/build/lib/commands/shell.js +7 -6
  79. package/build/lib/commands/shell.js.map +1 -1
  80. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  81. package/build/lib/commands/streamscreen.js +14 -15
  82. package/build/lib/commands/streamscreen.js.map +1 -1
  83. package/build/lib/commands/system-bars.d.ts.map +1 -1
  84. package/build/lib/commands/system-bars.js +19 -21
  85. package/build/lib/commands/system-bars.js.map +1 -1
  86. package/build/lib/commands/time.d.ts.map +1 -1
  87. package/build/lib/commands/time.js +23 -8
  88. package/build/lib/commands/time.js.map +1 -1
  89. package/build/lib/driver.d.ts.map +1 -1
  90. package/build/lib/driver.js +2 -6
  91. package/build/lib/driver.js.map +1 -1
  92. package/build/lib/logger.d.ts +2 -1
  93. package/build/lib/logger.d.ts.map +1 -1
  94. package/build/lib/logger.js.map +1 -1
  95. package/build/lib/utils.d.ts.map +1 -1
  96. package/build/lib/utils.js +9 -12
  97. package/build/lib/utils.js.map +1 -1
  98. package/lib/commands/app-management.ts +19 -9
  99. package/lib/commands/bidi/models.ts +1 -2
  100. package/lib/commands/bluetooth.ts +1 -2
  101. package/lib/commands/context/exports.ts +12 -14
  102. package/lib/commands/context/helpers.ts +47 -22
  103. package/lib/commands/device/common.ts +10 -8
  104. package/lib/commands/device/utils.ts +2 -3
  105. package/lib/commands/deviceidle.ts +2 -3
  106. package/lib/commands/execute.ts +2 -3
  107. package/lib/commands/file-actions.ts +2 -3
  108. package/lib/commands/find.ts +4 -5
  109. package/lib/commands/geolocation.ts +3 -4
  110. package/lib/commands/image-injection.ts +1 -2
  111. package/lib/commands/intent.ts +14 -15
  112. package/lib/commands/keyboard.ts +6 -3
  113. package/lib/commands/lock/exports.ts +1 -2
  114. package/lib/commands/lock/helpers.ts +5 -6
  115. package/lib/commands/log.ts +9 -9
  116. package/lib/commands/media-projection.ts +5 -6
  117. package/lib/commands/network.ts +12 -13
  118. package/lib/commands/nfc.ts +1 -2
  119. package/lib/commands/performance.ts +7 -11
  120. package/lib/commands/permissions.ts +23 -20
  121. package/lib/commands/recordscreen.ts +10 -11
  122. package/lib/commands/resources.ts +7 -8
  123. package/lib/commands/shell.ts +7 -3
  124. package/lib/commands/streamscreen.ts +14 -16
  125. package/lib/commands/system-bars.ts +20 -20
  126. package/lib/commands/time.ts +26 -8
  127. package/lib/driver.ts +2 -4
  128. package/lib/logger.ts +2 -1
  129. package/lib/utils.ts +9 -9
  130. 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 (_.isUndefined(this._screenStreamingProps)) {
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 (_.isEmpty(this._screenStreamingProps)) {
250
- if (!_.isUndefined(this._screenStreamingProps)) {
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
- _.truncate(udid, {
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 (!_.trim(await adb.shell(['which', SCREENRECORD_BINARY]))) {
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 _.toPairs(REQUIRED_GST_PLUGINS)) {
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 (!_.includes(stdout, modName)) {
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 = _.isUndefined(width) ? deviceInfo.width : parseInt(String(width), 10);
370
- const adjustedHeight = _.isUndefined(height) ? deviceInfo.height : parseInt(String(height), 10);
371
- const adjustedBitrate = _.isUndefined(bitRate) ? DEFAULT_BITRATE : parseInt(String(bitRate), 10);
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 (_.trim(stderr)) {
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 = !_.isEmpty(chunk);
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 (_.trim(stderr || stdout)) {
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
- await this.adb.shell([
69
- 'cmd',
70
- 'statusbar',
71
- cmd,
72
- ...(argsCallable ? _.castArray(argsCallable()) : []),
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 = _.fromPairs(
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: ${_.keys(statusBarCommands)}`,
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 = _.cloneDeep(DEFAULT_WINDOW_PROPERTIES);
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(_.trimEnd)) {
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 (_.trim(line).length === 0) {
152
+ if (String(line)?.trim()?.length === 0) {
153
153
  currentWindowName = null;
154
154
  continue;
155
155
  }
156
156
 
157
- if (currentWindowName && _.isArray(windows[currentWindowName])) {
157
+ if (currentWindowName && Array.isArray(windows[currentWindowName])) {
158
158
  windows[currentWindowName].push(line);
159
159
  }
160
160
  }
161
- if (_.isEmpty(windows)) {
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 _.toPairs(windows)) {
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]) => _.isNil(result[name as keyof SystemBarsResult]));
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: ${_.keys(windows)}`,
190
+ `Only the following windows are available: ${Object.keys(windows)}`,
191
191
  );
192
- result[window as keyof SystemBarsResult] = _.cloneDeep(DEFAULT_WINDOW_PROPERTIES);
192
+ result[window as keyof SystemBarsResult] = structuredClone(DEFAULT_WINDOW_PROPERTIES);
193
193
  }
194
194
  return result;
195
195
  }
@@ -1,7 +1,12 @@
1
- import moment from 'moment-timezone';
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
- const MOMENT_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ';
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 = MOMENT_FORMAT_ISO8601,
19
+ format: string = DATETIME_FORMAT_ISO8601,
15
20
  ): Promise<string> {
16
21
  this.log.debug(
17
- 'Attempting to capture android device date and time. ' + `The format specifier is '${format}'`,
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 = moment.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
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
- // @ts-expect-error private API
27
- return parsedTimestamp.utcOffset(parsedTimestamp._tzm || 0).format(format);
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 (!moment.tz.names().includes(zoneName)) {
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 = _.cloneDeep(ANDROID_DRIVER_CONSTRAINTS);
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 _.includes(
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
@@ -1,3 +1,4 @@
1
1
  import {logger} from '@appium/support';
2
+ import type {AppiumLogger} from '@appium/types';
2
3
 
3
- export const log = logger.getLogger('AndroidDriver');
4
+ export const log: AppiumLogger = logger.getLogger('AndroidDriver');
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 _.isArray(argNames) ? argNames : [argNames]) {
33
- if (!_.has(opts, argName)) {
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 (_.isArray(parsedCaps)) {
51
+ if (Array.isArray(parsedCaps)) {
52
52
  return parsedCaps;
53
- } else if (_.isString(cap)) {
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 || !_.isFunction(this.server?.getWebSocketHandlers)) {
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 _.keys(activeHandlers)) {
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 = _.isEmpty(x.prefix) ? x.message : `[${x.prefix}] ${x.message}`;
82
- return toLogRecord(x.timestamp ?? Date.now(), _.replace(msg, COLOR_CODE_PATTERN, ''));
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.1",
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",