detox 20.12.0-smoke.0 → 20.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar → 20.12.0/detox-20.12.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar → 20.12.0/detox-20.12.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0.pom → 20.12.0/detox-20.12.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/build.gradle +1 -1
  29. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAssertion.java +44 -25
  30. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +6 -7
  31. package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +4 -4
  32. package/android/detox/src/full/java/com/wix/detox/espresso/performer/MultipleViewsActionPerformer.kt +43 -0
  33. package/android/detox/src/full/java/com/wix/detox/espresso/performer/SingleViewActionPerformer.kt +19 -0
  34. package/android/detox/src/full/java/com/wix/detox/espresso/performer/ViewActionPerformer.kt +24 -0
  35. package/android/detox/src/full/java/com/wix/invoke/types/Invocation.java +5 -4
  36. package/android/detox/src/main/java/com/wix/detox/espresso/MultipleViewsAction.kt +4 -0
  37. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -1
  38. package/android/detox/src/main/java/com/wix/detox/espresso/ViewActionWithResult.kt +2 -1
  39. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +6 -5
  40. package/android/detox/src/testFull/java/com/wix/detox/espresso/performer/ViewActionPerformerSpec.kt +37 -0
  41. package/index.d.ts +4 -3
  42. package/local-cli/reset-lock-file.js +9 -5
  43. package/package.json +6 -6
  44. package/src/DetoxWorker.js +9 -5
  45. package/src/android/core/NativeElement.js +26 -29
  46. package/src/android/espressoapi/DetoxAssertion.js +16 -14
  47. package/src/android/espressoapi/EspressoDetox.js +9 -2
  48. package/src/android/interactions/native.js +2 -3
  49. package/src/artifacts/providers/index.js +3 -3
  50. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +17 -0
  51. package/src/devices/DeviceRegistry.js +176 -0
  52. package/src/devices/allocation/DeviceAllocator.js +15 -50
  53. package/src/devices/allocation/drivers/AllocationDriverBase.js +4 -10
  54. package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +6 -7
  55. package/src/devices/allocation/drivers/android/attached/AttachedAndroidLauncher.js +13 -0
  56. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +26 -108
  57. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +72 -0
  58. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +43 -33
  59. package/src/devices/allocation/drivers/android/emulator/FreeEmulatorFinder.js +1 -1
  60. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -3
  61. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +27 -87
  62. package/src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory.js +16 -0
  63. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +65 -0
  64. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceLauncher.js +28 -39
  65. package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +40 -70
  66. package/src/devices/allocation/drivers/ios/SimulatorLauncher.js +7 -11
  67. package/src/devices/allocation/factories/android.js +35 -29
  68. package/src/devices/allocation/factories/ios.js +5 -7
  69. package/src/devices/common/drivers/DeviceAllocationHelper.js +20 -0
  70. package/src/devices/common/drivers/DeviceLauncher.js +19 -0
  71. package/src/devices/common/drivers/android/emulator/exec/EmulatorExec.js +5 -17
  72. package/src/devices/common/drivers/android/exec/ADB.js +0 -1
  73. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +25 -0
  74. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLookupService.js +38 -0
  75. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +14 -0
  76. package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  77. package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyInstance.js +1 -6
  78. package/src/devices/{allocation/drivers/android → common/drivers/android/tools}/FreeDeviceFinder.js +10 -11
  79. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
  80. package/src/devices/cookies/AndroidDeviceCookie.js +0 -4
  81. package/src/devices/cookies/GenycloudEmulatorCookie.js +5 -3
  82. package/src/devices/cookies/IosSimulatorCookie.js +0 -4
  83. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +71 -0
  84. package/src/devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory.js +18 -0
  85. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +2 -2
  86. package/src/devices/runtime/factories/android.js +1 -1
  87. package/src/devices/runtime/factories/ios.js +2 -3
  88. package/src/environmentFactory.js +11 -1
  89. package/src/ipc/IPCClient.js +1 -17
  90. package/src/ipc/IPCServer.js +1 -25
  91. package/src/realms/DetoxContext.js +0 -6
  92. package/src/realms/DetoxPrimaryContext.js +42 -42
  93. package/src/realms/DetoxSecondaryContext.js +0 -19
  94. package/src/realms/symbols.js +0 -4
  95. package/src/{devices/servicelocator → servicelocator}/android/emulatorServiceLocator.js +1 -1
  96. package/src/servicelocator/android/genycloudServiceLocator.js +21 -0
  97. package/src/servicelocator/android/index.js +25 -0
  98. package/src/servicelocator/ios.js +7 -0
  99. package/src/utils/environment.js +15 -8
  100. package/src/utils/errorUtils.js +2 -2
  101. package/src/{devices/validation → validation}/android/GenycloudEnvValidator.js +2 -2
  102. package/src/{devices/validation → validation}/factories/index.js +1 -1
  103. package/src/{devices/validation → validation}/ios/IosSimulatorEnvValidator.js +2 -2
  104. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.md5 +0 -1
  105. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha1 +0 -1
  106. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha256 +0 -1
  107. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha512 +0 -1
  108. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.md5 +0 -1
  109. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha1 +0 -1
  110. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha256 +0 -1
  111. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha512 +0 -1
  112. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar +0 -0
  113. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.md5 +0 -1
  114. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha1 +0 -1
  115. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha256 +0 -1
  116. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha512 +0 -1
  117. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.md5 +0 -1
  118. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha1 +0 -1
  119. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha256 +0 -1
  120. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha512 +0 -1
  121. package/src/devices/allocation/DeviceList.js +0 -44
  122. package/src/devices/allocation/DeviceRegistry.js +0 -186
  123. package/src/devices/allocation/drivers/android/emulator/FreePortFinder.js +0 -16
  124. package/src/devices/allocation/drivers/android/genycloud/GenyRegistry.js +0 -93
  125. package/src/devices/allocation/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +0 -24
  126. package/src/devices/allocation/drivers/ios/SimulatorQuery.js +0 -24
  127. package/src/devices/servicelocator/android/genycloudServiceLocator.js +0 -17
  128. package/src/devices/servicelocator/android/index.js +0 -23
  129. package/src/utils/PIDService.js +0 -27
  130. /package/src/devices/{allocation → common}/drivers/android/genycloud/exec/GenyCloudExec.js +0 -0
  131. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyAuthService.js +0 -0
  132. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyRecipe.js +0 -0
  133. /package/src/{devices/validation → validation}/EnvironmentValidatorBase.js +0 -0
@@ -2,12 +2,11 @@
2
2
  const DeviceAllocatorFactory = require('./base');
3
3
 
4
4
  class AndroidEmulator extends DeviceAllocatorFactory {
5
- _createDriver({ detoxSession, detoxConfig }) {
6
- const serviceLocator = require('../../servicelocator/android');
5
+ _createDriver({ eventEmitter }) {
6
+ const serviceLocator = require('../../../servicelocator/android');
7
7
  const adb = serviceLocator.adb;
8
8
  const emulatorExec = serviceLocator.emulator.exec;
9
- const DeviceRegistry = require('../../allocation/DeviceRegistry');
10
- const deviceRegistry = new DeviceRegistry({ sessionId: detoxSession.id });
9
+ const deviceRegistry = serviceLocator.deviceRegistry;
11
10
 
12
11
  const AVDsResolver = require('../drivers/android/emulator/AVDsResolver');
13
12
  const avdsResolver = new AVDsResolver(emulatorExec);
@@ -21,67 +20,74 @@ class AndroidEmulator extends DeviceAllocatorFactory {
21
20
  const FreeEmulatorFinder = require('../drivers/android/emulator/FreeEmulatorFinder');
22
21
  const freeEmulatorFinder = new FreeEmulatorFinder(adb, deviceRegistry);
23
22
 
24
- const FreePortFinder = require('../drivers/android/emulator/FreePortFinder');
25
- const freePortFinder = new FreePortFinder();
26
-
27
23
  const EmulatorLauncher = require('../drivers/android/emulator/EmulatorLauncher');
28
- const emulatorLauncher = new EmulatorLauncher({ adb, emulatorExec });
24
+ const emulatorLauncher = new EmulatorLauncher({ adb, emulatorExec, eventEmitter });
25
+
26
+ const EmulatorAllocationHelper = require('../drivers/android/emulator/EmulatorAllocationHelper');
27
+ const allocationHelper = new EmulatorAllocationHelper(deviceRegistry, freeEmulatorFinder);
29
28
 
30
29
  const EmulatorAllocDriver = require('../drivers/android/emulator/EmulatorAllocDriver');
31
30
  return new EmulatorAllocDriver({
32
31
  adb,
33
32
  avdValidator,
34
- detoxConfig,
35
- deviceRegistry,
36
33
  emulatorVersionResolver,
37
34
  emulatorLauncher,
38
- freeDeviceFinder: freeEmulatorFinder,
39
- freePortFinder,
35
+ allocationHelper,
40
36
  });
41
37
  }
42
38
  }
43
39
 
44
40
  class AndroidAttached extends DeviceAllocatorFactory {
45
- _createDriver({ detoxSession, detoxConfig }) {
46
- const serviceLocator = require('../../servicelocator/android');
41
+ _createDriver({ eventEmitter }) {
42
+ const serviceLocator = require('../../../servicelocator/android');
47
43
  const adb = serviceLocator.adb;
48
- const DeviceRegistry = require('../../allocation/DeviceRegistry');
49
- const deviceRegistry = new DeviceRegistry({ sessionId: detoxSession.id });
44
+ const deviceRegistry = serviceLocator.deviceRegistry;
50
45
 
51
- const FreeDeviceFinder = require('../drivers/android/FreeDeviceFinder');
46
+ const FreeDeviceFinder = require('../../common/drivers/android/tools/FreeDeviceFinder');
52
47
  const freeDeviceFinder = new FreeDeviceFinder(adb, deviceRegistry);
53
48
 
49
+ const AttachedAndroidLauncher = require('../drivers/android/attached/AttachedAndroidLauncher');
50
+ const attachedAndroidLauncher = new AttachedAndroidLauncher(eventEmitter);
51
+
54
52
  const AttachedAndroidAllocDriver = require('../drivers/android/attached/AttachedAndroidAllocDriver');
55
- return new AttachedAndroidAllocDriver({ adb, deviceRegistry, freeDeviceFinder });
53
+ return new AttachedAndroidAllocDriver({ adb, deviceRegistry, freeDeviceFinder, attachedAndroidLauncher });
56
54
  }
57
55
  }
58
56
 
59
57
  class Genycloud extends DeviceAllocatorFactory {
60
- _createDriver(deps) {
61
- const serviceLocator = require('../../servicelocator/android');
58
+ _createDriver({ eventEmitter }) {
59
+ const serviceLocator = require('../../../servicelocator/android');
62
60
  const adb = serviceLocator.adb;
63
61
  const exec = serviceLocator.genycloud.exec;
62
+ const deviceRegistry = serviceLocator.genycloud.runtimeDeviceRegistry;
63
+ const deviceCleanupRegistry = serviceLocator.genycloud.cleanupDeviceRegistry;
64
64
 
65
- const RecipesService = require('../drivers/android/genycloud/services/GenyRecipesService');
65
+ const InstanceNaming = require('../../common/drivers/android/genycloud/services/GenyInstanceNaming');
66
+ const instanceNaming = new InstanceNaming(); // TODO should consider a permissive impl for debug/dev mode. Maybe even a custom arg in package.json (Detox > ... > genycloud > sharedAccount: false)
67
+
68
+ const RecipesService = require('../../common/drivers/android/genycloud/services/GenyRecipesService');
66
69
  const recipeService = new RecipesService(exec);
67
70
 
68
- const InstanceLifecycleService = require('../drivers/android/genycloud/services/GenyInstanceLifecycleService');
69
- const instanceLifecycleService = new InstanceLifecycleService(exec);
71
+ const InstanceLookupService = require('../../common/drivers/android/genycloud/services/GenyInstanceLookupService');
72
+ const instanceLookupService = new InstanceLookupService(exec, instanceNaming, deviceRegistry);
73
+
74
+ const InstanceLifecycleService = require('../../common/drivers/android/genycloud/services/GenyInstanceLifecycleService');
75
+ const instanceLifecycleService = new InstanceLifecycleService(exec, instanceNaming);
70
76
 
71
77
  const RecipeQuerying = require('../drivers/android/genycloud/GenyRecipeQuerying');
72
78
  const recipeQuerying = new RecipeQuerying(recipeService);
73
79
 
74
- const InstanceLauncher = require('../drivers/android/genycloud/GenyInstanceLauncher');
75
- const instanceLauncher = new InstanceLauncher({ genyCloudExec: exec, instanceLifecycleService });
80
+ const InstanceAllocationHelper = require('../drivers/android/genycloud/GenyInstanceAllocationHelper');
81
+ const allocationHelper = new InstanceAllocationHelper({ deviceRegistry, instanceLookupService, instanceLifecycleService });
76
82
 
83
+ const InstanceLauncher = require('../drivers/android/genycloud/GenyInstanceLauncher');
77
84
  const GenyAllocDriver = require('../drivers/android/genycloud/GenyAllocDriver');
78
-
85
+ const instanceLauncher = new InstanceLauncher({ instanceLifecycleService, instanceLookupService, deviceCleanupRegistry, eventEmitter });
79
86
  return new GenyAllocDriver({
80
87
  adb,
81
- instanceLauncher,
82
- instanceLifecycleService,
83
88
  recipeQuerying,
84
- ...deps,
89
+ allocationHelper,
90
+ instanceLauncher,
85
91
  });
86
92
  }
87
93
  }
@@ -2,18 +2,16 @@
2
2
  const DeviceAllocatorFactory = require('./base');
3
3
 
4
4
  class IosSimulator extends DeviceAllocatorFactory {
5
- _createDriver({ detoxConfig, detoxSession, eventEmitter }) {
6
- const AppleSimUtils = require('../../../devices/common/drivers/ios/tools/AppleSimUtils');
7
- const applesimutils = new AppleSimUtils();
8
-
9
- const DeviceRegistry = require('../../../devices/allocation/DeviceRegistry');
10
- const deviceRegistry = new DeviceRegistry({ sessionId: detoxSession.id });
5
+ _createDriver({ eventEmitter }) {
6
+ const serviceLocator = require('../../../servicelocator/ios');
7
+ const applesimutils = serviceLocator.appleSimUtils;
8
+ const deviceRegistry = serviceLocator.deviceRegistry;
11
9
 
12
10
  const SimulatorLauncher = require('../drivers/ios/SimulatorLauncher');
13
11
  const simulatorLauncher = new SimulatorLauncher({ applesimutils, eventEmitter });
14
12
 
15
13
  const SimulatorAllocDriver = require('../drivers/ios/SimulatorAllocDriver');
16
- return new SimulatorAllocDriver({ detoxConfig, deviceRegistry, applesimutils, simulatorLauncher });
14
+ return new SimulatorAllocDriver({ deviceRegistry, applesimutils, simulatorLauncher });
17
15
  }
18
16
  }
19
17
 
@@ -0,0 +1,20 @@
1
+ const ALLOCATE_DEVICE_LOG_EVT = 'ALLOCATE_DEVICE';
2
+
3
+ class DeviceAllocationHelper {
4
+ constructor(deviceRegistry, logger) {
5
+ this._deviceRegistry = deviceRegistry;
6
+ this._logger = logger;
7
+ }
8
+
9
+ _logAllocationAttempt(deviceQuery) {
10
+ this._logger.debug({ event: ALLOCATE_DEVICE_LOG_EVT }, `Trying to allocate a device based on "${deviceQuery}"`);
11
+ }
12
+
13
+ _logAllocationResult(deviceQuery, deviceHandle) {
14
+ this._logger.debug({ event: ALLOCATE_DEVICE_LOG_EVT }, `Settled on ${deviceHandle}`);
15
+ }
16
+ }
17
+
18
+ DeviceAllocationHelper.ALLOCATE_DEVICE_LOG_EVT = ALLOCATE_DEVICE_LOG_EVT;
19
+
20
+ module.exports = DeviceAllocationHelper;
@@ -0,0 +1,19 @@
1
+ class DeviceLauncher {
2
+ constructor(eventEmitter) {
3
+ this._eventEmitter = eventEmitter;
4
+ }
5
+
6
+ async _notifyPreShutdown(deviceId) {
7
+ return this._eventEmitter.emit('beforeShutdownDevice', { deviceId });
8
+ }
9
+
10
+ async _notifyShutdownCompleted(deviceId) {
11
+ return this._eventEmitter.emit('shutdownDevice', { deviceId });
12
+ }
13
+
14
+ async _notifyBootEvent(deviceId, type, coldBoot, headless) {
15
+ return this._eventEmitter.emit('bootDevice', { deviceId, type, coldBoot, headless });
16
+ }
17
+ }
18
+
19
+ module.exports = DeviceLauncher;
@@ -32,31 +32,19 @@ class QueryVersionCommand extends ExecCommand {
32
32
  }
33
33
 
34
34
  class LaunchCommand extends ExecCommand {
35
- constructor(options) {
35
+ constructor(emulatorName, options) {
36
36
  super();
37
37
  this._options = options;
38
- this._args = this._getEmulatorArgs();
39
- }
40
-
41
- get adbName() {
42
- return this._options.adbName;
43
- }
44
-
45
- get avdName() {
46
- return this._options.avdName;
47
- }
48
-
49
- get port() {
50
- return this._options.port;
38
+ this._args = this._getEmulatorArgs(emulatorName);
39
+ this.port = options.port;
51
40
  }
52
41
 
53
42
  _getArgs() {
54
43
  return this._args;
55
44
  }
56
45
 
57
- _getEmulatorArgs() {
46
+ _getEmulatorArgs(emulatorName) {
58
47
  const {
59
- avdName,
60
48
  bootArgs,
61
49
  gpuMode = this._getDefaultGPUMode(),
62
50
  headless,
@@ -76,7 +64,7 @@ class LaunchCommand extends ExecCommand {
76
64
  port ? '-port' : '',
77
65
  port ? `${port}` : '',
78
66
  ...deviceBootArgs,
79
- `@${avdName}`
67
+ `@${emulatorName}`
80
68
  ]);
81
69
 
82
70
  return emulatorArgs;
@@ -18,7 +18,6 @@ class ADB {
18
18
 
19
19
  async devices() {
20
20
  const { stdout } = await this.adbCmd('', 'devices', { verbosity: 'high' });
21
- /** @type {DeviceHandle[]} */
22
21
  const devices = _.chain(stdout)
23
22
  .trim()
24
23
  .split('\n')
@@ -0,0 +1,25 @@
1
+ const Instance = require('./dto/GenyInstance');
2
+
3
+ class GenyInstanceLifecycleService {
4
+ constructor(genyCloudExec, instanceNaming) {
5
+ this.genyCloudExec = genyCloudExec;
6
+ this.instanceNaming = instanceNaming;
7
+ }
8
+
9
+ async createInstance(recipeUUID) {
10
+ const result = await this.genyCloudExec.startInstance(recipeUUID, this.instanceNaming.generateName());
11
+ return new Instance(result.instance);
12
+ }
13
+
14
+ async adbConnectInstance(instanceUUID) {
15
+ const result = (await this.genyCloudExec.adbConnect(instanceUUID));
16
+ return new Instance(result.instance);
17
+ }
18
+
19
+ async deleteInstance(instanceUUID) {
20
+ const result = await this.genyCloudExec.stopInstance(instanceUUID);
21
+ return new Instance(result.instance);
22
+ }
23
+ }
24
+
25
+ module.exports = GenyInstanceLifecycleService;
@@ -0,0 +1,38 @@
1
+ const Instance = require('./dto/GenyInstance');
2
+
3
+ class GenyInstanceLookupService {
4
+ constructor(genyCloudExec, instanceNaming, genyCloudDeviceRegistry) {
5
+ this.genyCloudExec = genyCloudExec;
6
+ this.instanceNaming = instanceNaming;
7
+ this.deviceRegistry = genyCloudDeviceRegistry;
8
+ }
9
+
10
+ async findFreeInstance() {
11
+ const freeInstances = await this._getRelevantInstances();
12
+ return (freeInstances[0] || null);
13
+ }
14
+
15
+ async getInstance(instanceUUID) {
16
+ const { instance } = await this.genyCloudExec.getInstance(instanceUUID);
17
+ return new Instance(instance);
18
+ }
19
+
20
+ async _getRelevantInstances() {
21
+ const takenInstances = this.deviceRegistry.getRegisteredDevices();
22
+ const isRelevant = (instance) =>
23
+ (instance.isOnline() || instance.isInitializing()) &&
24
+ this.instanceNaming.isFamilial(instance.name) &&
25
+ !takenInstances.includes(instance.uuid);
26
+
27
+ const instances = await this._getAllInstances();
28
+ return instances.filter(isRelevant);
29
+ }
30
+
31
+ async _getAllInstances() {
32
+ return (await this.genyCloudExec.getInstances())
33
+ .instances
34
+ .map((rawInstance) => new Instance(rawInstance));
35
+ }
36
+ }
37
+
38
+ module.exports = GenyInstanceLookupService;
@@ -0,0 +1,14 @@
1
+ const internals = () => require('../../../../../../../internals');
2
+
3
+ class GenyInstanceNaming {
4
+ generateName() {
5
+ const { session, worker } = internals();
6
+ return `Detox.${session.id}.${worker.id}`;
7
+ }
8
+
9
+ isFamilial(name) {
10
+ return name === this.generateName();
11
+ }
12
+ }
13
+
14
+ module.exports = GenyInstanceNaming;
@@ -1,6 +1,6 @@
1
1
  const logger = require('../../../../../../utils/logger').child({ cat: 'device' });
2
2
 
3
- const Recipe = require('./dto/GenyRecipe');
3
+ const Recipe = require('./dto/GenyRecipe');
4
4
 
5
5
  class GenyRecipesService {
6
6
  constructor(genyCloudExec) {
@@ -59,12 +59,7 @@ class GenyInstance {
59
59
  }
60
60
 
61
61
  toString() {
62
- const description = [
63
- this.uuid,
64
- this.adbName
65
- ].filter(Boolean).join('/');
66
-
67
- return `${this.name} (${description})`;
62
+ return `GenyCloud:${this.name} (${this.uuid} ${this.adbName})`;
68
63
  }
69
64
  }
70
65
 
@@ -1,6 +1,6 @@
1
- const log = require('../../../../utils/logger').child({ cat: 'device' });
1
+ const log = require('../../../../../utils/logger').child({ cat: 'device' });
2
2
 
3
- const DEVICE_LOOKUP = { event: 'DEVICE_LOOKUP' };
3
+ const DEVICE_LOOKUP_LOG_EVT = 'DEVICE_LOOKUP';
4
4
 
5
5
  class FreeDeviceFinder {
6
6
  constructor(adb, deviceRegistry) {
@@ -10,9 +10,8 @@ class FreeDeviceFinder {
10
10
 
11
11
  async findFreeDevice(deviceQuery) {
12
12
  const { devices } = await this.adb.devices();
13
- const takenDevices = this.deviceRegistry.getTakenDevicesSync();
14
13
  for (const candidate of devices) {
15
- if (await this._isDeviceFreeAndMatching(takenDevices, candidate, deviceQuery)) {
14
+ if (await this._isDeviceFreeAndMatching(candidate, deviceQuery)) {
16
15
  return candidate.adbName;
17
16
  }
18
17
  }
@@ -20,30 +19,30 @@ class FreeDeviceFinder {
20
19
  }
21
20
 
22
21
  /**
23
- * @private
22
+ * @protected
24
23
  */
25
- async _isDeviceFreeAndMatching(takenDevices, candidate, deviceQuery) {
24
+ async _isDeviceFreeAndMatching(candidate, deviceQuery) {
26
25
  const { adbName } = candidate;
27
26
 
28
- const isTaken = takenDevices.includes(adbName);
27
+ const isTaken = this.deviceRegistry.includes(adbName);
29
28
  if (isTaken) {
30
- log.debug(DEVICE_LOOKUP, `Device ${adbName} is already taken, skipping...`);
29
+ log.debug({ event: DEVICE_LOOKUP_LOG_EVT }, `Device ${adbName} is already taken, skipping...`);
31
30
  return false;
32
31
  }
33
32
 
34
33
  const isOffline = candidate.status === 'offline';
35
34
  if (isOffline) {
36
- log.debug(DEVICE_LOOKUP, `Device ${adbName} is offline, skipping...`);
35
+ log.debug({ event: DEVICE_LOOKUP_LOG_EVT }, `Device ${adbName} is offline, skipping...`);
37
36
  return false;
38
37
  }
39
38
 
40
39
  const isMatching = await this._isDeviceMatching(candidate, deviceQuery);
41
40
  if (!isMatching) {
42
- log.debug(DEVICE_LOOKUP, `Device ${adbName} does not match "${deviceQuery}"`);
41
+ log.debug({ event: DEVICE_LOOKUP_LOG_EVT }, `Device ${adbName} does not match "${deviceQuery}"`);
43
42
  return false;
44
43
  }
45
44
 
46
- log.debug(DEVICE_LOOKUP, `Found a matching & free device ${candidate.adbName}`);
45
+ log.debug({ event: DEVICE_LOOKUP_LOG_EVT }, `Found a matching & free device ${candidate.adbName}`);
47
46
  return true;
48
47
  }
49
48
 
@@ -297,7 +297,7 @@ class AppleSimUtils {
297
297
  // want to make sure it isn't now.
298
298
  if (err.code === 3 &&
299
299
  (err.stderr.includes(`the app is not currently running`) ||
300
- err.stderr.includes(`The operation couldn’t be completed. found nothing to terminate`))) {
300
+ err.stderr.includes(`found nothing to terminate`))) {
301
301
  return;
302
302
  }
303
303
 
@@ -8,10 +8,6 @@ class AndroidDeviceCookie extends DeviceCookie {
8
8
  super();
9
9
  this.adbName = adbName;
10
10
  }
11
-
12
- toString() {
13
- return this.adbName;
14
- }
15
11
  }
16
12
 
17
13
  module.exports = AndroidDeviceCookie;
@@ -6,13 +6,15 @@ class GenycloudEmulatorCookie extends AndroidDeviceCookie {
6
6
  * @param instance { GenyInstance }
7
7
  */
8
8
  constructor(instance) {
9
- super(instance.adb.name);
9
+ super();
10
10
  this.instance = instance;
11
11
  }
12
12
 
13
- toString() {
14
- return `${this.instance}`;
13
+ get adbName() {
14
+ return this.instance.adbName;
15
15
  }
16
+
17
+ set adbName(value) {}
16
18
  }
17
19
 
18
20
  module.exports = GenycloudEmulatorCookie;
@@ -5,10 +5,6 @@ class IosSimulatorCookie extends IosCookie {
5
5
  super();
6
6
  this.udid = udid;
7
7
  }
8
-
9
- toString() {
10
- return this.udid;
11
- }
12
8
  }
13
9
 
14
10
  module.exports = IosSimulatorCookie;
@@ -0,0 +1,71 @@
1
+ const logger = require('../../utils/logger').child({ cat: 'device' });
2
+
3
+ const cleanupLogData = {
4
+ event: 'GENYCLOUD_TEARDOWN',
5
+ };
6
+
7
+ class GenyGlobalLifecycleHandler {
8
+ constructor({ deviceCleanupRegistry, instanceLifecycleService }) {
9
+ /** @private */
10
+ this._deviceCleanupRegistry = deviceCleanupRegistry;
11
+ /** @private */
12
+ this._instanceLifecycleService = instanceLifecycleService;
13
+ }
14
+
15
+ async globalInit() {}
16
+
17
+ emergencyCleanup() {
18
+ const { rawDevices } = this._deviceCleanupRegistry.readRegisteredDevicesUNSAFE();
19
+ const instanceHandles = rawDevicesToInstanceHandles(rawDevices);
20
+ if (instanceHandles.length) {
21
+ reportGlobalCleanupSummary(instanceHandles);
22
+ }
23
+ }
24
+
25
+ async globalCleanup() {
26
+ const { rawDevices } = await this._deviceCleanupRegistry.readRegisteredDevices();
27
+ const instanceHandles = rawDevicesToInstanceHandles(rawDevices);
28
+ if (instanceHandles.length) {
29
+ await doSafeCleanup(this._instanceLifecycleService, instanceHandles);
30
+ }
31
+ }
32
+ }
33
+
34
+ async function doSafeCleanup(instanceLifecycleService, instanceHandles) {
35
+ logger.info(cleanupLogData, 'Initiating Genymotion SaaS instances teardown...');
36
+
37
+ const deletionLeaks = [];
38
+ const killPromises = instanceHandles.map((instanceHandle) =>
39
+ instanceLifecycleService.deleteInstance(instanceHandle.uuid)
40
+ .catch((error) => deletionLeaks.push({ ...instanceHandle, error })));
41
+
42
+ await Promise.all(killPromises);
43
+ reportGlobalCleanupSummary(deletionLeaks);
44
+ }
45
+
46
+ function reportGlobalCleanupSummary(deletionLeaks) {
47
+ if (deletionLeaks.length) {
48
+ logger.warn(cleanupLogData, 'WARNING! Detected a Genymotion SaaS instance leakage, for the following instances:');
49
+
50
+ deletionLeaks.forEach(({ uuid, name, error }) => {
51
+ logger.warn(cleanupLogData, [
52
+ `Instance ${name} (${uuid})${error ? `: ${error}` : ''}`,
53
+ ` Kill it by visiting https://cloud.geny.io/instance/${uuid}, or by running:`,
54
+ ` gmsaas instances stop ${uuid}`,
55
+ ].join('\n'));
56
+ });
57
+
58
+ logger.info(cleanupLogData, 'Instances teardown completed with warnings');
59
+ } else {
60
+ logger.info(cleanupLogData, 'Instances teardown completed successfully');
61
+ }
62
+ }
63
+
64
+ function rawDevicesToInstanceHandles(rawDevices) {
65
+ return rawDevices.map((rawDevice) => ({
66
+ uuid: rawDevice.id,
67
+ name: rawDevice.data.name,
68
+ }));
69
+ }
70
+
71
+ module.exports = GenyGlobalLifecycleHandler;
@@ -0,0 +1,18 @@
1
+ class GenyGlobalLifecycleHandlerFactory {
2
+ /**
3
+ * @returns { GenyGlobalLifecycleHandler }
4
+ */
5
+ createHandler() {
6
+ const serviceLocator = require('../../../servicelocator/android');
7
+ const deviceCleanupRegistry = serviceLocator.genycloud.cleanupDeviceRegistry;
8
+ const exec = serviceLocator.genycloud.exec;
9
+
10
+ const InstanceLifecycleService = require('../../common/drivers/android/genycloud/services/GenyInstanceLifecycleService');
11
+ const instanceLifecycleService = new InstanceLifecycleService(exec, null);
12
+
13
+ const GenyGlobalLifecycleHandler = require('../GenyGlobalLifecycleHandler');
14
+ return new GenyGlobalLifecycleHandler({ deviceCleanupRegistry, instanceLifecycleService });
15
+ }
16
+ }
17
+
18
+ module.exports = GenyGlobalLifecycleHandlerFactory;
@@ -17,12 +17,12 @@ class GenyCloudDriver extends AndroidDriver {
17
17
  * @param props { GenycloudDriverProps }
18
18
  */
19
19
  constructor(deps, { instance }) {
20
- super(deps, { adbName: instance.adb.name });
20
+ super(deps, { adbName: instance.adbName });
21
21
  this.instance = instance;
22
22
  }
23
23
 
24
24
  getDeviceName() {
25
- return this.instance.name;
25
+ return this.instance.toString();
26
26
  }
27
27
 
28
28
  async setLocation(lat, lon) {
@@ -3,7 +3,7 @@ const RuntimeDeviceFactory = require('./base');
3
3
 
4
4
  class RuntimeDriverFactoryAndroid extends RuntimeDeviceFactory {
5
5
  _createDriverDependencies(commonDeps) {
6
- const serviceLocator = require('../../servicelocator/android');
6
+ const serviceLocator = require('../../../servicelocator/android');
7
7
  const adb = serviceLocator.adb;
8
8
  const aapt = serviceLocator.aapt;
9
9
  const apkValidator = serviceLocator.apkValidator;
@@ -2,11 +2,10 @@ const RuntimeDeviceFactory = require('./base');
2
2
 
3
3
  class RuntimeDriverFactoryIos extends RuntimeDeviceFactory {
4
4
  _createDriverDependencies(commonDeps) {
5
+ const serviceLocator = require('../../../servicelocator/ios');
6
+ const applesimutils = serviceLocator.appleSimUtils;
5
7
  const { eventEmitter } = commonDeps;
6
8
 
7
- const AppleSimUtils = require('../../../devices/common/drivers/ios/tools/AppleSimUtils');
8
- const applesimutils = new AppleSimUtils();
9
-
10
9
  const SimulatorLauncher = require('../../allocation/drivers/ios/SimulatorLauncher');
11
10
  return {
12
11
  ...commonDeps,
@@ -2,9 +2,9 @@
2
2
  const artifactsManagerFactories = require('./artifacts/factories');
3
3
  const deviceAllocationFactories = require('./devices/allocation/factories');
4
4
  const runtimeDeviceFactories = require('./devices/runtime/factories');
5
- const envValidationFactories = require('./devices/validation/factories');
6
5
  const matchersFactories = require('./matchers/factories');
7
6
  const resolveModuleFromPath = require('./utils/resolveModuleFromPath');
7
+ const envValidationFactories = require('./validation/factories');
8
8
 
9
9
  function validateConfig(deviceConfig) {
10
10
  const classes = _getFactoryClasses(deviceConfig);
@@ -36,6 +36,15 @@ function createFactories(deviceConfig) {
36
36
  return _getExternalModuleFactories(deviceConfig);
37
37
  }
38
38
 
39
+ function createGlobalLifecycleHandler(deviceConfig) {
40
+ if (deviceConfig.type === 'android.genycloud') {
41
+ const FactoryClass = require('./devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory');
42
+ const factory = new FactoryClass();
43
+ return factory.createHandler();
44
+ }
45
+ return null;
46
+ }
47
+
39
48
  function _getFactoryClasses(deviceConfig) {
40
49
  let envValidatorFactoryClass;
41
50
  let artifactsManagerFactoryClass;
@@ -106,4 +115,5 @@ function _getExternalModuleFactories(deviceConfig) {
106
115
  module.exports = {
107
116
  validateConfig,
108
117
  createFactories,
118
+ createGlobalLifecycleHandler,
109
119
  };
@@ -1,7 +1,7 @@
1
1
  const { IPC } = require('node-ipc');
2
2
 
3
3
  const { DetoxInternalError } = require('../errors');
4
- const { serializeObjectWithError, deserializeObjectWithError } = require('../utils/errorUtils');
4
+ const { serializeObjectWithError } = require('../utils/errorUtils');
5
5
 
6
6
  class IPCClient {
7
7
  constructor({ id, logger, sessionState }) {
@@ -60,22 +60,6 @@ class IPCClient {
60
60
  this._sessionState.patch(sessionState);
61
61
  }
62
62
 
63
- async allocateDevice() {
64
- const { deviceCookie, error } = deserializeObjectWithError(await this._emit('allocateDevice', {}));
65
- if (error) {
66
- throw error;
67
- }
68
-
69
- return deviceCookie;
70
- }
71
-
72
- async deallocateDevice(deviceCookie) {
73
- const { error } = deserializeObjectWithError(await this._emit('deallocateDevice', { deviceCookie }));
74
- if (error) {
75
- throw error;
76
- }
77
- }
78
-
79
63
  /**
80
64
  * @param {DetoxInternals.DetoxTestFileReport[]} testResults
81
65
  */