appium-android-driver 13.3.2 → 13.3.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.
Files changed (122) 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 +3 -4
  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/driver.d.ts.map +1 -1
  87. package/build/lib/driver.js +2 -6
  88. package/build/lib/driver.js.map +1 -1
  89. package/build/lib/utils.d.ts.map +1 -1
  90. package/build/lib/utils.js +9 -12
  91. package/build/lib/utils.js.map +1 -1
  92. package/lib/commands/app-management.ts +19 -9
  93. package/lib/commands/bidi/models.ts +1 -2
  94. package/lib/commands/bluetooth.ts +1 -2
  95. package/lib/commands/context/exports.ts +12 -14
  96. package/lib/commands/context/helpers.ts +47 -22
  97. package/lib/commands/device/common.ts +10 -8
  98. package/lib/commands/device/utils.ts +2 -3
  99. package/lib/commands/deviceidle.ts +2 -3
  100. package/lib/commands/execute.ts +2 -3
  101. package/lib/commands/file-actions.ts +2 -3
  102. package/lib/commands/find.ts +4 -5
  103. package/lib/commands/geolocation.ts +3 -4
  104. package/lib/commands/image-injection.ts +1 -2
  105. package/lib/commands/intent.ts +14 -15
  106. package/lib/commands/keyboard.ts +6 -3
  107. package/lib/commands/lock/exports.ts +1 -2
  108. package/lib/commands/lock/helpers.ts +5 -6
  109. package/lib/commands/log.ts +9 -9
  110. package/lib/commands/media-projection.ts +3 -4
  111. package/lib/commands/network.ts +12 -13
  112. package/lib/commands/nfc.ts +1 -2
  113. package/lib/commands/performance.ts +7 -11
  114. package/lib/commands/permissions.ts +23 -20
  115. package/lib/commands/recordscreen.ts +10 -11
  116. package/lib/commands/resources.ts +7 -8
  117. package/lib/commands/shell.ts +7 -3
  118. package/lib/commands/streamscreen.ts +14 -16
  119. package/lib/commands/system-bars.ts +20 -20
  120. package/lib/driver.ts +2 -4
  121. package/lib/utils.ts +9 -9
  122. package/package.json +2 -7
@@ -1,5 +1,4 @@
1
1
  import * as semver from 'semver';
2
- import _ from 'lodash';
3
2
  import path from 'node:path';
4
3
  import {setMockLocationApp} from '../geolocation';
5
4
  import {SETTINGS_HELPER_ID} from 'io.appium.settings';
@@ -38,7 +37,7 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
38
37
 
39
38
  // udid was given, lets try to init with that device
40
39
  if (udid) {
41
- if (!_.includes(_.map(devices, 'udid'), udid)) {
40
+ if (!devices?.some((device) => device.udid === udid)) {
42
41
  throw this.log.errorWithException(
43
42
  `Device ${udid} was not in the list of connected devices`,
44
43
  );
@@ -72,11 +71,13 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
72
71
  const semverDO = deviceOS;
73
72
 
74
73
  const bothVersionsCanBeCoerced = semver.valid(deviceOS) && semver.valid(platformVersion);
75
- const bothVersionsAreStrings = _.isString(deviceOS) && _.isString(platformVersion);
74
+ const bothVersionsAreStrings =
75
+ typeof deviceOS === 'string' && typeof platformVersion === 'string';
76
76
  if (
77
77
  (bothVersionsCanBeCoerced &&
78
78
  (semverDO as semver.SemVer).version === (semverPV as semver.SemVer).version) ||
79
- (bothVersionsAreStrings && _.toLower(deviceOS) === _.toLower(platformVersion))
79
+ (bothVersionsAreStrings &&
80
+ String(deviceOS)?.toLowerCase() === String(platformVersion)?.toLowerCase())
80
81
  ) {
81
82
  // Got an exact match - proceed immediately
82
83
  udid = device.udid;
@@ -91,18 +92,19 @@ export async function getDeviceInfoFromCaps(this: AndroidDriver): Promise<ADBDev
91
92
  const dvMajor = (semverDO as semver.SemVer).major;
92
93
  const dvMinor = (semverDO as semver.SemVer).minor;
93
94
  if (
94
- ((!_.includes(this.opts.platformVersion, '.') && pvMajor === dvMajor) ||
95
+ ((!String(this.opts.platformVersion)?.includes('.') && pvMajor === dvMajor) ||
95
96
  (pvMajor === dvMajor && pvMinor === dvMinor)) &&
96
97
  // Got a partial match - make sure we consider the most recent
97
98
  // device version available on the host system
98
- ((partialMatchCandidate && semver.gt(deviceOS, _.values(partialMatchCandidate)[0])) ||
99
+ ((partialMatchCandidate &&
100
+ semver.gt(deviceOS, Object.values(partialMatchCandidate)[0])) ||
99
101
  !partialMatchCandidate)
100
102
  ) {
101
103
  partialMatchCandidate = {[device.udid]: deviceOS};
102
104
  }
103
105
  }
104
106
  if (!udid && partialMatchCandidate) {
105
- udid = _.keys(partialMatchCandidate)[0];
107
+ udid = Object.keys(partialMatchCandidate)[0];
106
108
  adb.setDeviceId(udid);
107
109
  }
108
110
 
@@ -241,7 +243,7 @@ export async function initDevice(this: AndroidDriver): Promise<void> {
241
243
  if (!this.isEmulator()) {
242
244
  setupPromises.push(
243
245
  (async () => {
244
- if (mockLocationApp || _.isUndefined(mockLocationApp)) {
246
+ if (mockLocationApp || mockLocationApp === undefined) {
245
247
  await setMockLocationApp.bind(this)(mockLocationApp || SETTINGS_HELPER_ID);
246
248
  } else {
247
249
  await this.mobileResetGeolocation();
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {util} from '@appium/support';
3
2
  import {ADB} from 'appium-adb';
4
3
  import {retryInterval} from 'asyncbox';
@@ -39,7 +38,7 @@ export function ensureNetworkSpeed(this: AndroidDriver, networkSpeed: string): s
39
38
  }
40
39
  this.log.warn(
41
40
  `Wrong network speed param '${networkSpeed}', using default: ${this.adb.NETWORK_SPEED.FULL}. ` +
42
- `Supported values: ${_.values(this.adb.NETWORK_SPEED)}`,
41
+ `Supported values: ${Object.values(this.adb.NETWORK_SPEED)}`,
43
42
  );
44
43
  return this.adb.NETWORK_SPEED.FULL;
45
44
  }
@@ -53,7 +52,7 @@ export function prepareAvdArgs(this: AndroidDriver): string[] {
53
52
  const {networkSpeed, isHeadless, avdArgs} = this.opts;
54
53
  const result: string[] = [];
55
54
  if (avdArgs) {
56
- if (_.isArray(avdArgs)) {
55
+ if (Array.isArray(avdArgs)) {
57
56
  result.push(...avdArgs);
58
57
  } else {
59
58
  result.push(...util.shellParse(`${avdArgs}`));
@@ -1,5 +1,4 @@
1
1
  import {errors} from 'appium/driver';
2
- import _ from 'lodash';
3
2
  import type {AndroidDriver} from '../driver';
4
3
 
5
4
  const SUPPORTED_ACTIONS = ['whitelistAdd', 'whitelistRemove'] as const;
@@ -20,11 +19,11 @@ export async function mobileDeviceidle(
20
19
  action: (typeof SUPPORTED_ACTIONS)[number],
21
20
  packages?: string | string[],
22
21
  ): Promise<void> {
23
- if (!(_.isString(packages) || _.isArray(packages))) {
22
+ if (!(typeof packages === 'string' || Array.isArray(packages))) {
24
23
  throw new errors.InvalidArgumentError(`packages argument must be a string or an array`);
25
24
  }
26
25
 
27
- const packagesArr = _.isArray(packages) ? packages : [packages];
26
+ const packagesArr = Array.isArray(packages) ? packages : [packages];
28
27
  const commonArgs = ['dumpsys', 'deviceidle', 'whitelist'];
29
28
  let argsGenerator: (pkg: string) => string[];
30
29
  switch (action) {
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {errors, PROTOCOLS} from 'appium/driver';
3
2
  import {util} from '@appium/support';
4
3
  import type {StringRecord, Element} from '@appium/types';
@@ -23,7 +22,7 @@ export async function execute(
23
22
  script: string,
24
23
  args?: ExecuteMethodArgs,
25
24
  ): Promise<any> {
26
- if (_.startsWith(script, EXECUTE_SCRIPT_PREFIX)) {
25
+ if (script?.startsWith(EXECUTE_SCRIPT_PREFIX)) {
27
26
  const formattedScript = script.trim().replace(/^mobile:\s*/, `${EXECUTE_SCRIPT_PREFIX} `);
28
27
  const executeMethodArgs = preprocessExecuteMethodArgs(args);
29
28
  return await this.executeMethod(formattedScript, [executeMethodArgs]);
@@ -48,7 +47,7 @@ export async function execute(
48
47
  * @returns Preprocessed arguments as a StringRecord.
49
48
  */
50
49
  function preprocessExecuteMethodArgs(args?: ExecuteMethodArgs): StringRecord {
51
- const executeMethodArgs = (_.isArray(args) ? _.first(args) : args) ?? ({} as StringRecord);
50
+ const executeMethodArgs = (Array.isArray(args) ? args[0] : args) ?? ({} as StringRecord);
52
51
 
53
52
  /**
54
53
  * Renames the deprecated `element` key to `elementId`. Historically,
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {fs, util, zip, tempDir} from '@appium/support';
3
2
  import path from 'node:path';
4
3
  import {errors} from 'appium/driver';
@@ -98,7 +97,7 @@ export async function pushFile(
98
97
  }
99
98
  const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
100
99
  let base64String: string;
101
- if (_.isArray(base64Data)) {
100
+ if (Array.isArray(base64Data)) {
102
101
  // some clients (ahem) java, send a byte array encoding utf8 characters
103
102
  // instead of a string, which would be infinitely better!
104
103
  base64String = Buffer.from(base64Data).toString('utf8');
@@ -327,7 +326,7 @@ function createFSTests(adb: ADB) {
327
326
  const checkCmd = `[ -${op} '${escapePath(p)}' ] && echo ${passFlag}`;
328
327
  const fullCmd = runAs ? `run-as ${runAs} ${checkCmd}` : checkCmd;
329
328
  try {
330
- return _.includes(await adb.shell([fullCmd]), passFlag);
329
+ return (await adb.shell([fullCmd])).includes(passFlag);
331
330
  } catch {
332
331
  return false;
333
332
  }
@@ -1,10 +1,8 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
-
3
- import _ from 'lodash';
4
1
  import {errors, isErrorType} from 'appium/driver';
5
2
  import type {AndroidDriver} from '../driver';
6
3
  import type {Element} from '@appium/types';
7
4
  import type {FindElementOpts} from './types';
5
+ import {util} from '@appium/support';
8
6
 
9
7
  /**
10
8
  * @param strategy The element location strategy to use (e.g., 'id', 'xpath', 'class name').
@@ -70,7 +68,7 @@ export async function findElOrEls(
70
68
  }
71
69
 
72
70
  // we want to return false if we want to potentially try again
73
- return !_.isEmpty(element);
71
+ return !util.isEmpty(element);
74
72
  };
75
73
 
76
74
  try {
@@ -89,7 +87,7 @@ export async function findElOrEls(
89
87
  if (mult) {
90
88
  return element as Element[];
91
89
  }
92
- if (_.isEmpty(element)) {
90
+ if (util.isEmpty(element)) {
93
91
  throw new errors.NoSuchElementError();
94
92
  }
95
93
  return element as Element;
@@ -109,5 +107,6 @@ export async function doFindElementOrEls(
109
107
  this: AndroidDriver,
110
108
  params: FindElementOpts,
111
109
  ): Promise<Element | Element[]> {
110
+ void params;
112
111
  throw new errors.NotImplementedError('Not implemented');
113
112
  }
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {asyncmap} from 'asyncbox';
3
2
  import {fs, tempDir} from '@appium/support';
4
3
  import path from 'node:path';
@@ -208,10 +207,10 @@ async function resetMockLocation(this: AndroidDriver): Promise<void> {
208
207
  pkgIds = JSON.parse(await this.adb.shell(['cat', MOCK_APP_IDS_STORE]));
209
208
  } catch {}
210
209
  }
211
- const thirdPartyPkgIds = await thirdPartyPkgIdsPromise;
210
+ const thirdPartyPkgIds = new Set(await thirdPartyPkgIdsPromise);
212
211
  // Only include currently installed packages
213
- const resultPkgs = _.intersection(pkgIds, thirdPartyPkgIds);
214
- if (_.size(resultPkgs) <= 1) {
212
+ const resultPkgs = pkgIds.filter((pkg) => thirdPartyPkgIds.has(pkg));
213
+ if (resultPkgs.length <= 1) {
215
214
  await this.adb.shell([
216
215
  'appops',
217
216
  'set',
@@ -2,7 +2,6 @@ import {errors} from 'appium/driver';
2
2
  import path from 'node:path';
3
3
  import {fs, tempDir} from '@appium/support';
4
4
  import crypto from 'node:crypto';
5
- import _ from 'lodash';
6
5
  import type {AndroidDriver} from '../driver';
7
6
 
8
7
  const EMULATOR_RESOURCES_ROOT = ['emulator', 'resources'];
@@ -92,7 +91,7 @@ export async function mobileInjectEmulatorCameraImage(
92
91
  throw new Error('The image injection feature is only available on emulators');
93
92
  }
94
93
 
95
- if (!_.isString(payload) || _.size(payload) <= PNG_MAGIC_LENGTH) {
94
+ if (typeof payload !== 'string' || payload.length <= PNG_MAGIC_LENGTH) {
96
95
  throw new errors.InvalidArgumentError(
97
96
  `You must provide a valid base64-encoded .PNG data as the 'payload' argument`,
98
97
  );
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {errors} from 'appium/driver';
3
2
  import {util} from '@appium/support';
4
3
  import type {AndroidDriver} from '../driver';
@@ -126,7 +125,7 @@ export async function mobileStartActivity(
126
125
  flags?: string,
127
126
  ): Promise<string> {
128
127
  const cmd = ['am', 'start-activity'];
129
- if (!_.isNil(user)) {
128
+ if (util.hasValue(user)) {
130
129
  cmd.push('--user', String(user));
131
130
  }
132
131
  if (wait) {
@@ -135,13 +134,13 @@ export async function mobileStartActivity(
135
134
  if (stop) {
136
135
  cmd.push('-S');
137
136
  }
138
- if (!_.isNil(windowingMode)) {
137
+ if (util.hasValue(windowingMode)) {
139
138
  cmd.push('--windowingMode', String(windowingMode));
140
139
  }
141
- if (!_.isNil(activityType)) {
140
+ if (util.hasValue(activityType)) {
142
141
  cmd.push('--activityType', String(activityType));
143
142
  }
144
- if (!_.isNil(display)) {
143
+ if (util.hasValue(display)) {
145
144
  cmd.push('--display', String(display));
146
145
  }
147
146
  cmd.push(
@@ -200,7 +199,7 @@ export async function mobileBroadcast(
200
199
  flags?: string,
201
200
  ): Promise<string> {
202
201
  const cmd = ['am', 'broadcast'];
203
- if (!_.isNil(user)) {
202
+ if (util.hasValue(user)) {
204
203
  cmd.push('--user', String(user));
205
204
  }
206
205
  if (receiverPermission) {
@@ -265,7 +264,7 @@ export async function mobileStartService(
265
264
  ): Promise<string> {
266
265
  const cmd = ['am'];
267
266
  cmd.push(foreground ? 'start-foreground-service' : 'start-service');
268
- if (!_.isNil(user)) {
267
+ if (util.hasValue(user)) {
269
268
  cmd.push('--user', String(user));
270
269
  }
271
270
  cmd.push(
@@ -320,7 +319,7 @@ export async function mobileStopService(
320
319
  flags?: string,
321
320
  ): Promise<string> {
322
321
  const cmd = ['am', 'stop-service'];
323
- if (!_.isNil(user)) {
322
+ if (util.hasValue(user)) {
324
323
  cmd.push('--user', String(user));
325
324
  }
326
325
  cmd.push(
@@ -366,12 +365,12 @@ function parseIntentSpec(opts: IntentOpts = {}): string[] {
366
365
  if (mimeType) {
367
366
  resultArgs.push('-t', mimeType);
368
367
  }
369
- if (!_.isNil(identifier)) {
368
+ if (util.hasValue(identifier)) {
370
369
  resultArgs.push('-i', identifier);
371
370
  }
372
371
  if (categories) {
373
- if (_.isArray(categories)) {
374
- resultArgs.push(..._.flatMap(categories.map((cName) => ['-c', cName])));
372
+ if (Array.isArray(categories)) {
373
+ resultArgs.push(...categories.flatMap((cName) => ['-c', cName]));
375
374
  } else {
376
375
  resultArgs.push('-c', categories);
377
376
  }
@@ -383,11 +382,11 @@ function parseIntentSpec(opts: IntentOpts = {}): string[] {
383
382
  resultArgs.push('-p', opts.package);
384
383
  }
385
384
  if (extras) {
386
- if (!_.isArray(extras)) {
385
+ if (!Array.isArray(extras)) {
387
386
  throw new errors.InvalidArgumentError(`'extras' must be an array`);
388
387
  }
389
388
  for (const item of extras) {
390
- if (!_.isArray(item)) {
389
+ if (!Array.isArray(item)) {
391
390
  throw new errors.InvalidArgumentError(`Extra argument '${item}' must be an array`);
392
391
  }
393
392
  const [type, key, value] = item;
@@ -397,14 +396,14 @@ function parseIntentSpec(opts: IntentOpts = {}): string[] {
397
396
  `Supported intent argument types are: ${SUPPORTED_EXTRA_TYPES.join(', ')}`,
398
397
  );
399
398
  }
400
- if (_.isEmpty(key) || (_.isString(key) && _.trim(key) === '')) {
399
+ if (util.isEmpty(key) || (typeof key === 'string' && key.trim() === '')) {
401
400
  throw new errors.InvalidArgumentError(
402
401
  `Extra argument's key in '${JSON.stringify(item)}' must be a valid string identifier`,
403
402
  );
404
403
  }
405
404
  if (type === NO_VALUE_ARG_TYPE) {
406
405
  resultArgs.push(`--e${type}`, key);
407
- } else if (_.isUndefined(value)) {
406
+ } else if (value === undefined) {
408
407
  throw new errors.InvalidArgumentError(
409
408
  `Intent argument type '${type}' in '${JSON.stringify(item)}' requires a ` +
410
409
  `valid value to be provided`,
@@ -1,5 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import _ from 'lodash';
3
1
  import {errors} from 'appium/driver';
4
2
  import {UNICODE_IME, EMPTY_IME} from 'io.appium.settings';
5
3
  import type {AndroidDriver} from '../driver';
@@ -32,7 +30,7 @@ export async function isKeyboardShown(this: AndroidDriver): Promise<boolean> {
32
30
  */
33
31
  export async function keys(this: AndroidDriver, keys: string | string[]): Promise<void> {
34
32
  // Protocol sends an array; rethink approach
35
- const keysStr = _.isArray(keys) ? keys.join('') : keys;
33
+ const keysStr = Array.isArray(keys) ? keys.join('') : keys;
36
34
  await this.doSendKeys({
37
35
  text: keysStr,
38
36
  replace: false,
@@ -47,6 +45,7 @@ export async function keys(this: AndroidDriver, keys: string | string[]): Promis
47
45
  * @throws {errors.NotImplementedError} This method is not implemented.
48
46
  */
49
47
  export async function doSendKeys(this: AndroidDriver, params: SendKeysOpts): Promise<void> {
48
+ void params;
50
49
  throw new errors.NotImplementedError('Not implemented');
51
50
  }
52
51
 
@@ -81,6 +80,8 @@ export async function pressKeyCode(
81
80
  keycode: string | number,
82
81
  metastate?: number,
83
82
  ): Promise<void> {
83
+ void keycode;
84
+ void metastate;
84
85
  throw new errors.NotImplementedError('Not implemented');
85
86
  }
86
87
 
@@ -97,6 +98,8 @@ export async function longPressKeyCode(
97
98
  keycode: string | number,
98
99
  metastate?: number,
99
100
  ): Promise<void> {
101
+ void keycode;
102
+ void metastate;
100
103
  throw new errors.NotImplementedError('Not implemented');
101
104
  }
102
105
 
@@ -15,7 +15,6 @@ import {
15
15
  toCredentialType,
16
16
  verifyUnlock,
17
17
  } from './helpers';
18
- import _ from 'lodash';
19
18
  import type {AndroidDriver, AndroidDriverCaps} from '../../driver';
20
19
  import type {UnlockType} from '../types';
21
20
 
@@ -119,7 +118,7 @@ export async function unlockWithOptions(
119
118
  if (
120
119
  unlockKey &&
121
120
  unlockType !== FINGERPRINT_UNLOCK &&
122
- (_.isNil(unlockStrategy) || _.toLower(unlockStrategy) === 'locksettings') &&
121
+ (unlockStrategy == null || String(unlockStrategy)?.toLowerCase() === 'locksettings') &&
123
122
  (await this.adb.isLockManagementSupported())
124
123
  ) {
125
124
  await fastUnlock.bind(this)({
@@ -1,6 +1,5 @@
1
1
  import {util} from '@appium/support';
2
2
  import {sleep, waitForCondition} from 'asyncbox';
3
- import _ from 'lodash';
4
3
  import type {ADB} from 'appium-adb';
5
4
  import type {Position, StringRecord} from '@appium/types';
6
5
  import type {AndroidDriver, AndroidDriverCaps} from '../../driver';
@@ -58,16 +57,16 @@ export function validateUnlockCapabilities<T extends AndroidDriverCaps>(caps: T)
58
57
  }
59
58
 
60
59
  if ([PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, FINGERPRINT_UNLOCK].includes(unlockType)) {
61
- if (!/^[0-9]+$/.test(_.trim(unlockKey))) {
60
+ if (!/^[0-9]+$/.test(String(unlockKey)?.trim())) {
62
61
  throw new Error(`Unlock key value '${unlockKey}' must only consist of digits`);
63
62
  }
64
63
  } else if (unlockType === PATTERN_UNLOCK) {
65
- if (!/^[1-9]{2,9}$/.test(_.trim(unlockKey))) {
64
+ if (!/^[1-9]{2,9}$/.test(String(unlockKey)?.trim())) {
66
65
  throw new Error(
67
66
  `Unlock key value '${unlockKey}' must only include from two to nine digits in range 1..9`,
68
67
  );
69
68
  }
70
- if (/([1-9]).*?\1/.test(_.trim(unlockKey))) {
69
+ if (/([1-9]).*?\1/.test(String(unlockKey)?.trim())) {
71
70
  throw new Error(
72
71
  `Unlock key value '${unlockKey}' must define a valid pattern where repeats are not allowed`,
73
72
  );
@@ -161,7 +160,7 @@ export async function pinUnlock(
161
160
  await this.adb.dismissKeyguard();
162
161
  const keys = stringKeyToArr(String(capabilities.unlockKey));
163
162
  const els = await this.findElOrEls('id', 'com.android.systemui:id/digit_text', true);
164
- if (_.isEmpty(els)) {
163
+ if (util.isEmpty(els)) {
165
164
  // fallback to pin with key event
166
165
  return await pinUnlockWithKeyEvent.bind(this)(capabilities);
167
166
  }
@@ -267,7 +266,7 @@ export function getPatternActions(
267
266
  ): StringRecord[] {
268
267
  // https://www.w3.org/TR/webdriver2/#actions
269
268
  const pointerActions: StringRecord[] = [];
270
- const intKeys = keys.map((key) => (_.isString(key) ? _.parseInt(key) : key));
269
+ const intKeys = keys.map((key) => (typeof key === 'string' ? parseInt(key, 10) : key));
271
270
  let lastPos: Position | undefined;
272
271
  for (const key of intKeys) {
273
272
  const keyPos = getPatternKeyPosition(key, initPos, piece);
@@ -1,5 +1,4 @@
1
1
  import {DEFAULT_WS_PATHNAME_PREFIX, BaseDriver} from 'appium/driver';
2
- import _ from 'lodash';
3
2
  import os from 'node:os';
4
3
  import WebSocket from 'ws';
5
4
  import type {AppiumServer, WSServer} from '@appium/types';
@@ -16,6 +15,7 @@ import {NATIVE_WIN} from './context/helpers';
16
15
  import {BIDI_EVENT_NAME} from './bidi/constants';
17
16
  import {makeLogEntryAddedEvent} from './bidi/models';
18
17
  import type {AndroidDriver} from '../driver';
18
+ import {util} from '@appium/support';
19
19
 
20
20
  export const supportedLogTypes = {
21
21
  logcat: {
@@ -52,7 +52,7 @@ export const supportedLogTypes = {
52
52
  export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<void> {
53
53
  const server = this.server as AppiumServer;
54
54
  const pathname = WEBSOCKET_ENDPOINT(this.sessionId as string);
55
- if (!_.isEmpty(await server.getWebSocketHandlers(pathname))) {
55
+ if (!util.isEmpty(await server.getWebSocketHandlers(pathname))) {
56
56
  this.log.debug(`The logcat broadcasting web socket server is already listening at ${pathname}`);
57
57
  return;
58
58
  }
@@ -67,7 +67,7 @@ export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<voi
67
67
  });
68
68
  wss.on('connection', (ws, req) => {
69
69
  if (req) {
70
- const remoteIp = _.isEmpty(req.headers['x-forwarded-for'])
70
+ const remoteIp = util.isEmpty(req.headers['x-forwarded-for'])
71
71
  ? req.socket.remoteAddress
72
72
  : req.headers['x-forwarded-for'];
73
73
  this.log.debug(`Established a new logcat listener web socket connection from ${remoteIp}`);
@@ -75,7 +75,7 @@ export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<voi
75
75
  this.log.debug('Established a new logcat listener web socket connection');
76
76
  }
77
77
 
78
- if (_.isEmpty(this._logcatWebsocketListener)) {
78
+ if (!this._logcatWebsocketListener) {
79
79
  this._logcatWebsocketListener = (logRecord: LogEntry) => {
80
80
  if (ws?.readyState === WebSocket.OPEN) {
81
81
  ws.send(logRecord.message);
@@ -85,7 +85,7 @@ export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<voi
85
85
  this.adb.setLogcatListener(this._logcatWebsocketListener);
86
86
 
87
87
  ws.on('close', (code, reason) => {
88
- if (!_.isEmpty(this._logcatWebsocketListener)) {
88
+ if (this._logcatWebsocketListener) {
89
89
  try {
90
90
  this.adb.removeLogcatListener(this._logcatWebsocketListener);
91
91
  } catch {}
@@ -93,10 +93,10 @@ export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<voi
93
93
  }
94
94
 
95
95
  let closeMsg = 'Logcat listener web socket is closed.';
96
- if (!_.isEmpty(code)) {
96
+ if (!util.isEmpty(code)) {
97
97
  closeMsg += ` Code: ${code}.`;
98
98
  }
99
- if (!_.isEmpty(reason)) {
99
+ if (!util.isEmpty(reason)) {
100
100
  closeMsg += ` Reason: ${reason.toString()}.`;
101
101
  }
102
102
  this.log.debug(closeMsg);
@@ -114,7 +114,7 @@ export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<voi
114
114
  export async function mobileStopLogsBroadcast(this: AndroidDriver): Promise<void> {
115
115
  const pathname = WEBSOCKET_ENDPOINT(this.sessionId as string);
116
116
  const server = this.server as AppiumServer;
117
- if (_.isEmpty(await server.getWebSocketHandlers(pathname))) {
117
+ if (util.isEmpty(await server.getWebSocketHandlers(pathname))) {
118
118
  return;
119
119
  }
120
120
 
@@ -174,7 +174,7 @@ export function assignBiDiLogListener<EE extends EventEmitter>(
174
174
  * @returns Promise that resolves to the logs for the specified type.
175
175
  */
176
176
  export async function getLog(this: AndroidDriver, logType: string): Promise<any> {
177
- if (this.isWebContext() && !_.keys(this.supportedLogTypes).includes(logType)) {
177
+ if (this.isWebContext() && !Object.keys(this.supportedLogTypes).includes(logType)) {
178
178
  return await (this.chromedriver as Chromedriver).jwproxy.command('/log', 'POST', {
179
179
  type: logType,
180
180
  });
@@ -1,6 +1,5 @@
1
1
  import {fs, net, util} from '@appium/support';
2
2
  import type {NetOptions, HttpUploadOptions} from '@appium/support';
3
- import _ from 'lodash';
4
3
  import dayjs from 'dayjs';
5
4
  import path from 'node:path';
6
5
  import type {HTTPMethod, StringRecord} from '@appium/types';
@@ -128,7 +127,7 @@ export async function mobileStopMediaProjectionRecording(
128
127
  throw new Error(`No recent media projection recording have been found. Did you start any?`);
129
128
  }
130
129
 
131
- if (_.isEmpty(remotePath)) {
130
+ if (util.isEmpty(remotePath)) {
132
131
  const {size} = await fs.stat(recentRecordingPath);
133
132
  this.log.debug(
134
133
  `The size of the resulting media projection recording is ${util.toReadableSizeString(size)}`,
@@ -154,7 +153,7 @@ async function uploadRecordedMedia(
154
153
  remotePath?: string,
155
154
  uploadOptions: UploadOptions = {},
156
155
  ): Promise<string> {
157
- if (_.isEmpty(remotePath)) {
156
+ if (util.isEmpty(remotePath)) {
158
157
  return (await util.toInMemoryBase64(localFile)).toString();
159
158
  }
160
159
 
@@ -182,7 +181,7 @@ async function uploadRecordedMedia(
182
181
  }
183
182
 
184
183
  function adjustMediaExtension(name: string): string {
185
- return _.toLower(name).endsWith(DEFAULT_EXT) ? name : `${name}${DEFAULT_EXT}`;
184
+ return name?.toLowerCase()?.endsWith(DEFAULT_EXT) ? name : `${name}${DEFAULT_EXT}`;
186
185
  }
187
186
 
188
187
  async function verifyMediaProjectionRecordingIsSupported(adb: ADB): Promise<void> {
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import {errors} from 'appium/driver';
3
2
  import {util} from '@appium/support';
4
3
  import type {AndroidDriver} from '../driver';
@@ -69,7 +68,7 @@ export async function mobileSetConnectivity(
69
68
  data?: boolean,
70
69
  airplaneMode?: boolean,
71
70
  ): Promise<void> {
72
- if (_.every([wifi, data, airplaneMode], _.isUndefined)) {
71
+ if (wifi === undefined && data === undefined && airplaneMode === undefined) {
73
72
  throw new errors.InvalidArgumentError(
74
73
  `Either one of ${JSON.stringify(SUPPORTED_SERVICE_NAMES)} options must be provided`,
75
74
  );
@@ -81,20 +80,20 @@ export async function mobileSetConnectivity(
81
80
  [airplaneMode, AIRPLANE_MODE_KEY_NAME],
82
81
  ];
83
82
  const services = connectivityPairs.reduce<ServiceType[]>((acc, [value, key]) => {
84
- if (!_.isUndefined(value)) {
83
+ if (value !== undefined) {
85
84
  acc.push(key);
86
85
  }
87
86
  return acc;
88
87
  }, []);
89
88
  const currentState = await this.mobileGetConnectivity(services);
90
89
  const setters: Promise<any>[] = [];
91
- if (!_.isUndefined(wifi) && currentState.wifi !== Boolean(wifi)) {
90
+ if (wifi !== undefined && currentState.wifi !== Boolean(wifi)) {
92
91
  setters.push(this.setWifiState(wifi));
93
92
  }
94
- if (!_.isUndefined(data) && currentState.data !== Boolean(data)) {
93
+ if (data !== undefined && currentState.data !== Boolean(data)) {
95
94
  setters.push(this.setDataState(data));
96
95
  }
97
- if (!_.isUndefined(airplaneMode) && currentState.airplaneMode !== Boolean(airplaneMode)) {
96
+ if (airplaneMode !== undefined && currentState.airplaneMode !== Boolean(airplaneMode)) {
98
97
  setters.push(
99
98
  (async () => {
100
99
  await this.adb.setAirplaneMode(airplaneMode);
@@ -104,7 +103,7 @@ export async function mobileSetConnectivity(
104
103
  })(),
105
104
  );
106
105
  }
107
- if (!_.isEmpty(setters)) {
106
+ if (setters.length > 0) {
108
107
  await Promise.all(setters);
109
108
  }
110
109
  }
@@ -120,9 +119,9 @@ export async function mobileGetConnectivity(
120
119
  this: AndroidDriver,
121
120
  services: ServiceType[] | ServiceType = SUPPORTED_SERVICE_NAMES,
122
121
  ): Promise<GetConnectivityResult> {
123
- const svcs = _.castArray(services);
124
- const unsupportedServices = _.difference(svcs, SUPPORTED_SERVICE_NAMES);
125
- if (!_.isEmpty(unsupportedServices)) {
122
+ const svcs = Array.isArray(services) ? services : [services];
123
+ const unsupportedServices = svcs.filter((svc) => !SUPPORTED_SERVICE_NAMES.includes(svc));
124
+ if (unsupportedServices.length > 0) {
126
125
  throw new errors.InvalidArgumentError(
127
126
  `${util.pluralize(
128
127
  'Service name',
@@ -144,13 +143,13 @@ export async function mobileGetConnectivity(
144
143
  : Promise.resolve(undefined),
145
144
  ]);
146
145
  const result: GetConnectivityResult = {};
147
- if (!_.isUndefined(wifi)) {
146
+ if (wifi !== undefined) {
148
147
  result.wifi = Boolean(wifi);
149
148
  }
150
- if (!_.isUndefined(data)) {
149
+ if (data !== undefined) {
151
150
  result.data = Boolean(data);
152
151
  }
153
- if (!_.isUndefined(airplaneMode)) {
152
+ if (airplaneMode !== undefined) {
154
153
  result.airplaneMode = Boolean(airplaneMode);
155
154
  }
156
155
  return result;
@@ -1,5 +1,4 @@
1
1
  import {errors} from 'appium/driver';
2
- import _ from 'lodash';
3
2
  import type {AndroidDriver} from '../driver';
4
3
  import type {NfcAction} from './types';
5
4
 
@@ -27,7 +26,7 @@ export async function mobileNfc(this: AndroidDriver, action: NfcAction): Promise
27
26
  break;
28
27
  default:
29
28
  throw new errors.InvalidArgumentError(
30
- `You must provide a valid 'action' argument. Supported actions are: ${_.values(SUPPORTED_ACTIONS)}`,
29
+ `You must provide a valid 'action' argument. Supported actions are: ${Object.values(SUPPORTED_ACTIONS)}`,
31
30
  );
32
31
  }
33
32
  }