appium-uiautomator2-driver 8.2.0 → 8.2.2

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 (94) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/actions.d.ts.map +1 -1
  3. package/build/lib/commands/actions.js.map +1 -1
  4. package/build/lib/commands/alert.d.ts.map +1 -1
  5. package/build/lib/commands/alert.js.map +1 -1
  6. package/build/lib/commands/app-management.d.ts.map +1 -1
  7. package/build/lib/commands/app-management.js.map +1 -1
  8. package/build/lib/commands/aut.d.ts.map +1 -1
  9. package/build/lib/commands/aut.js +1 -2
  10. package/build/lib/commands/aut.js.map +1 -1
  11. package/build/lib/commands/battery.d.ts.map +1 -1
  12. package/build/lib/commands/battery.js.map +1 -1
  13. package/build/lib/commands/element.d.ts +1 -1
  14. package/build/lib/commands/element.d.ts.map +1 -1
  15. package/build/lib/commands/element.js.map +1 -1
  16. package/build/lib/commands/find.d.ts.map +1 -1
  17. package/build/lib/commands/find.js.map +1 -1
  18. package/build/lib/commands/gestures.d.ts.map +1 -1
  19. package/build/lib/commands/gestures.js.map +1 -1
  20. package/build/lib/commands/keyboard.d.ts +1 -1
  21. package/build/lib/commands/keyboard.d.ts.map +1 -1
  22. package/build/lib/commands/keyboard.js.map +1 -1
  23. package/build/lib/commands/misc.d.ts.map +1 -1
  24. package/build/lib/commands/misc.js.map +1 -1
  25. package/build/lib/commands/screenshot.d.ts +1 -1
  26. package/build/lib/commands/screenshot.d.ts.map +1 -1
  27. package/build/lib/commands/screenshot.js +1 -3
  28. package/build/lib/commands/screenshot.js.map +1 -1
  29. package/build/lib/commands/viewport.d.ts.map +1 -1
  30. package/build/lib/commands/viewport.js.map +1 -1
  31. package/build/lib/commands/windows.d.ts.map +1 -1
  32. package/build/lib/commands/windows.js.map +1 -1
  33. package/build/lib/css/index.d.ts.map +1 -1
  34. package/build/lib/css/index.js.map +1 -1
  35. package/build/lib/css/ui-automator-emitter.d.ts.map +1 -1
  36. package/build/lib/css/ui-automator-emitter.js +1 -3
  37. package/build/lib/css/ui-automator-emitter.js.map +1 -1
  38. package/build/lib/doctor/optional-checks.d.ts.map +1 -1
  39. package/build/lib/doctor/optional-checks.js.map +1 -1
  40. package/build/lib/doctor/required-checks.d.ts.map +1 -1
  41. package/build/lib/doctor/required-checks.js.map +1 -1
  42. package/build/lib/driver.d.ts +6 -6
  43. package/build/lib/driver.d.ts.map +1 -1
  44. package/build/lib/driver.js +9 -20
  45. package/build/lib/driver.js.map +1 -1
  46. package/build/lib/logger.d.ts.map +1 -1
  47. package/build/lib/logger.js.map +1 -1
  48. package/build/lib/session-claim-handler.d.ts.map +1 -1
  49. package/build/lib/session-claim-handler.js +1 -1
  50. package/build/lib/session-claim-handler.js.map +1 -1
  51. package/build/lib/types.d.ts.map +1 -1
  52. package/build/lib/uiautomator2-server/core.d.ts +1 -1
  53. package/build/lib/uiautomator2-server/core.d.ts.map +1 -1
  54. package/build/lib/uiautomator2-server/core.js +8 -22
  55. package/build/lib/uiautomator2-server/core.js.map +1 -1
  56. package/build/lib/uiautomator2-server/session.d.ts.map +1 -1
  57. package/build/lib/uiautomator2-server/session.js +8 -6
  58. package/build/lib/uiautomator2-server/session.js.map +1 -1
  59. package/build/lib/utils/app.d.ts.map +1 -1
  60. package/build/lib/utils/app.js.map +1 -1
  61. package/build/lib/utils/mjpeg.d.ts.map +1 -1
  62. package/build/lib/utils/mjpeg.js +1 -1
  63. package/build/lib/utils/mjpeg.js.map +1 -1
  64. package/build/lib/utils/object.d.ts.map +1 -1
  65. package/build/lib/utils/object.js.map +1 -1
  66. package/lib/commands/actions.ts +4 -12
  67. package/lib/commands/alert.ts +2 -8
  68. package/lib/commands/app-management.ts +3 -4
  69. package/lib/commands/aut.ts +4 -10
  70. package/lib/commands/battery.ts +1 -5
  71. package/lib/commands/element.ts +15 -51
  72. package/lib/commands/find.ts +5 -6
  73. package/lib/commands/gestures.ts +5 -11
  74. package/lib/commands/keyboard.ts +10 -19
  75. package/lib/commands/misc.ts +3 -7
  76. package/lib/commands/screenshot.ts +8 -15
  77. package/lib/commands/viewport.ts +3 -10
  78. package/lib/commands/windows.ts +1 -5
  79. package/lib/css/index.ts +3 -5
  80. package/lib/css/ui-automator-emitter.ts +3 -9
  81. package/lib/doctor/optional-checks.ts +1 -1
  82. package/lib/doctor/required-checks.ts +1 -1
  83. package/lib/driver.ts +34 -61
  84. package/lib/logger.ts +1 -1
  85. package/lib/session-claim-handler.ts +21 -45
  86. package/lib/types.ts +2 -2
  87. package/lib/uiautomator2-server/core.ts +24 -60
  88. package/lib/uiautomator2-server/session.ts +13 -22
  89. package/lib/utils/app.ts +1 -0
  90. package/lib/utils/mjpeg.ts +8 -28
  91. package/lib/utils/object.ts +1 -4
  92. package/npm-shrinkwrap.json +74 -95
  93. package/package.json +21 -35
  94. package/scripts/reset.mjs +2 -8
package/lib/logger.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {logger} from 'appium/support.js';
2
1
  import type {AppiumLogger} from '@appium/types';
2
+ import {logger} from 'appium/support.js';
3
3
 
4
4
  export const log: AppiumLogger = logger.getLogger('UiAutomator2');
@@ -1,7 +1,9 @@
1
+ import {setTimeout as delay} from 'node:timers/promises';
2
+
1
3
  import type {AppiumLogger, IAppiumIpc, IIpcSubscription, IpcMessage} from '@appium/types';
2
4
  import {node, util} from 'appium/support.js';
3
5
  import {waitForCondition} from 'asyncbox';
4
- import {setTimeout as delay} from 'node:timers/promises';
6
+
5
7
  import type {AndroidUiautomator2Driver} from './driver.js';
6
8
  import {memoize} from './utils/index.js';
7
9
 
@@ -21,10 +23,7 @@ export class SessionClaimHandler {
21
23
  private static readonly CONTENTION_PROBE_MS = 10;
22
24
  private static readonly RELEASE_WAIT_MS = 15000;
23
25
 
24
- private readonly subscriptionsBySessionId = new Map<
25
- string,
26
- IIpcSubscription<SessionUdidIpcMessage>
27
- >();
26
+ private readonly subscriptionsBySessionId = new Map<string, IIpcSubscription<SessionUdidIpcMessage>>();
28
27
 
29
28
  constructor(private readonly getIpc: IpcProvider) {}
30
29
 
@@ -64,9 +63,7 @@ export class SessionClaimHandler {
64
63
  async claimSessionUdid(driver: AndroidUiautomator2Driver): Promise<void> {
65
64
  const ipc = await this.getIpc();
66
65
  if (!ipc) {
67
- driver.log.debug(
68
- 'Driver-instance IPC is unavailable. Skipping publication of the session udid.',
69
- );
66
+ driver.log.debug('Driver-instance IPC is unavailable. Skipping publication of the session udid.');
70
67
  return;
71
68
  }
72
69
 
@@ -99,14 +96,10 @@ export class SessionClaimHandler {
99
96
  });
100
97
 
101
98
  try {
102
- await ipc.publish<SessionUdidIpcMessage>(
103
- SessionClaimHandler.CLAIMED_TOPIC,
104
- this.getPublisherId(driver),
105
- {
106
- udid,
107
- sessionId,
108
- },
109
- );
99
+ await ipc.publish<SessionUdidIpcMessage>(SessionClaimHandler.CLAIMED_TOPIC, this.getPublisherId(driver), {
100
+ udid,
101
+ sessionId,
102
+ });
110
103
  await delay(SessionClaimHandler.CONTENTION_PROBE_MS);
111
104
 
112
105
  if (contendingSessionIds.size === 0) {
@@ -114,21 +107,16 @@ export class SessionClaimHandler {
114
107
  }
115
108
 
116
109
  try {
117
- await waitForCondition(
118
- () => [...contendingSessionIds].every((id) => releasedSessionIds.has(id)),
119
- {
120
- waitMs: SessionClaimHandler.RELEASE_WAIT_MS,
121
- intervalMs: 50,
122
- },
123
- );
110
+ await waitForCondition(() => [...contendingSessionIds].every((id) => releasedSessionIds.has(id)), {
111
+ waitMs: SessionClaimHandler.RELEASE_WAIT_MS,
112
+ intervalMs: 50,
113
+ });
124
114
  driver.log.debug(
125
115
  `Received release confirmation from ` +
126
116
  `${util.pluralize('session', contendingSessionIds.size, true)} for udid '${udid}'`,
127
117
  );
128
118
  } catch {
129
- const pendingSessionIds = [...contendingSessionIds].filter(
130
- (id) => !releasedSessionIds.has(id),
131
- );
119
+ const pendingSessionIds = [...contendingSessionIds].filter((id) => !releasedSessionIds.has(id));
132
120
  driver.log.warn(
133
121
  `Timed out after ${SessionClaimHandler.RELEASE_WAIT_MS}ms waiting for ` +
134
122
  `${util.pluralize('session', pendingSessionIds.length, true)} ` +
@@ -177,9 +165,7 @@ export class SessionClaimHandler {
177
165
  await this.publishSessionUdidContended(driver, udid);
178
166
  } catch (err) {
179
167
  const msg = err instanceof Error ? err.message : String(err);
180
- driver.log.warn(
181
- `Could not publish udid contention message for session '${driver.sessionId}': ${msg}`,
182
- );
168
+ driver.log.warn(`Could not publish udid contention message for session '${driver.sessionId}': ${msg}`);
183
169
  }
184
170
 
185
171
  driver.log.warn(
@@ -192,30 +178,20 @@ export class SessionClaimHandler {
192
178
  await this.terminateSessionOnRequest(driver, udid);
193
179
  }
194
180
 
195
- private async publishSessionUdidContended(
196
- driver: AndroidUiautomator2Driver,
197
- udid: string,
198
- ): Promise<void> {
181
+ private async publishSessionUdidContended(driver: AndroidUiautomator2Driver, udid: string): Promise<void> {
199
182
  const ipc = await this.getIpc();
200
183
  const sessionId = driver.sessionId ?? undefined;
201
184
  if (!ipc || !udid || !sessionId) {
202
185
  return;
203
186
  }
204
187
 
205
- await ipc.publish<SessionUdidIpcMessage>(
206
- SessionClaimHandler.CONTENDED_TOPIC,
207
- this.getPublisherId(driver),
208
- {
209
- udid,
210
- sessionId,
211
- },
212
- );
188
+ await ipc.publish<SessionUdidIpcMessage>(SessionClaimHandler.CONTENDED_TOPIC, this.getPublisherId(driver), {
189
+ udid,
190
+ sessionId,
191
+ });
213
192
  }
214
193
 
215
- private async terminateSessionOnRequest(
216
- driver: AndroidUiautomator2Driver,
217
- udid: string,
218
- ): Promise<void> {
194
+ private async terminateSessionOnRequest(driver: AndroidUiautomator2Driver, udid: string): Promise<void> {
219
195
  const sessionId = driver.sessionId ?? undefined;
220
196
  const publisherId = sessionId ? this.getPublisherId(driver) : undefined;
221
197
  const {log} = driver;
package/lib/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type {DriverCaps, DriverOpts, W3CDriverCaps} from '@appium/types';
2
+
2
3
  import type {RelativeRect} from './commands/types.js';
3
4
  import type {Uiautomator2Constraints} from './constraints.js';
4
5
 
@@ -41,8 +42,7 @@ export interface Uiautomator2ServerInfo {
41
42
  desired: Uiautomator2DriverCaps;
42
43
  }
43
44
 
44
- export interface Uiautomator2StartSessionOpts
45
- extends Uiautomator2DriverCaps, Uiautomator2ServerInfo {}
45
+ export interface Uiautomator2StartSessionOpts extends Uiautomator2DriverCaps, Uiautomator2ServerInfo {}
46
46
 
47
47
  export interface Uiautomator2SessionCaps
48
48
  extends Uiautomator2ServerInfo, Uiautomator2SessionInfo, Partial<Uiautomator2DeviceDetails> {}
@@ -1,22 +1,16 @@
1
- import {JWProxy, errors} from 'appium/driver.js';
2
- import {sleep, waitForCondition} from 'asyncbox';
1
+ import type {AppiumLogger, StringRecord, HTTPMethod, HTTPBody, ProxyResponse, ProxyOptions} from '@appium/types';
2
+ import type {ADB, InstallState} from 'appium-adb';
3
3
  import {
4
4
  SERVER_APK_PATH as apkPath,
5
5
  TEST_APK_PATH as testApkPath,
6
6
  version as serverVersion,
7
7
  } from 'appium-uiautomator2-server';
8
+ import {JWProxy, errors} from 'appium/driver.js';
8
9
  import {util, timing} from 'appium/support.js';
9
- import type {
10
- AppiumLogger,
11
- StringRecord,
12
- HTTPMethod,
13
- HTTPBody,
14
- ProxyResponse,
15
- ProxyOptions,
16
- } from '@appium/types';
10
+ import {sleep, waitForCondition} from 'asyncbox';
17
11
  import axios from 'axios';
18
- import type {ADB, InstallState} from 'appium-adb';
19
12
  import type {SubProcess} from 'teen_process';
13
+
20
14
  import {SERVER_PACKAGE_ID, SERVER_TEST_PACKAGE_ID} from './packages.js';
21
15
 
22
16
  const SERVER_LAUNCH_TIMEOUT_MS = 30000;
@@ -147,11 +141,8 @@ export class UiAutomator2Server {
147
141
  const shouldUninstallServerPackages = this.shouldUninstallServerPackages(packagesInfo);
148
142
  // Install must always follow uninstall. Also, perform the install if
149
143
  // any of server packages is not installed or is outdated
150
- const shouldInstallServerPackages =
151
- shouldUninstallServerPackages || this.shouldInstallServerPackages(packagesInfo);
152
- this.log.info(
153
- `Server packages are ${shouldInstallServerPackages ? '' : 'not '}going to be (re)installed`,
154
- );
144
+ const shouldInstallServerPackages = shouldUninstallServerPackages || this.shouldInstallServerPackages(packagesInfo);
145
+ this.log.info(`Server packages are ${shouldInstallServerPackages ? '' : 'not '}going to be (re)installed`);
155
146
  if (shouldInstallServerPackages && shouldUninstallServerPackages) {
156
147
  this.log.info('Full packages reinstall is going to be performed');
157
148
  }
@@ -183,9 +174,7 @@ export class UiAutomator2Server {
183
174
  async startSession(caps: StringRecord): Promise<void> {
184
175
  await this.cleanupAutomationLeftovers();
185
176
  if (caps.skipServerInstallation) {
186
- this.log.info(
187
- `'skipServerInstallation' is set. Attempting to use UIAutomator2 server from the device`,
188
- );
177
+ this.log.info(`'skipServerInstallation' is set. Attempting to use UIAutomator2 server from the device`);
189
178
  } else {
190
179
  this.log.info(`Starting UIAutomator2 server ${serverVersion}`);
191
180
  this.log.info(`Using UIAutomator2 server from '${apkPath}' and test from '${testApkPath}'`);
@@ -248,8 +237,7 @@ export class UiAutomator2Server {
248
237
  }
249
238
 
250
239
  this.log.debug(
251
- `The initialization of the instrumentation process took ` +
252
- `${timer.getDuration().asMilliSeconds.toFixed(0)}ms`,
240
+ `The initialization of the instrumentation process took ` + `${timer.getDuration().asMilliSeconds.toFixed(0)}ms`,
253
241
  );
254
242
  await this.jwproxy.command('/session', 'POST', {
255
243
  capabilities: {
@@ -266,8 +254,7 @@ export class UiAutomator2Server {
266
254
  await this.jwproxy.command('/', 'DELETE');
267
255
  } catch (err: any) {
268
256
  this.log.warn(
269
- `Did not get the confirmation of UiAutomator2 server session deletion. ` +
270
- `Original error: ${err.message}`,
257
+ `Did not get the confirmation of UiAutomator2 server session deletion. ` + `Original error: ${err.message}`,
271
258
  );
272
259
  }
273
260
 
@@ -283,10 +270,7 @@ export class UiAutomator2Server {
283
270
  }
284
271
 
285
272
  try {
286
- await Promise.all([
287
- this.adb.forceStop(SERVER_PACKAGE_ID),
288
- this.adb.forceStop(SERVER_TEST_PACKAGE_ID),
289
- ]);
273
+ await Promise.all([this.adb.forceStop(SERVER_PACKAGE_ID), this.adb.forceStop(SERVER_TEST_PACKAGE_ID)]);
290
274
  } catch {}
291
275
  }
292
276
 
@@ -302,10 +286,7 @@ export class UiAutomator2Server {
302
286
  // since it does not contain any version info
303
287
  resultInfo.installState = this.adb.APP_INSTALL_STATE.SAME_VERSION_INSTALLED;
304
288
  } else if (appId === SERVER_PACKAGE_ID) {
305
- resultInfo.installState = await this.adb.getApplicationInstallState(
306
- resultInfo.appPath,
307
- appId,
308
- );
289
+ resultInfo.installState = await this.adb.getApplicationInstallState(resultInfo.appPath, appId);
309
290
  }
310
291
 
311
292
  return resultInfo;
@@ -330,10 +311,9 @@ export class UiAutomator2Server {
330
311
  ({installState}) => installState !== this.adb.APP_INSTALL_STATE.NOT_INSTALLED,
331
312
  );
332
313
  const isAnyComponentNotInstalledOrNewer = packagesInfo.some(({installState}) =>
333
- [
334
- this.adb.APP_INSTALL_STATE.NOT_INSTALLED,
335
- this.adb.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED,
336
- ].includes(installState),
314
+ [this.adb.APP_INSTALL_STATE.NOT_INSTALLED, this.adb.APP_INSTALL_STATE.NEWER_VERSION_INSTALLED].includes(
315
+ installState,
316
+ ),
337
317
  );
338
318
  return isAnyComponentInstalled && isAnyComponentNotInstalledOrNewer;
339
319
  }
@@ -347,10 +327,9 @@ export class UiAutomator2Server {
347
327
  */
348
328
  private shouldInstallServerPackages(packagesInfo: PackageInfo[] = []): boolean {
349
329
  return packagesInfo.some(({installState}) =>
350
- [
351
- this.adb.APP_INSTALL_STATE.NOT_INSTALLED,
352
- this.adb.APP_INSTALL_STATE.OLDER_VERSION_INSTALLED,
353
- ].includes(installState),
330
+ [this.adb.APP_INSTALL_STATE.NOT_INSTALLED, this.adb.APP_INSTALL_STATE.OLDER_VERSION_INSTALLED].includes(
331
+ installState,
332
+ ),
354
333
  );
355
334
  }
356
335
 
@@ -390,9 +369,7 @@ export class UiAutomator2Server {
390
369
  );
391
370
  } catch {
392
371
  const errorMessage = (pmError as any)?.message || 'Unknown error';
393
- this.log.error(
394
- `Unable to find instrumentation target '${INSTRUMENTATION_TARGET}': ${errorMessage}`,
395
- );
372
+ this.log.error(`Unable to find instrumentation target '${INSTRUMENTATION_TARGET}': ${errorMessage}`);
396
373
  if (pmOutput) {
397
374
  this.log.debug('Available targets:');
398
375
  for (const line of pmOutput.split('\n')) {
@@ -408,11 +385,7 @@ export class UiAutomator2Server {
408
385
  cmd.push('--no-window-animation');
409
386
  }
410
387
  if (typeof this.disableSuppressAccessibilityService === 'boolean') {
411
- cmd.push(
412
- '-e',
413
- 'DISABLE_SUPPRESS_ACCESSIBILITY_SERVICES',
414
- `${this.disableSuppressAccessibilityService}`,
415
- );
388
+ cmd.push('-e', 'DISABLE_SUPPRESS_ACCESSIBILITY_SERVICES', `${this.disableSuppressAccessibilityService}`);
416
389
  }
417
390
  // Disable Google analytics to prevent possible fatal exception
418
391
  cmd.push('-e', 'disableAnalytics', 'true');
@@ -424,9 +397,7 @@ export class UiAutomator2Server {
424
397
  );
425
398
  }
426
399
  this.instrumentationProcess.once('exit', (code: number | null, signal: string | null) => {
427
- this.log.debug(
428
- `[Instrumentation] The process has exited with code ${code}, signal ${signal}`,
429
- );
400
+ this.log.debug(`[Instrumentation] The process has exited with code ${code}, signal ${signal}`);
430
401
  this.jwproxy.didInstrumentationExit = true;
431
402
  });
432
403
  await this.instrumentationProcess.start(0);
@@ -444,9 +415,7 @@ export class UiAutomator2Server {
444
415
  }
445
416
 
446
417
  private async cleanupAutomationLeftovers(strictCleanup: boolean = false): Promise<void> {
447
- this.log.debug(
448
- `Performing ${strictCleanup ? 'strict' : 'shallow'} cleanup of automation leftovers`,
449
- );
418
+ this.log.debug(`Performing ${strictCleanup ? 'strict' : 'shallow'} cleanup of automation leftovers`);
450
419
 
451
420
  const serverBase = `http://${this.host}:${this.systemPort}`;
452
421
  try {
@@ -459,9 +428,7 @@ export class UiAutomator2Server {
459
428
  const activeSessionIds = value.map(({id}) => id).filter(Boolean);
460
429
  if (activeSessionIds.length) {
461
430
  this.log.debug(`The following obsolete sessions are still running: ${activeSessionIds}`);
462
- this.log.debug(
463
- `Cleaning up ${util.pluralize('obsolete session', activeSessionIds.length, true)}`,
464
- );
431
+ this.log.debug(`Cleaning up ${util.pluralize('obsolete session', activeSessionIds.length, true)}`);
465
432
  await Promise.all(
466
433
  activeSessionIds.map((id: string) =>
467
434
  axios.delete(`${serverBase}/session/${id}`, {
@@ -479,10 +446,7 @@ export class UiAutomator2Server {
479
446
  }
480
447
 
481
448
  try {
482
- await Promise.all([
483
- this.adb.forceStop(SERVER_PACKAGE_ID),
484
- this.adb.forceStop(SERVER_TEST_PACKAGE_ID),
485
- ]);
449
+ await Promise.all([this.adb.forceStop(SERVER_PACKAGE_ID), this.adb.forceStop(SERVER_TEST_PACKAGE_ID)]);
486
450
  } catch {}
487
451
  if (strictCleanup) {
488
452
  // https://github.com/appium/appium/issues/10749
@@ -1,11 +1,13 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+
1
4
  import type {Orientation, StringRecord} from '@appium/types';
2
- import {SETTINGS_HELPER_ID} from 'io.appium.settings';
3
5
  import {util} from 'appium/support.js';
4
6
  import {retryInterval} from 'asyncbox';
5
- import os from 'node:os';
6
- import path from 'node:path';
7
+ import {SETTINGS_HELPER_ID} from 'io.appium.settings';
7
8
  import {checkPortStatus, findAPortNotInUse} from 'portscanner';
8
9
  import type {ExecError} from 'teen_process';
10
+
9
11
  import type {AndroidUiautomator2Driver} from '../driver.js';
10
12
  import type {
11
13
  EmptyObject,
@@ -23,10 +25,10 @@ const DEVICE_PORT_RANGE = [8200, 8299];
23
25
 
24
26
  // The guard is needed to avoid dynamic system port allocation conflicts for
25
27
  // parallel driver sessions
26
- const DEVICE_PORT_ALLOCATION_GUARD = util.getLockFileGuard(
27
- path.resolve(os.tmpdir(), 'uia2_device_port_guard'),
28
- {timeout: 25, tryRecovery: true},
29
- );
28
+ const DEVICE_PORT_ALLOCATION_GUARD = util.getLockFileGuard(path.resolve(os.tmpdir(), 'uia2_device_port_guard'), {
29
+ timeout: 25,
30
+ tryRecovery: true,
31
+ });
30
32
 
31
33
  // This is the port that UiAutomator2 listens to on the device. We will forward
32
34
  // one of the ports above on the system to this port on the device.
@@ -112,9 +114,7 @@ export async function releaseMjpegServerPort(this: AndroidUiautomator2Driver) {
112
114
  }
113
115
 
114
116
  /** Runs device preparation steps before the UiAutomator2 server session starts. */
115
- export async function performPreExecSetup(
116
- this: AndroidUiautomator2Driver,
117
- ): Promise<StringRecord | undefined> {
117
+ export async function performPreExecSetup(this: AndroidUiautomator2Driver): Promise<StringRecord | undefined> {
118
118
  const apiLevel = await this.adb.getApiLevel();
119
119
  if (apiLevel < MIN_SUPPORTED_API_LEVEL) {
120
120
  throw this.log.errorWithException('UIAutomator2 only supports Android 8.0 (Oreo) and above');
@@ -144,9 +144,7 @@ export async function performPreExecSetup(
144
144
  if (util.hasValue(this.opts.gpsEnabled)) {
145
145
  preflightPromises.push(
146
146
  (async () => {
147
- this.log.info(
148
- `Trying to ${this.opts.gpsEnabled ? 'enable' : 'disable'} gps location provider`,
149
- );
147
+ this.log.info(`Trying to ${this.opts.gpsEnabled ? 'enable' : 'disable'} gps location provider`);
150
148
  await this.adb.toggleGPSLocationProvider(Boolean(this.opts.gpsEnabled));
151
149
  })(),
152
150
  );
@@ -327,17 +325,10 @@ export async function initServer(this: AndroidUiautomator2Driver) {
327
325
  } else {
328
326
  await this.uiautomator2.installServerApk(this.opts.uiautomator2ServerInstallTimeout);
329
327
  try {
330
- await this.requireAdb().addToDeviceIdleWhitelist(
331
- SETTINGS_HELPER_ID,
332
- SERVER_PACKAGE_ID,
333
- SERVER_TEST_PACKAGE_ID,
334
- );
328
+ await this.requireAdb().addToDeviceIdleWhitelist(SETTINGS_HELPER_ID, SERVER_PACKAGE_ID, SERVER_TEST_PACKAGE_ID);
335
329
  } catch (e) {
336
330
  const err = e as ExecError;
337
- this.log.warn(
338
- `Cannot add server packages to the Doze whitelist. Original error: ` +
339
- (err.stderr || err.message),
340
- );
331
+ this.log.warn(`Cannot add server packages to the Doze whitelist. Original error: ` + (err.stderr || err.message));
341
332
  }
342
333
  }
343
334
 
package/lib/utils/app.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+
2
3
  import type {ADB} from 'appium-adb';
3
4
  import {fs, system} from 'appium/support.js';
4
5
 
@@ -1,10 +1,4 @@
1
- import {
2
- Transform,
3
- Writable,
4
- type Readable,
5
- type TransformCallback,
6
- type WritableOptions,
7
- } from 'node:stream';
1
+ import {Transform, Writable, type Readable, type TransformCallback, type WritableOptions} from 'node:stream';
8
2
 
9
3
  import {logger} from 'appium/support.js';
10
4
  import axios from 'axios';
@@ -144,11 +138,7 @@ export class MJpegStream extends Writable {
144
138
  * @param errorHandler - additional function that will be called in the case of any errors
145
139
  * @param options - Options to pass to the Writable constructor
146
140
  */
147
- constructor(
148
- mJpegUrl: string,
149
- errorHandler: (err: Error) => void = noop,
150
- options: WritableOptions = {},
151
- ) {
141
+ constructor(mJpegUrl: string, errorHandler: (err: Error) => void = noop, options: WritableOptions = {}) {
152
142
  super(options);
153
143
  this.errorHandler = errorHandler;
154
144
  this.url = mJpegUrl;
@@ -216,12 +206,9 @@ export class MJpegStream extends Writable {
216
206
  } else {
217
207
  message = String(e);
218
208
  }
219
- throw new Error(
220
- `Cannot connect to the MJPEG stream at ${url}. Original error: ${message}`,
221
- {
222
- cause: e,
223
- },
224
- );
209
+ throw new Error(`Cannot connect to the MJPEG stream at ${url}. Original error: ${message}`, {
210
+ cause: e,
211
+ });
225
212
  }
226
213
  } finally {
227
214
  clearTimeout(connectTimeoutId);
@@ -238,9 +225,7 @@ export class MJpegStream extends Writable {
238
225
  this.lastChunk = null;
239
226
  // No-op if start() has already resolved; only rejects a still-pending start().
240
227
  this.registerStartFailure?.(
241
- new Error(
242
- `The connection to the MJPEG stream at ${url} has been closed before any frame was received`,
243
- ),
228
+ new Error(`The connection to the MJPEG stream at ${url} has been closed before any frame was received`),
244
229
  );
245
230
  };
246
231
 
@@ -249,8 +234,7 @@ export class MJpegStream extends Writable {
249
234
  this.registerStartSuccess = resolve;
250
235
  this.registerStartFailure = reject;
251
236
  timeoutId = setTimeout(
252
- () =>
253
- reject(new Error(`Waited ${serverTimeout}ms but the MJPEG server never sent any images`)),
237
+ () => reject(new Error(`Waited ${serverTimeout}ms but the MJPEG server never sent any images`)),
254
238
  serverTimeout,
255
239
  );
256
240
  });
@@ -286,11 +270,7 @@ export class MJpegStream extends Writable {
286
270
  }
287
271
 
288
272
  /* eslint-disable promise/prefer-await-to-callbacks -- Writable._write is callback-based */
289
- override _write(
290
- chunk: Buffer | string,
291
- _encoding: BufferEncoding,
292
- callback: (error?: Error | null) => void,
293
- ): void {
273
+ override _write(chunk: Buffer | string, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
294
274
  this.lastChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
295
275
  this.updateCount++;
296
276
  if (this.registerStartSuccess) {
@@ -2,10 +2,7 @@
2
2
  * Assigns own enumerable properties of `source` onto `target` only where `target[key] === undefined`
3
3
  * (lodash `defaults` semantics).
4
4
  */
5
- export function assignDefaults<T extends Record<string, unknown>>(
6
- target: T,
7
- source: Record<string, unknown>,
8
- ): void {
5
+ export function assignDefaults<T extends Record<string, unknown>>(target: T, source: Record<string, unknown>): void {
9
6
  for (const key of Object.keys(source)) {
10
7
  if (target[key] === undefined) {
11
8
  (target as Record<string, unknown>)[key] = source[key];