Repository: wix/Detox
Pull request #1989 (2020-04-01 13:06:28)

Break emulator class into more contained sub-concern classes
- [ ] This is a small change 
- [ ] This change has been discussed in issue #<?> and the solution has been agreed upon with maintainers.

---

**Description:**
Final episode (I think) for season 1, continuing #1988, #1987, #1984. It's been quite a ride. `Emulator` class is dead, but it's children live on.


Patch:
diff --git a/detox/package.json b/detox/package.json
index 1606beb1b..15391f73c 100644
--- a/detox/package.json
+++ b/detox/package.json
@@ -91,7 +91,7 @@
       "MissingDetox.js",
       "EmulatorTelnet.js",
       "EmulatorExec.js",
-      "Emulator.js",
+      "EmulatorLauncher.js",
       "DeviceDriverBase.js",
       "GREYConfiguration.js",
       "src/utils/environment.js",
diff --git a/detox/src/devices/drivers/android/EmulatorDriver.js b/detox/src/devices/drivers/android/EmulatorDriver.js
index 6b7171e0f..647cb0bb2 100644
--- a/detox/src/devices/drivers/android/EmulatorDriver.js
+++ b/detox/src/devices/drivers/android/EmulatorDriver.js
@@ -3,12 +3,14 @@ const fs = require('fs');
 const path = require('path');
 const ini = require('ini');
 const AndroidDriver = require('./AndroidDriver');
-const EmulatorLookupHelper = require('./EmulatorLookupHelper');
+const FreeEmulatorFinder = require('./emulator/FreeEmulatorFinder');
+const AVDValidator = require('./emulator/AVDValidator');
+const EmulatorLauncher = require('./emulator/EmulatorLauncher');
+const { EmulatorExec } = require('./tools/EmulatorExec');
+const EmulatorTelnet = require('./tools/EmulatorTelnet');
+const EmulatorVersionResolver = require('./emulator/EmulatorVersionResolver');
 const DetoxRuntimeError = require('../../../errors/DetoxRuntimeError');
 const DeviceRegistry = require('../../DeviceRegistry');
-const Emulator = require('./tools/Emulator');
-const EmulatorTelnet = require('./tools/EmulatorTelnet');
-const EmulatorVersion = require('./EmulatorVersion');
 const environment = require('../../../utils/environment');
 const retry = require('../../../utils/retry');
 const log = require('../../../utils/logger').child({ __filename });
@@ -25,13 +27,17 @@ class EmulatorDriver extends AndroidDriver {
   constructor(config) {
     super(config);
 
-    this.emulator = new Emulator();
     this.deviceRegistry = new DeviceRegistry({
       lockfilePath: environment.getDeviceLockFilePathAndroid(),
     });
+
+    const emulatorExec = new EmulatorExec();
+    this._emuVersionResolver = new EmulatorVersionResolver(emulatorExec);
+    this._emuLauncher = new EmulatorLauncher(emulatorExec);
+    this._avdValidator = new AVDValidator(emulatorExec);
+
     this.pendingBoots = {};
     this._name = 'Unspecified Emulator';
-    this._emulatorVersion = new EmulatorVersion(this.emulator);
   }
 
   get name() {
@@ -41,7 +47,7 @@ class EmulatorDriver extends AndroidDriver {
   async acquireFreeDevice(deviceQuery) {
     const avdName = _.isPlainObject(deviceQuery) ? deviceQuery.avdName : deviceQuery;
 
-    await this._validateAvd(avdName);
+    await this._avdValidator.validate(avdName);
     await this._fixEmulatorConfigIniSkinNameIfNeeded(avdName);
 
     const adbName = await this._allocateDevice(avdName);
@@ -61,7 +67,7 @@ class EmulatorDriver extends AndroidDriver {
   }
 
   /*async*/ binaryVersion() {
-    return this._emulatorVersion.resolve();
+    return this._emuVersionResolver.resolve();
   }
 
   async _boot(avdName, adbName) {
@@ -69,7 +75,7 @@ class EmulatorDriver extends AndroidDriver {
 
     if (coldBoot) {
       const port = this.pendingBoots[adbName];
-      await this.emulator.boot(avdName, {port});
+      await this._emuLauncher.launch(avdName, { port });
       delete this.pendingBoots[adbName];
     }
 
@@ -77,22 +83,6 @@ class EmulatorDriver extends AndroidDriver {
     await this.emitter.emit('bootDevice', { coldBoot, deviceId: adbName, type: adbName });
   }
 
-  async _validateAvd(avdName) {
-    const avds = await this.emulator.listAvds();
-    if (!avds) {
-      const avdmanagerPath = path.join(environment.getAndroidSDKPath(), 'tools', 'bin', 'avdmanager');
-
-      throw new Error(`Could not find any configured Android Emulator. 
-      Try creating a device first, example: ${avdmanagerPath} create avd --force --name Pixel_2_API_26 --abi x86 --package 'system-images;android-26;google_apis_playstore;x86' --device "pixel"
-      or go to https://developer.android.com/studio/run/managing-avds.html for details on how to create an Emulator.`);
-    }
-
-    if (_.indexOf(avds, avdName) === -1) {
-      throw new Error(`Can not boot Android Emulator with the name: '${avdName}',
-      make sure you choose one of the available emulators: ${avds.toString()}`);
-    }
-  }
-
   async _waitForBootToComplete(deviceId) {
     await retry({ retries: 240, interval: 2500 }, async () => {
       const isBootComplete = await this.adb.isBootComplete(deviceId);
@@ -145,8 +135,8 @@ class EmulatorDriver extends AndroidDriver {
   }
 
   async _doAllocateDevice(avdName) {
-    const emulatorLookupHelper = new EmulatorLookupHelper(this.adb, this.deviceRegistry, avdName);
-    const freeEmulatorAdbName = await emulatorLookupHelper.findFreeDevice();
+    const freeEmulatorFinder = new FreeEmulatorFinder(this.adb, this.deviceRegistry, avdName);
+    const freeEmulatorAdbName = await freeEmulatorFinder.findFreeDevice();
     return freeEmulatorAdbName || this._createDevice();
   }
 
diff --git a/detox/src/devices/drivers/android/emulator/AVDValidator.js b/detox/src/devices/drivers/android/emulator/AVDValidator.js
new file mode 100644
index 000000000..dd6c89592
--- /dev/null
+++ b/detox/src/devices/drivers/android/emulator/AVDValidator.js
@@ -0,0 +1,28 @@
+const _ = require('lodash');
+const path = require('path');
+const AVDsResolver = require('./AVDsResolver');
+const environment = require('../../../../utils/environment');
+
+class AVDValidator {
+  constructor(emulatorExec) {
+    this._avdsResolver = new AVDsResolver(emulatorExec);
+  }
+
+  async validate(avdName) {
+    const avds = await this._avdsResolver.resolve(avdName);
+    if (!avds) {
+      const avdmanagerPath = path.join(environment.getAndroidSDKPath(), 'tools', 'bin', 'avdmanager');
+
+      throw new Error(`Could not find any configured Android Emulator.\n
+        Try creating a device first, example: ${avdmanagerPath} create avd --force --name Pixel_API_28 --abi x86_64 --package "system-images;android-28;default;x86_64" --device "pixel"
+        or go to https://developer.android.com/studio/run/managing-avds.html for details on how to create an Emulator.`);
+    }
+
+    if (_.indexOf(avds, avdName) === -1) {
+      throw new Error(`Can not boot Android Emulator with the name: '${avdName}',
+        make sure you choose one of the available emulators: ${avds.toString()}`);
+    }
+  }
+}
+
+ module.exports = AVDValidator;
diff --git a/detox/src/devices/drivers/android/emulator/AVDsResolver.js b/detox/src/devices/drivers/android/emulator/AVDsResolver.js
new file mode 100644
index 000000000..910ad9c08
--- /dev/null
+++ b/detox/src/devices/drivers/android/emulator/AVDsResolver.js
@@ -0,0 +1,15 @@
+const { ListAVDsCommand } = require('../tools/EmulatorExec');
+
+class AVDsResolver {
+  constructor(emulatorExec) {
+    this._emulatorExec = emulatorExec;
+  }
+
+  async resolve() {
+    const output = await this._emulatorExec.exec(new ListAVDsCommand());
+    const avds = output.trim().split('\n');
+    return avds;
+  }
+}
+
+module.exports = AVDsResolver;
diff --git a/detox/src/devices/drivers/android/tools/Emulator.js b/detox/src/devices/drivers/android/emulator/EmulatorLauncher.js
similarity index 75%
rename from detox/src/devices/drivers/android/tools/Emulator.js
rename to detox/src/devices/drivers/android/emulator/EmulatorLauncher.js
index e524b78a6..c3c8ba310 100644
--- a/detox/src/devices/drivers/android/tools/Emulator.js
+++ b/detox/src/devices/drivers/android/emulator/EmulatorLauncher.js
@@ -1,33 +1,18 @@
 const _ = require('lodash');
 const fs = require('fs');
 const Tail = require('tail').Tail;
+const { LaunchCommand } = require('../tools/EmulatorExec');
 const unitLogger = require('../../../../utils/logger').child({ __filename });
 const retry = require('../../../../utils/retry');
-const {
-  EmulatorExec,
-  ListAVDsCommand,
-  QueryVersionCommand,
-  LaunchCommand,
-} = require('./EmulatorExec');
 
 const isUnknownEmulatorError = (err) => (err.message || '').includes('failed with code null');
 
-class Emulator {
-  constructor() {
-    this.emulatorExec = new EmulatorExec();
+class EmulatorLauncher {
+  constructor(emulatorExec) {
+    this._emulatorExec = emulatorExec;
   }
 
-  async listAvds() {
-    const output = await this.emulatorExec.exec(new ListAVDsCommand());
-    const avds = output.trim().split('\n');
-    return avds;
-  }
-
-  async queryVersion() {
-    return await this.emulatorExec.exec(new QueryVersionCommand());
-  }
-
-  async boot(emulatorName, options = {port: undefined}) {
+  async launch(emulatorName, options = {port: undefined}) {
     const launchCommand = new LaunchCommand(emulatorName, options);
 
     return await retry({
@@ -70,8 +55,8 @@ class Emulator {
     }
 
     let log = unitLogger.child({ fn: 'boot' });
-    log.debug({ event: 'SPAWN_CMD' }, this.emulatorExec.toString(), launchCommand.toString());
-    const childProcessPromise = this.emulatorExec.spawn(launchCommand, stdout, stderr);
+    log.debug({ event: 'SPAWN_CMD' }, this._emulatorExec.toString(), launchCommand.toString());
+    const childProcessPromise = this._emulatorExec.spawn(launchCommand, stdout, stderr);
     childProcessPromise.childProcess.unref();
     log = log.child({ child_pid: childProcessPromise.childProcess.pid });
 
@@ -93,4 +78,4 @@ class Emulator {
   }
 }
 
-module.exports = Emulator;
+module.exports = EmulatorLauncher;
diff --git a/detox/src/devices/drivers/android/EmulatorVersion.js b/detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.js
similarity index 71%
rename from detox/src/devices/drivers/android/EmulatorVersion.js
rename to detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.js
index 321ddec69..e9d2666d6 100644
--- a/detox/src/devices/drivers/android/EmulatorVersion.js
+++ b/detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.js
@@ -1,10 +1,11 @@
-const log = require('../../../utils/logger').child({ __filename });
+const {QueryVersionCommand} = require('../tools/EmulatorExec');
+const log = require('../../../../utils/logger').child({ __filename });
 
 const EMU_BIN_VERSION_DETECT_EV = 'EMU_BIN_VERSION_DETECT';
 
-class EmulatorVersion {
-  constructor(emulator) {
-    this.emulator = emulator;
+class EmulatorVersionResolver {
+  constructor(emulatorExec) {
+    this._emulatorExec = emulatorExec;
     this.version = undefined;
   }
 
@@ -16,7 +17,7 @@ class EmulatorVersion {
   }
 
   async _resolve() {
-    const rawOutput = await this.emulator.queryVersion() || '';
+    const rawOutput = await this._emulatorExec.exec(new QueryVersionCommand()) || '';
     const matches = rawOutput.match(/Android emulator version ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]*)/);
     if (!matches) {
       log.warn({ event: EMU_BIN_VERSION_DETECT_EV, success: false }, 'Could not detect emulator binary version, got:', rawOutput);
@@ -37,4 +38,4 @@ class EmulatorVersion {
     };
   }
 }
-module.exports = EmulatorVersion;
+module.exports = EmulatorVersionResolver;
diff --git a/detox/src/devices/drivers/android/EmulatorLookupHelper.js b/detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.js
similarity index 83%
rename from detox/src/devices/drivers/android/EmulatorLookupHelper.js
rename to detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.js
index 89305e51d..2ad8e4f96 100644
--- a/detox/src/devices/drivers/android/EmulatorLookupHelper.js
+++ b/detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.js
@@ -1,9 +1,9 @@
-const log = require('../../../utils/logger').child({ __filename });
-const AdbDevicesHelper = require('./AdbDevicesHelper');
+const AdbDevicesHelper = require('../tools/AdbDevicesHelper');
+const log = require('../../../../utils/logger').child({ __filename });
 
 const ACQUIRE_DEVICE_EV = 'ACQUIRE_DEVICE';
 
-class EmulatorLookupHelper {
+class FreeEmulatorFinder {
   constructor(adb, deviceRegistry, avdName) {
     this.adbDevicesHelper = new AdbDevicesHelper(adb);
     this.deviceRegistry = deviceRegistry;
@@ -32,4 +32,5 @@ class EmulatorLookupHelper {
     return false;
   }
 }
-module.exports = EmulatorLookupHelper;
+
+module.exports = FreeEmulatorFinder;


Test patch:
diff --git a/detox/src/devices/drivers/android/emulator/AVDValidator.test.js b/detox/src/devices/drivers/android/emulator/AVDValidator.test.js
new file mode 100644
index 000000000..6ea639e7c
--- /dev/null
+++ b/detox/src/devices/drivers/android/emulator/AVDValidator.test.js
@@ -0,0 +1,53 @@
+describe('AVD validator', () => {
+  let mockAvdsResolver;
+
+  class MockAVDsResolver {
+    constructor(...args) {
+      mockAvdsResolver.ctor(...args);
+      this.resolve = mockAvdsResolver.resolve;
+    }
+  }
+
+  const emulatorExec = {};
+  let uut;
+  beforeEach(() => {
+    mockAvdsResolver = {
+      ctor: jest.fn(),
+      resolve: jest.fn().mockResolvedValue(['mock-avd-name']),
+    };
+    jest.mock('./AVDsResolver', () => MockAVDsResolver);
+
+    const AVDValidator = require('./AVDValidator');
+    uut = new AVDValidator(emulatorExec);
+  });
+
+  it('should use an AVDs resolver', async () => {
+    await uut.validate('mock-avd-name');
+
+    expect(mockAvdsResolver.ctor).toHaveBeenCalledWith(emulatorExec);
+    expect(mockAvdsResolver.resolve).toHaveBeenCalledWith('mock-avd-name');
+  });
+
+  it('should return safely if AVD exists', async () => {
+    mockAvdsResolver.resolve.mockResolvedValue(['mock-avd-name']);
+    await uut.validate('mock-avd-name');
+  });
+
+  it('should throw if no AVDs found', async () => {
+    mockAvdsResolver.resolve.mockResolvedValue(undefined);
+
+    try {
+      await uut.validate();
+      fail('expected to throw');
+    } catch (err) {}
+  });
+
+  it('should throw if specific AVD not found', async () => {
+    mockAvdsResolver.resolve.mockResolvedValue(['other-avd', 'yet-another']);
+
+    try {
+      await uut.validate();
+      fail('expected to throw');
+    } catch (err) {}
+  });
+});
diff --git a/detox/src/devices/drivers/android/emulator/AVDsResolver.test.js b/detox/src/devices/drivers/android/emulator/AVDsResolver.test.js
new file mode 100644
index 000000000..45747d672
--- /dev/null
+++ b/detox/src/devices/drivers/android/emulator/AVDsResolver.test.js
@@ -0,0 +1,28 @@
+describe('AVDs resolver', () => {
+  let MockListAVDsCommand;
+  let emulatorExec;
+  let uut;
+  beforeEach(() => {
+    MockListAVDsCommand = jest.genMockFromModule('../tools/EmulatorExec').ListAVDsCommand;
+    jest.mock('../tools/EmulatorExec', () => ({
+      ListAVDsCommand: MockListAVDsCommand,
+    }));
+
+    emulatorExec = {
+      exec: jest.fn().mockResolvedValue(''),
+    };
+
+    const AVDsResolver = require('./AVDsResolver');
+    uut = new AVDsResolver(emulatorExec);
+  });
+
+  it('should exec command', async () => {
+    await uut.resolve();
+    expect(emulatorExec.exec).toHaveBeenCalledWith(expect.any(MockListAVDsCommand));
+  });
+
+  it('should parse emulators list given as text', async () => {
+    emulatorExec.exec.mockResolvedValue('avd-device1\navd-device2\n');
+    expect(await uut.resolve()).toEqual(['avd-device1', 'avd-device2']);
+  });
+});
diff --git a/detox/src/devices/drivers/android/EmulatorVersion.test.js b/detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.test.js
similarity index 61%
rename from detox/src/devices/drivers/android/EmulatorVersion.test.js
rename to detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.test.js
index 089c08d5d..53409ed52 100644
--- a/detox/src/devices/drivers/android/EmulatorVersion.test.js
+++ b/detox/src/devices/drivers/android/emulator/EmulatorVersionResolver.test.js
@@ -17,64 +17,70 @@ describe('Emulator binary version', () => {
     patch: 2,
   };
 
-  let emulator;
+  let MockQueryVersionCommand;
+  let emulatorExec;
   let log;
-  let emulatorVersion;
+  let uut;
   beforeEach(() => {
-    emulator = {
-      queryVersion: jest.fn().mockResolvedValue(versionResult),
+    MockQueryVersionCommand = jest.genMockFromModule('../tools/EmulatorExec').QueryVersionCommand;
+    jest.mock('../tools/EmulatorExec', () => ({
+      QueryVersionCommand: MockQueryVersionCommand,
+    }));
+
+    emulatorExec = {
+      exec: jest.fn().mockResolvedValue(versionResult),
     };
 
-    jest.mock('../../../utils/logger', () => ({
+    jest.mock('../../../../utils/logger', () => ({
       child: jest.fn().mockReturnValue({
         debug: jest.fn(),
         warn: jest.fn(),
       }),
     }));
-    log = require('../../../utils/logger').child();
+    log = require('../../../../utils/logger').child();
 
-    const EmulatorVersion = require('./EmulatorVersion');
-    emulatorVersion = new EmulatorVersion(emulator);
+    const EmulatorVersionResolver = require('./EmulatorVersionResolver');
+    uut = new EmulatorVersionResolver(emulatorExec);
   });
 
   it('should query the emulator', async () => {
-    await emulatorVersion.resolve();
-    expect(emulator.queryVersion).toHaveBeenCalled();
+    await uut.resolve();
+    expect(emulatorExec.exec).toHaveBeenCalledWith(expect.any(MockQueryVersionCommand));
   });
 
   it('should extract version from common log', async () => {
-    const version = await emulatorVersion.resolve();
+    const version = await uut.resolve();
     expect(version).toEqual(expectedVersion);
   });
 
   it('should return null for an empty query result', async () => {
-    emulator.queryVersion.mockResolvedValue(undefined);
-    const version = await emulatorVersion.resolve();
+    emulatorExec.exec.mockResolvedValue(undefined);
+    const version = await uut.resolve();
     expect(version).toEqual(null);
   });
 
   it('should return null for a query result that has an invalid syntax', async () => {
-    emulator.queryVersion.mockResolvedValue('Android emulator version \<invalid\> (build_id 6306047) (CL:N/A)');
-    const version = await emulatorVersion.resolve();
+    emulatorExec.exec.mockResolvedValue('Android emulator version \<invalid\> (build_id 6306047) (CL:N/A)');
+    const version = await uut.resolve();
     expect(version).toEqual(null);
   });
 
   it('should cache the version', async () => {
-    await emulatorVersion.resolve();
-    const version = await emulatorVersion.resolve();
+    await uut.resolve();
+    const version = await uut.resolve();
 
-    expect(emulator.queryVersion).toHaveBeenCalledTimes(1);
+    expect(emulatorExec.exec).toHaveBeenCalledTimes(1);
     expect(version).toEqual(expectedVersion);
   });
 
   it('should log the version', async () => {
-    await emulatorVersion.resolve();
+    await uut.resolve();
     expect(log.debug).toHaveBeenCalledWith({event: 'EMU_BIN_VERSION_DETECT', success: true}, expect.any(String), expectedVersion);
   });
 
   it('should log in case of an error', async () => {
-    emulator.queryVersion.mockResolvedValue('mock result');
-    await emulatorVersion.resolve();
+    emulatorExec.exec.mockResolvedValue('mock result');
+    await uut.resolve();
     expect(log.warn).toHaveBeenCalledWith({event: 'EMU_BIN_VERSION_DETECT', success: false}, expect.any(String), 'mock result');
   });
 });
diff --git a/detox/src/devices/drivers/android/EmulatorLookupHelper.test.js b/detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.test.js
similarity index 79%
rename from detox/src/devices/drivers/android/EmulatorLookupHelper.test.js
rename to detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.test.js
index 3da54cad0..627636dd8 100644
--- a/detox/src/devices/drivers/android/EmulatorLookupHelper.test.js
+++ b/detox/src/devices/drivers/android/emulator/FreeEmulatorFinder.test.js
@@ -1,4 +1,3 @@
-
 describe('emulators lookup helper', () => {
   const mockAdb = {};
   const mockAvdName = 'mock-avd';
@@ -15,16 +14,16 @@ describe('emulators lookup helper', () => {
 
   let adbDevicesHelper;
   beforeEach(() => {
-    const AdbDevicesHelper = jest.genMockFromModule('./AdbDevicesHelper');
+    const AdbDevicesHelper = jest.genMockFromModule('../tools/AdbDevicesHelper');
     adbDevicesHelper = new AdbDevicesHelper();
     adbDevicesHelper.ctor = jest.fn();
-    jest.mock('./AdbDevicesHelper', () => MockAdbDevicesHelper);
+    jest.mock('../tools/AdbDevicesHelper', () => MockAdbDevicesHelper);
   });
 
   let mockDeviceRegistry;
-  let helper;
+  let uut;
   beforeEach(() => {
-    jest.mock('../../../utils/logger', () => ({
+    jest.mock('../../../../utils/logger', () => ({
       child: jest.fn().mockReturnValue({
         debug: jest.fn(),
       }),
@@ -34,24 +33,24 @@ describe('emulators lookup helper', () => {
       isDeviceBusy: jest.fn().mockReturnValue(false),
     };
 
-    const Helper = require('./EmulatorLookupHelper');
-    helper = new Helper(mockAdb, mockDeviceRegistry, mockAvdName);
+    const FreeEmulatorFinder = require('./FreeEmulatorFinder');
+    uut = new FreeEmulatorFinder(mockAdb, mockDeviceRegistry, mockAvdName);
   });
 
   it('should create an adb devices helper', async () => {
     expect(adbDevicesHelper.ctor).toHaveBeenCalledWith(mockAdb);
   });
 
-  it('should pass a custom matcher func onto adb-devices helper for finding a free devices', async () => {
-    await helper.findFreeDevice();
+  it('should pass a custom matcher func onto adb-devices helper for finding a free emulator', async () => {
+    await uut.findFreeDevice();
     expect(adbDevicesHelper.lookupDevice).toHaveBeenCalledWith(expect.any(Function));
   });
 
-  it('should return the matched device', async () => {
+  it('should return the matched emulator', async () => {
     const adbName = 'mock-adb-name';
     adbDevicesHelper.lookupDevice.mockReturnValue(adbName);
 
-    const deviceName = await helper.findFreeDevice();
+    const deviceName = await uut.findFreeDevice();
     expect(deviceName).toEqual(adbName);
   });
 
@@ -60,7 +59,7 @@ describe('emulators lookup helper', () => {
       const emuDevice = anEmulatorDevice();
       const nonEmuDevice = aNonEmuDevice();
 
-      await helper.findFreeDevice();
+      await uut.findFreeDevice();
 
       const matcherFn = resolveMatcherFn();
       expect(await matcherFn(emuDevice)).toEqual(true);
@@ -71,7 +70,7 @@ describe('emulators lookup helper', () => {
       const device = anEmulatorDevice();
       mockDeviceRegistry.isDeviceBusy.mockReturnValue(true);
 
-      await helper.findFreeDevice();
+      await uut.findFreeDevice();
 
       const matcherFn = resolveMatcherFn();
       expect(await matcherFn(device)).toEqual(false);
@@ -84,7 +83,7 @@ describe('emulators lookup helper', () => {
         queryName: jest.fn().mockResolvedValue('other ' + mockAvdName),
       };
 
-      await helper.findFreeDevice();
+      await uut.findFreeDevice();
 
       const matcherFn = resolveMatcherFn();
       expect(await matcherFn(device)).toEqual(false);