appium-uiautomator2-driver 2.0.5 → 2.0.8

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/lib/driver.js CHANGED
@@ -6,7 +6,6 @@ import {
6
6
  import { fs, util, mjpeg } from '@appium/support';
7
7
  import { retryInterval } from 'asyncbox';
8
8
  import B from 'bluebird';
9
- import logger from './logger';
10
9
  import commands from './commands/index';
11
10
  import { DEFAULT_ADB_PORT } from 'appium-adb';
12
11
  import uiautomator2Helpers from './helpers';
@@ -212,11 +211,11 @@ class AndroidUiautomator2Driver extends BaseDriver {
212
211
  _.defaults(this.opts, defaultOpts);
213
212
 
214
213
  if (this.isChromeSession) {
215
- logger.info("We're going to run a Chrome-based session");
214
+ this.log.info("We're going to run a Chrome-based session");
216
215
  let {pkg, activity} = helpers.getChromePkg(this.opts.browserName);
217
216
  this.opts.appPackage = this.caps.appPackage = pkg;
218
217
  this.opts.appActivity = this.caps.appActivity = activity;
219
- logger.info(`Chrome-type package and activity are ${pkg} and ${activity}`);
218
+ this.log.info(`Chrome-type package and activity are ${pkg} and ${activity}`);
220
219
  }
221
220
 
222
221
  if (this.opts.reboot) {
@@ -230,9 +229,9 @@ class AndroidUiautomator2Driver extends BaseDriver {
230
229
  } else if (this.opts.appPackage) {
231
230
  // the app isn't an actual app file but rather something we want to
232
231
  // assume is on the device and just launch via the appPackage
233
- logger.info(`Starting '${this.opts.appPackage}' directly on the device`);
232
+ this.log.info(`Starting '${this.opts.appPackage}' directly on the device`);
234
233
  } else {
235
- logger.info(`Neither 'app' nor 'appPackage' was set. Starting UiAutomator2 ` +
234
+ this.log.info(`Neither 'app' nor 'appPackage' was set. Starting UiAutomator2 ` +
236
235
  'without the target application');
237
236
  }
238
237
  this.opts.adbPort = this.opts.adbPort || DEFAULT_ADB_PORT;
@@ -240,7 +239,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
240
239
  await this.startUiAutomator2Session();
241
240
  await this.fillDeviceDetails();
242
241
  if (this.opts.mjpegScreenshotUrl) {
243
- logger.info(`Starting MJPEG stream reading URL: '${this.opts.mjpegScreenshotUrl}'`);
242
+ this.log.info(`Starting MJPEG stream reading URL: '${this.opts.mjpegScreenshotUrl}'`);
244
243
  this.mjpegStream = new mjpeg.MJpegStream(this.opts.mjpegScreenshotUrl);
245
244
  await this.mjpegStream.start();
246
245
  }
@@ -264,7 +263,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
264
263
 
265
264
  async getSession () {
266
265
  let sessionData = await super.getSession();
267
- logger.debug('Getting session details from server to mix in');
266
+ this.log.debug('Getting session details from server to mix in');
268
267
  let uia2Data = await this.uiautomator2.jwproxy.command('/', 'GET', {});
269
268
  return Object.assign({}, sessionData, uia2Data);
270
269
  }
@@ -275,13 +274,13 @@ class AndroidUiautomator2Driver extends BaseDriver {
275
274
 
276
275
  setAvdFromCapabilities (caps) {
277
276
  if (this.opts.avd) {
278
- logger.info('avd name defined, ignoring device name and platform version');
277
+ this.log.info('avd name defined, ignoring device name and platform version');
279
278
  } else {
280
279
  if (!caps.deviceName) {
281
- logger.errorAndThrow('avd or deviceName should be specified when reboot option is enables');
280
+ this.log.errorAndThrow('avd or deviceName should be specified when reboot option is enables');
282
281
  }
283
282
  if (!caps.platformVersion) {
284
- logger.errorAndThrow('avd or platformVersion should be specified when reboot option is enabled');
283
+ this.log.errorAndThrow('avd or platformVersion should be specified when reboot option is enabled');
285
284
  }
286
285
  let avdDevice = caps.deviceName.replace(/[^a-zA-Z0-9_.]/g, '-');
287
286
  this.opts.avd = `${avdDevice}__${caps.platformVersion}`;
@@ -290,9 +289,9 @@ class AndroidUiautomator2Driver extends BaseDriver {
290
289
 
291
290
  async allocateSystemPort () {
292
291
  const forwardPort = async (localPort) => {
293
- logger.debug(`Forwarding UiAutomator2 Server port ${DEVICE_PORT} to local port ${localPort}`);
292
+ this.log.debug(`Forwarding UiAutomator2 Server port ${DEVICE_PORT} to local port ${localPort}`);
294
293
  if ((await checkPortStatus(localPort, LOCALHOST_IP4)) === 'open') {
295
- logger.errorAndThrow(`UiAutomator2 Server cannot start because the local port #${localPort} is busy. ` +
294
+ this.log.errorAndThrow(`UiAutomator2 Server cannot start because the local port #${localPort} is busy. ` +
296
295
  `Make sure the port you provide via 'systemPort' capability is not occupied. ` +
297
296
  `This situation might often be a result of an inaccurate sessions management, e.g. ` +
298
297
  `old automation sessions on the same device must always be closed before starting new ones.`);
@@ -310,7 +309,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
310
309
  try {
311
310
  this.opts.systemPort = await findAPortNotInUse(startPort, endPort);
312
311
  } catch (e) {
313
- logger.errorAndThrow(
312
+ this.log.errorAndThrow(
314
313
  `Cannot find any free port in range ${startPort}..${endPort}}. ` +
315
314
  `Please set the available port number by providing the systemPort capability or ` +
316
315
  `double check the processes that are locking ports within this range and terminate ` +
@@ -357,22 +356,22 @@ class AndroidUiautomator2Driver extends BaseDriver {
357
356
  const apiLevel = await this.adb.getApiLevel();
358
357
 
359
358
  if (apiLevel < 21) {
360
- logger.errorAndThrow('UIAutomator2 is only supported since Android 5.0 (Lollipop). ' +
359
+ this.log.errorAndThrow('UIAutomator2 is only supported since Android 5.0 (Lollipop). ' +
361
360
  'You could still use other supported backends in order to automate older Android versions.');
362
361
  }
363
362
 
364
363
  if (apiLevel >= 28) { // Android P
365
- logger.info('Relaxing hidden api policy');
364
+ this.log.info('Relaxing hidden api policy');
366
365
  await this.adb.setHiddenApiPolicy('1', !!this.opts.ignoreHiddenApiPolicyError);
367
366
  }
368
367
 
369
368
  // check if we have to enable/disable gps before running the application
370
369
  if (util.hasValue(this.opts.gpsEnabled)) {
371
370
  if (this.isEmulator()) {
372
- logger.info(`Trying to ${this.opts.gpsEnabled ? 'enable' : 'disable'} gps location provider`);
371
+ this.log.info(`Trying to ${this.opts.gpsEnabled ? 'enable' : 'disable'} gps location provider`);
373
372
  await this.adb.toggleGPSLocationProvider(this.opts.gpsEnabled);
374
373
  } else {
375
- logger.warn(`Sorry! 'gpsEnabled' capability is only available for emulators`);
374
+ this.log.warn(`Sorry! 'gpsEnabled' capability is only available for emulators`);
376
375
  }
377
376
  }
378
377
 
@@ -406,11 +405,11 @@ class AndroidUiautomator2Driver extends BaseDriver {
406
405
  // Read https://github.com/appium/appium/pull/11640#issuecomment-438260477
407
406
  // `--no-window-animation` works over Android 8 to disable all of animations
408
407
  if (await this.adb.isAnimationOn()) {
409
- logger.info('Disabling animation via io.appium.settings');
408
+ this.log.info('Disabling animation via io.appium.settings');
410
409
  await this.adb.setAnimationState(false);
411
410
  this._wasWindowAnimationDisabled = true;
412
411
  } else {
413
- logger.info('Window animation is already disabled');
412
+ this.log.info('Window animation is already disabled');
414
413
  }
415
414
  }
416
415
 
@@ -433,7 +432,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
433
432
  // unlock the device to prepare it for testing
434
433
  await helpers.unlock(this, this.adb, this.caps);
435
434
  } else {
436
- logger.debug(`'skipUnlock' capability set, so skipping device unlock`);
435
+ this.log.debug(`'skipUnlock' capability set, so skipping device unlock`);
437
436
  }
438
437
 
439
438
  if (this.isChromeSession) { // start a chromedriver session
@@ -444,7 +443,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
444
443
 
445
444
  // if the initial orientation is requested, set it
446
445
  if (util.hasValue(this.opts.orientation)) {
447
- logger.debug(`Setting initial orientation to '${this.opts.orientation}'`);
446
+ this.log.debug(`Setting initial orientation to '${this.opts.orientation}'`);
448
447
  await this.setOrientation(this.opts.orientation);
449
448
  }
450
449
 
@@ -453,7 +452,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
453
452
  if (this.opts.autoWebview) {
454
453
  const viewName = this.defaultWebviewName();
455
454
  const timeout = this.opts.autoWebviewTimeout || 2000;
456
- logger.info(`Setting auto webview to context '${viewName}' with timeout ${timeout}ms`);
455
+ this.log.info(`Setting auto webview to context '${viewName}' with timeout ${timeout}ms`);
457
456
  await retryInterval(timeout / 500, 500, this.setContext.bind(this), viewName);
458
457
  }
459
458
 
@@ -496,12 +495,12 @@ class AndroidUiautomator2Driver extends BaseDriver {
496
495
  };
497
496
  // now that we have package and activity, we can create an instance of
498
497
  // uiautomator2 with the appropriate options
499
- this.uiautomator2 = new UiAutomator2Server(uiautomator2Opts);
498
+ this.uiautomator2 = new UiAutomator2Server(this.log, uiautomator2Opts);
500
499
  this.proxyReqRes = this.uiautomator2.proxyReqRes.bind(this.uiautomator2);
501
500
  this.proxyCommand = this.uiautomator2.proxyCommand.bind(this.uiautomator2);
502
501
 
503
502
  if (this.opts.skipServerInstallation) {
504
- logger.info(`'skipServerInstallation' is set. Skipping UIAutomator2 server installation.`);
503
+ this.log.info(`'skipServerInstallation' is set. Skipping UIAutomator2 server installation.`);
505
504
  } else {
506
505
  await this.uiautomator2.installServerApk(this.opts.uiautomator2ServerInstallTimeout);
507
506
  try {
@@ -509,7 +508,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
509
508
  SETTINGS_HELPER_PKG_ID, SERVER_PACKAGE_ID, SERVER_TEST_PACKAGE_ID,
510
509
  );
511
510
  } catch (e) {
512
- logger.warn(`Cannot add server packages to the Doze whitelist. Original error: ` +
511
+ this.log.warn(`Cannot add server packages to the Doze whitelist. Original error: ` +
513
512
  (e.stderr || e.message));
514
513
  }
515
514
  }
@@ -531,7 +530,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
531
530
  try {
532
531
  otherApps = helpers.parseArray(this.opts.otherApps);
533
532
  } catch (e) {
534
- logger.errorAndThrow(`Could not parse "otherApps" capability: ${e.message}`);
533
+ this.log.errorAndThrow(`Could not parse "otherApps" capability: ${e.message}`);
535
534
  }
536
535
  otherApps = await B.all(otherApps
537
536
  .map((app) => this.helpers.configureApp(app, [APK_EXTENSION, APKS_EXTENSION])));
@@ -551,13 +550,13 @@ class AndroidUiautomator2Driver extends BaseDriver {
551
550
  }
552
551
  await helpers.installApk(this.adb, this.opts);
553
552
  } else {
554
- logger.debug('noReset has been requested and the app is already installed. Doing nothing');
553
+ this.log.debug('noReset has been requested and the app is already installed. Doing nothing');
555
554
  }
556
555
  } else {
557
556
  if (this.opts.fullReset) {
558
- logger.errorAndThrow('Full reset requires an app capability, use fastReset if app is not provided');
557
+ this.log.errorAndThrow('Full reset requires an app capability, use fastReset if app is not provided');
559
558
  }
560
- logger.debug('No app capability. Assuming it is already on the device');
559
+ this.log.debug('No app capability. Assuming it is already on the device');
561
560
  if (this.opts.fastReset && this.opts.appPackage) {
562
561
  await helpers.resetApp(this.adb, this.opts);
563
562
  }
@@ -569,11 +568,11 @@ class AndroidUiautomator2Driver extends BaseDriver {
569
568
  const appWaitPackage = this.opts.appWaitPackage || this.opts.appPackage;
570
569
  const appWaitActivity = this.opts.appWaitActivity || this.opts.appActivity;
571
570
 
572
- logger.info(`Starting '${this.opts.appPackage}/${this.opts.appActivity} ` +
571
+ this.log.info(`Starting '${this.opts.appPackage}/${this.opts.appActivity} ` +
573
572
  `and waiting for '${appWaitPackage}/${appWaitActivity}'`);
574
573
 
575
574
  if (this.caps.androidCoverage) {
576
- logger.info(`androidCoverage is configured. ` +
575
+ this.log.info(`androidCoverage is configured. ` +
577
576
  ` Starting instrumentation of '${this.caps.androidCoverage}'...`);
578
577
  await this.adb.androidCoverage(this.caps.androidCoverage, appWaitPackage, appWaitActivity);
579
578
  } else {
@@ -597,7 +596,7 @@ class AndroidUiautomator2Driver extends BaseDriver {
597
596
  }
598
597
 
599
598
  async deleteSession () {
600
- logger.debug('Deleting UiAutomator2 session');
599
+ this.log.debug('Deleting UiAutomator2 session');
601
600
 
602
601
  try {
603
602
  if (!_.isEmpty(this._screenRecordingProperties)) {
@@ -613,13 +612,13 @@ class AndroidUiautomator2Driver extends BaseDriver {
613
612
  try {
614
613
  await this.stopChromedriverProxies();
615
614
  } catch (err) {
616
- logger.warn(`Unable to stop ChromeDriver proxies: ${err.message}`);
615
+ this.log.warn(`Unable to stop ChromeDriver proxies: ${err.message}`);
617
616
  }
618
617
  if (this.jwpProxyActive) {
619
618
  try {
620
619
  await this.uiautomator2.deleteSession();
621
620
  } catch (err) {
622
- logger.warn(`Unable to proxy deleteSession to UiAutomator2: ${err.message}`);
621
+ this.log.warn(`Unable to proxy deleteSession to UiAutomator2: ${err.message}`);
623
622
  }
624
623
  }
625
624
  this.uiautomator2 = null;
@@ -628,22 +627,22 @@ class AndroidUiautomator2Driver extends BaseDriver {
628
627
 
629
628
  if (this.adb) {
630
629
  if (this.opts.unicodeKeyboard && this.opts.resetKeyboard && this.defaultIME) {
631
- logger.debug(`Resetting IME to '${this.defaultIME}'`);
630
+ this.log.debug(`Resetting IME to '${this.defaultIME}'`);
632
631
  try {
633
632
  await this.adb.setIME(this.defaultIME);
634
633
  } catch (err) {
635
- logger.warn(`Unable to reset IME: ${err.message}`);
634
+ this.log.warn(`Unable to reset IME: ${err.message}`);
636
635
  }
637
636
  }
638
637
  if (this.caps.androidCoverage) {
639
- logger.info('Shutting down the adb process of instrumentation...');
638
+ this.log.info('Shutting down the adb process of instrumentation...');
640
639
  await this.adb.endAndroidCoverage();
641
640
  // Use this broadcast intent to notify it's time to dump coverage to file
642
641
  if (this.caps.androidCoverageEndIntent) {
643
- logger.info(`Sending intent broadcast '${this.caps.androidCoverageEndIntent}' at the end of instrumenting.`);
642
+ this.log.info(`Sending intent broadcast '${this.caps.androidCoverageEndIntent}' at the end of instrumenting.`);
644
643
  await this.adb.broadcast(this.caps.androidCoverageEndIntent);
645
644
  } else {
646
- logger.warn('No androidCoverageEndIntent is configured in caps. Possibly you cannot get coverage file.');
645
+ this.log.warn('No androidCoverageEndIntent is configured in caps. Possibly you cannot get coverage file.');
647
646
  }
648
647
  }
649
648
  if (this.opts.appPackage) {
@@ -653,65 +652,65 @@ class AndroidUiautomator2Driver extends BaseDriver {
653
652
  try {
654
653
  await this.adb.forceStop(this.opts.appPackage);
655
654
  } catch (err) {
656
- logger.warn(`Unable to force stop app: ${err.message}`);
655
+ this.log.warn(`Unable to force stop app: ${err.message}`);
657
656
  }
658
657
  }
659
658
  if (this.opts.fullReset && !this.opts.skipUninstall) {
660
- logger.debug(`Capability 'fullReset' set to 'true', Uninstalling '${this.opts.appPackage}'`);
659
+ this.log.debug(`Capability 'fullReset' set to 'true', Uninstalling '${this.opts.appPackage}'`);
661
660
  try {
662
661
  await this.adb.uninstallApk(this.opts.appPackage);
663
662
  } catch (err) {
664
- logger.warn(`Unable to uninstall app: ${err.message}`);
663
+ this.log.warn(`Unable to uninstall app: ${err.message}`);
665
664
  }
666
665
  }
667
666
  }
668
667
  // This value can be true if test target device is <= 26
669
668
  if (this._wasWindowAnimationDisabled) {
670
- logger.info('Restoring window animation state');
669
+ this.log.info('Restoring window animation state');
671
670
  await this.adb.setAnimationState(true);
672
671
  }
673
672
  await this.adb.stopLogcat();
674
673
  try {
675
674
  await this.releaseSystemPort();
676
675
  } catch (error) {
677
- logger.warn(`Unable to remove system port forward: ${error.message}`);
676
+ this.log.warn(`Unable to remove system port forward: ${error.message}`);
678
677
  // Ignore, this block will also be called when we fall in catch block
679
678
  // and before even port forward.
680
679
  }
681
680
  try {
682
681
  await this.releaseMjpegServerPort();
683
682
  } catch (error) {
684
- logger.warn(`Unable to remove MJPEG server port forward: ${error.message}`);
683
+ this.log.warn(`Unable to remove MJPEG server port forward: ${error.message}`);
685
684
  // Ignore, this block will also be called when we fall in catch block
686
685
  // and before even port forward.
687
686
  }
688
687
 
689
688
  if (await this.adb.getApiLevel() >= 28) { // Android P
690
- logger.info('Restoring hidden api policy to the device default configuration');
689
+ this.log.info('Restoring hidden api policy to the device default configuration');
691
690
  await this.adb.setDefaultHiddenApiPolicy(!!this.opts.ignoreHiddenApiPolicyError);
692
691
  }
693
692
 
694
693
  if (this.opts.reboot) {
695
694
  let avdName = this.opts.avd.replace('@', '');
696
- logger.debug(`Closing emulator '${avdName}'`);
695
+ this.log.debug(`Closing emulator '${avdName}'`);
697
696
  try {
698
697
  await this.adb.killEmulator(avdName);
699
698
  } catch (err) {
700
- logger.warn(`Unable to close emulator: ${err.message}`);
699
+ this.log.warn(`Unable to close emulator: ${err.message}`);
701
700
  }
702
701
  }
703
702
  }
704
703
  if (this.mjpegStream) {
705
- logger.info('Closing MJPEG stream');
704
+ this.log.info('Closing MJPEG stream');
706
705
  this.mjpegStream.stop();
707
706
  }
708
707
  await super.deleteSession();
709
708
  }
710
709
 
711
710
  async checkAppPresent () {
712
- logger.debug('Checking whether app is actually present');
711
+ this.log.debug('Checking whether app is actually present');
713
712
  if (!(await fs.exists(this.opts.app))) {
714
- logger.errorAndThrow(`Could not find app apk at '${this.opts.app}'`);
713
+ this.log.errorAndThrow(`Could not find app apk at '${this.opts.app}'`);
715
714
  }
716
715
  }
717
716
 
@@ -1,7 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import { JWProxy, errors } from '@appium/base-driver';
3
3
  import { waitForCondition } from 'asyncbox';
4
- import log from './logger';
5
4
  import {
6
5
  SERVER_APK_PATH as apkPath,
7
6
  TEST_APK_PATH as testApkPath,
@@ -37,15 +36,17 @@ class UIA2Proxy extends JWProxy {
37
36
  }
38
37
 
39
38
  class UiAutomator2Server {
40
- constructor (opts = {}) {
39
+ constructor (log, opts = {}) {
41
40
  for (let req of REQD_PARAMS) {
42
41
  if (!opts || !util.hasValue(opts[req])) {
43
42
  throw new Error(`Option '${req}' is required!`);
44
43
  }
45
44
  this[req] = opts[req];
46
45
  }
46
+ this.log = log;
47
47
  this.disableSuppressAccessibilityService = opts.disableSuppressAccessibilityService;
48
48
  const proxyOpts = {
49
+ log,
49
50
  server: this.host,
50
51
  port: this.systemPort,
51
52
  keepAlive: true,
@@ -71,7 +72,7 @@ class UiAutomator2Server {
71
72
  return { appPath, appId };
72
73
  }
73
74
 
74
- log.info(`Server package at '${appPath}' is not writeable. ` +
75
+ this.log.info(`Server package at '${appPath}' is not writeable. ` +
75
76
  `Will copy it into the temporary location at '${tmpRoot}' as a workaround. ` +
76
77
  `Consider making this file writeable manually in order to improve the performance of session startup.`);
77
78
  const dstPath = path.resolve(tmpRoot, path.basename(appPath));
@@ -114,7 +115,7 @@ class UiAutomator2Server {
114
115
  }
115
116
 
116
117
  const appState = await this.adb.getApplicationInstallState(appPath, appId);
117
- log.debug(`${appId} installation state: ${appState}`);
118
+ this.log.debug(`${appId} installation state: ${appState}`);
118
119
  if (await this.adb.checkApkCert(appPath, appId)) {
119
120
  shouldUninstallServerPackages = shouldUninstallServerPackages || [
120
121
  this.adb.APP_INSTALL_STATE.OLDER_VERSION_INSTALLED,
@@ -130,16 +131,16 @@ class UiAutomator2Server {
130
131
  this.adb.APP_INSTALL_STATE.NOT_INSTALLED,
131
132
  ].includes(appState);
132
133
  }
133
- log.info(`Server packages are ${shouldInstallServerPackages ? '' : 'not '}going to be (re)installed`);
134
+ this.log.info(`Server packages are ${shouldInstallServerPackages ? '' : 'not '}going to be (re)installed`);
134
135
  if (shouldInstallServerPackages && shouldUninstallServerPackages) {
135
- log.info('Full packages reinstall is going to be performed');
136
+ this.log.info('Full packages reinstall is going to be performed');
136
137
  }
137
138
  for (const {appId, appPath} of packagesInfo) {
138
139
  if (shouldUninstallServerPackages) {
139
140
  try {
140
141
  await this.adb.uninstallApk(appId);
141
142
  } catch (err) {
142
- log.warn(`Error uninstalling '${appId}': ${err.message}`);
143
+ this.log.warn(`Error uninstalling '${appId}': ${err.message}`);
143
144
  }
144
145
  }
145
146
  if (shouldInstallServerPackages) {
@@ -159,7 +160,7 @@ class UiAutomator2Server {
159
160
  }
160
161
 
161
162
  async verifyServicesAvailability () {
162
- log.debug(`Waiting up to ${SERVICES_LAUNCH_TIMEOUT}ms for services to be available`);
163
+ this.log.debug(`Waiting up to ${SERVICES_LAUNCH_TIMEOUT}ms for services to be available`);
163
164
  let isPmServiceAvailable = false;
164
165
  let pmOutput = '';
165
166
  let pmError = null;
@@ -178,7 +179,7 @@ class UiAutomator2Server {
178
179
  pmOutput = ''; // remove output, so it is not printed below
179
180
  } else if (pmOutput.includes(INSTRUMENTATION_TARGET)) {
180
181
  pmOutput = ''; // remove output, so it is not printed below
181
- log.debug(`Instrumentation target '${INSTRUMENTATION_TARGET}' is available`);
182
+ this.log.debug(`Instrumentation target '${INSTRUMENTATION_TARGET}' is available`);
182
183
  // eslint-disable-next-line require-atomic-updates
183
184
  isPmServiceAvailable = true;
184
185
  } else if (!pmError) {
@@ -191,11 +192,11 @@ class UiAutomator2Server {
191
192
  intervalMs: 1000,
192
193
  });
193
194
  } catch (err) {
194
- log.error(`Unable to find instrumentation target '${INSTRUMENTATION_TARGET}': ${(pmError || {}).message}`);
195
+ this.log.error(`Unable to find instrumentation target '${INSTRUMENTATION_TARGET}': ${(pmError || {}).message}`);
195
196
  if (pmOutput) {
196
- log.debug('Available targets:');
197
+ this.log.debug('Available targets:');
197
198
  for (const line of pmOutput.split('\n')) {
198
- log.debug(` ${line.replace('instrumentation:', '')}`);
199
+ this.log.debug(` ${line.replace('instrumentation:', '')}`);
199
200
  }
200
201
  }
201
202
  }
@@ -204,10 +205,10 @@ class UiAutomator2Server {
204
205
  async startSession (caps) {
205
206
  await this.cleanupAutomationLeftovers();
206
207
  if (caps.skipServerInstallation) {
207
- log.info(`'skipServerInstallation' is set. Attempting to use UIAutomator2 server from the device`);
208
+ this.log.info(`'skipServerInstallation' is set. Attempting to use UIAutomator2 server from the device`);
208
209
  } else {
209
- log.info(`Starting UIAutomator2 server ${serverVersion}`);
210
- log.info(`Using UIAutomator2 server from '${apkPath}' and test from '${testApkPath}'`);
210
+ this.log.info(`Starting UIAutomator2 server ${serverVersion}`);
211
+ this.log.info(`Using UIAutomator2 server from '${apkPath}' and test from '${testApkPath}'`);
211
212
  }
212
213
 
213
214
  const timeout = caps.uiautomator2ServerLaunchTimeout || SERVER_LAUNCH_TIMEOUT;
@@ -216,7 +217,7 @@ class UiAutomator2Server {
216
217
  const maxRetries = 2;
217
218
  const delayBetweenRetries = 3000;
218
219
  while (retries < maxRetries) {
219
- log.info(`Waiting up to ${timeout}ms for UiAutomator2 to be online...`);
220
+ this.log.info(`Waiting up to ${timeout}ms for UiAutomator2 to be online...`);
220
221
  this.jwproxy.didInstrumentationExit = false;
221
222
  await this.startInstrumentationProcess();
222
223
  if (!this.jwproxy.didInstrumentationExit) {
@@ -234,7 +235,7 @@ class UiAutomator2Server {
234
235
  intervalMs: 1000,
235
236
  });
236
237
  } catch (err) {
237
- log.errorAndThrow(`The instrumentation process cannot be initialized within ${timeout}ms timeout. `
238
+ this.log.errorAndThrow(`The instrumentation process cannot be initialized within ${timeout}ms timeout. `
238
239
  + 'Make sure the application under test does not crash and investigate the logcat output. '
239
240
  + `You could also try to increase the value of 'uiautomator2ServerLaunchTimeout' capability`);
240
241
  }
@@ -245,16 +246,16 @@ class UiAutomator2Server {
245
246
 
246
247
  retries++;
247
248
  if (retries >= maxRetries) {
248
- log.errorAndThrow('The instrumentation process cannot be initialized. '
249
+ this.log.errorAndThrow('The instrumentation process cannot be initialized. '
249
250
  + 'Make sure the application under test does not crash and investigate the logcat output.');
250
251
  }
251
- log.warn(`The instrumentation process has been unexpectedly terminated. `
252
+ this.log.warn(`The instrumentation process has been unexpectedly terminated. `
252
253
  + `Retrying UiAutomator2 startup (#${retries} of ${maxRetries - 1})`);
253
254
  await this.cleanupAutomationLeftovers(true);
254
255
  await B.delay(delayBetweenRetries);
255
256
  }
256
257
 
257
- log.debug(`The initialization of the instrumentation process took `
258
+ this.log.debug(`The initialization of the instrumentation process took `
258
259
  + `${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
259
260
  await this.jwproxy.command('/session', 'POST', {
260
261
  capabilities: {
@@ -290,19 +291,19 @@ class UiAutomator2Server {
290
291
  }
291
292
 
292
293
  async deleteSession () {
293
- log.debug('Deleting UiAutomator2 server session');
294
+ this.log.debug('Deleting UiAutomator2 server session');
294
295
  // rely on jwproxy's intelligence to know what we're talking about and
295
296
  // delete the current session
296
297
  try {
297
298
  await this.jwproxy.command('/', 'DELETE');
298
299
  } catch (err) {
299
- log.warn(`Did not get confirmation UiAutomator2 deleteSession worked; ` +
300
+ this.log.warn(`Did not get confirmation UiAutomator2 deleteSession worked; ` +
300
301
  `Error was: ${err}`);
301
302
  }
302
303
  }
303
304
 
304
305
  async cleanupAutomationLeftovers (strictCleanup = false) {
305
- log.debug(`Performing ${strictCleanup ? 'strict' : 'shallow'} cleanup of automation leftovers`);
306
+ this.log.debug(`Performing ${strictCleanup ? 'strict' : 'shallow'} cleanup of automation leftovers`);
306
307
 
307
308
  try {
308
309
  const {value} = (await axios({
@@ -311,18 +312,18 @@ class UiAutomator2Server {
311
312
  })).data;
312
313
  const activeSessionIds = value.map(({id}) => id).filter(Boolean);
313
314
  if (activeSessionIds.length) {
314
- log.debug(`The following obsolete sessions are still running: ${JSON.stringify(activeSessionIds)}`);
315
- log.debug(`Cleaning up ${util.pluralize('obsolete session', activeSessionIds.length, true)}`);
315
+ this.log.debug(`The following obsolete sessions are still running: ${JSON.stringify(activeSessionIds)}`);
316
+ this.log.debug(`Cleaning up ${util.pluralize('obsolete session', activeSessionIds.length, true)}`);
316
317
  await B.all(activeSessionIds
317
318
  .map((id) => axios.delete(`http://${this.host}:${this.systemPort}/session/${id}`))
318
319
  );
319
320
  // Let all sessions to be properly terminated before continuing
320
321
  await B.delay(1000);
321
322
  } else {
322
- log.debug('No obsolete sessions have been detected');
323
+ this.log.debug('No obsolete sessions have been detected');
323
324
  }
324
325
  } catch (e) {
325
- log.debug(`No obsolete sessions have been detected (${e.message})`);
326
+ this.log.debug(`No obsolete sessions have been detected (${e.message})`);
326
327
  }
327
328
 
328
329
  try {