detox 21.0.0-rc.0 → 21.0.0-rc.10
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintignore +3 -0
- package/.eslintrc.js +1 -40
- package/Detox-android/com/wix/detox/{21.0.0-rc.0/detox-21.0.0-rc.0-javadoc.jar → 21.0.0-rc.10/detox-21.0.0-rc.10-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{21.0.0-rc.0/detox-21.0.0-rc.0-sources.jar → 21.0.0-rc.10/detox-21.0.0-rc.10-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.aar +0 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{21.0.0-rc.0/detox-21.0.0-rc.0.pom → 21.0.0-rc.10/detox-21.0.0-rc.10.pom} +1 -7
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.10/detox-21.0.0-rc.10.pom.sha512 +1 -0
- package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
- package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
- package/Detox-ios-framework.tbz +0 -0
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios-xcuitest.tbz +0 -0
- package/android/build.gradle +20 -10
- package/android/detox/build.gradle +24 -12
- package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAssertion.java +44 -25
- package/android/detox/src/full/java/com/wix/detox/espresso/DetoxMatcher.java +12 -12
- package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +6 -7
- package/android/detox/src/full/java/com/wix/detox/espresso/action/AdjustSliderToPositionAction.kt +2 -2
- package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +34 -35
- package/android/detox/src/full/java/com/wix/detox/espresso/common/MaterialSliderHelper.kt +21 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/common/{SliderHelper.kt → ReactSliderHelper.kt} +7 -6
- package/android/detox/src/full/java/com/wix/detox/espresso/matcher/RegexMatcher.kt +56 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewMatchers.kt +18 -6
- package/android/detox/src/full/java/com/wix/detox/espresso/performer/MultipleViewsActionPerformer.kt +43 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/performer/SingleViewActionPerformer.kt +19 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/performer/ViewActionPerformer.kt +24 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +4 -4
- package/android/detox/src/full/java/com/wix/invoke/types/Invocation.java +7 -6
- package/android/detox/src/main/java/com/wix/detox/espresso/MultipleViewsAction.kt +4 -0
- package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -1
- package/android/detox/src/main/java/com/wix/detox/espresso/ViewActionWithResult.kt +2 -1
- package/android/detox/src/main/java/com/wix/detox/espresso/action/common/MotionEvents.kt +60 -4
- package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +6 -5
- package/android/detox/src/testFull/java/com/wix/detox/espresso/common/MaterialSliderHelperTest.kt +33 -0
- package/android/detox/src/testFull/java/com/wix/detox/espresso/common/{SliderHelperTest.kt → ReactSliderHelperTest.kt} +3 -3
- package/android/detox/src/testFull/java/com/wix/detox/espresso/matcher/RegexMatcherTest.kt +52 -0
- package/android/detox/src/testFull/java/com/wix/detox/espresso/performer/ViewActionPerformerSpec.kt +37 -0
- package/android/detox/src/testFull/java/com/wix/invoke/JsonParserTest.java +23 -7
- package/android/detox/src/testFull/resources/targetInvocationEspressoWebDetoxScript.json +47 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/rninfo.gradle +25 -0
- package/android/settings.gradle +2 -1
- package/detox.d.ts +1840 -0
- package/globals.d.ts +23 -0
- package/index.d.ts +2 -1789
- package/internals.d.ts +11 -1
- package/jest.config.js +108 -0
- package/local-cli/reset-lock-file.js +5 -9
- package/local-cli/startCommand/AppStartCommand.js +4 -1
- package/local-cli/testCommand/TestRunnerCommand.js +26 -3
- package/local-cli/utils/interruptListeners.js +15 -0
- package/package.json +15 -108
- package/runners/jest/reporter.js +21 -1
- package/runners/jest/reporters/DetoxIPCReporter.js +34 -0
- package/runners/jest/reporters/DetoxReporterDispatcher.js +144 -0
- package/runners/jest/reporters/DetoxSummaryReporter.js +16 -0
- package/runners/jest/reporters/DetoxVerboseReporter.js +16 -0
- package/runners/jest/reporters/index.js +6 -0
- package/runners/jest/testEnvironment/index.js +11 -0
- package/src/DetoxWorker.js +5 -11
- package/src/android/core/NativeElement.js +26 -29
- package/src/android/core/WebElement.js +24 -6
- package/src/android/espressoapi/DetoxAssertion.js +16 -14
- package/src/android/espressoapi/DetoxMatcher.js +24 -8
- package/src/android/espressoapi/EspressoDetox.js +9 -2
- package/src/android/espressoapi/web/WebElement.js +1 -4
- package/src/android/interactions/native.js +2 -3
- package/src/android/matchers/index.js +4 -0
- package/src/android/matchers/native.js +9 -4
- package/src/android/matchers/web.js +26 -1
- package/src/artifacts/providers/index.js +3 -3
- package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +0 -17
- package/src/configuration/composeLoggerConfig.js +1 -0
- package/src/configuration/composeRunnerConfig.js +3 -1
- package/src/devices/allocation/DeviceAllocator.js +66 -20
- package/src/devices/allocation/DeviceList.js +44 -0
- package/src/devices/allocation/DeviceRegistry.js +189 -0
- package/src/devices/allocation/drivers/AllocationDriverBase.d.ts +15 -0
- package/src/devices/{common/drivers/android/tools → allocation/drivers/android}/FreeDeviceFinder.js +11 -10
- package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +22 -17
- package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +97 -38
- package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +32 -45
- package/src/devices/allocation/drivers/android/emulator/FreeEmulatorFinder.js +1 -1
- package/src/devices/allocation/drivers/android/emulator/FreePortFinder.js +37 -0
- package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -3
- package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +104 -32
- package/src/devices/allocation/drivers/android/genycloud/GenyInstanceLauncher.js +40 -31
- package/src/devices/allocation/drivers/android/genycloud/GenyRegistry.js +121 -0
- package/src/devices/allocation/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +24 -0
- package/src/devices/{common → allocation}/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
- package/src/devices/allocation/drivers/android/genycloud/services/dto/GenyInstance.js +83 -0
- package/src/devices/allocation/drivers/android/genycloud/services/dto/GenyRecipe.js +25 -0
- package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +95 -54
- package/src/devices/allocation/drivers/ios/SimulatorQuery.js +24 -0
- package/src/devices/allocation/factories/android.js +29 -35
- package/src/devices/allocation/factories/ios.js +6 -7
- package/src/devices/common/drivers/DeviceCookie.d.ts +12 -0
- package/src/devices/common/drivers/android/cookies.d.ts +11 -0
- package/src/devices/common/drivers/android/emulator/exec/EmulatorExec.js +17 -5
- package/src/devices/common/drivers/android/exec/ADB.js +1 -0
- package/src/devices/common/drivers/android/tools/instrumentationArgs.js +7 -1
- package/src/devices/common/drivers/ios/cookies.d.ts +9 -0
- package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +3 -1
- package/src/devices/cookies/index.js +0 -6
- package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +7 -6
- package/src/devices/runtime/drivers/ios/SimulatorDriver.js +9 -24
- package/src/devices/runtime/drivers/ios/XCUITestUtils.js +33 -19
- package/src/devices/runtime/factories/android.js +3 -11
- package/src/devices/runtime/factories/ios.js +3 -4
- package/src/{servicelocator → devices/servicelocator}/android/emulatorServiceLocator.js +1 -1
- package/src/devices/servicelocator/android/genycloudServiceLocator.js +17 -0
- package/src/devices/servicelocator/android/index.js +23 -0
- package/src/{validation → devices/validation}/EnvironmentValidatorBase.js +1 -0
- package/src/{validation → devices/validation}/android/GenycloudEnvValidator.js +2 -2
- package/src/{validation → devices/validation}/factories/index.js +1 -1
- package/src/{validation → devices/validation}/ios/IosSimulatorEnvValidator.js +2 -2
- package/src/environmentFactory.js +1 -11
- package/src/invoke.js +0 -2
- package/src/ios/expectTwo.js +28 -11
- package/src/ios/web.js +302 -0
- package/src/ipc/IPCClient.js +22 -1
- package/src/ipc/IPCServer.js +42 -1
- package/src/ipc/SessionState.js +1 -0
- package/src/logger/DetoxLogger.js +2 -2
- package/src/realms/DetoxContext.js +8 -0
- package/src/realms/DetoxInternalsFacade.js +1 -0
- package/src/realms/DetoxPrimaryContext.js +49 -44
- package/src/realms/DetoxSecondaryContext.js +27 -0
- package/src/realms/symbols.js +6 -0
- package/src/utils/PIDService.js +27 -0
- package/src/utils/assertIsFunction.js +35 -0
- package/src/utils/environment.js +8 -15
- package/src/utils/errorUtils.js +3 -3
- package/src/utils/invocationTraceDescriptions.js +16 -0
- package/src/utils/isArrowFunction.js +24 -0
- package/src/utils/isRegExp.js +7 -0
- package/tsconfig.json +8 -3
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.aar +0 -0
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/21.0.0-rc.0/detox-21.0.0-rc.0.pom.sha512 +0 -1
- package/runners/jest/reporters/DetoxReporter.js +0 -36
- package/src/devices/DeviceRegistry.js +0 -176
- package/src/devices/allocation/drivers/AllocationDriverBase.js +0 -30
- package/src/devices/allocation/drivers/android/attached/AttachedAndroidLauncher.js +0 -13
- package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +0 -72
- package/src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory.js +0 -16
- package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +0 -65
- package/src/devices/allocation/drivers/ios/SimulatorLauncher.js +0 -21
- package/src/devices/common/drivers/DeviceAllocationHelper.js +0 -20
- package/src/devices/common/drivers/DeviceLauncher.js +0 -19
- package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +0 -25
- package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLookupService.js +0 -38
- package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +0 -14
- package/src/devices/common/drivers/android/genycloud/services/dto/GenyInstance.js +0 -66
- package/src/devices/common/drivers/android/genycloud/services/dto/GenyRecipe.js +0 -13
- package/src/devices/cookies/AndroidDeviceCookie.js +0 -13
- package/src/devices/cookies/AndroidEmulatorCookie.js +0 -6
- package/src/devices/cookies/AttachedAndroidDeviceCookie.js +0 -12
- package/src/devices/cookies/DeviceCookie.js +0 -4
- package/src/devices/cookies/GenycloudEmulatorCookie.js +0 -20
- package/src/devices/cookies/IosCookie.js +0 -6
- package/src/devices/cookies/IosSimulatorCookie.js +0 -10
- package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +0 -71
- package/src/devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory.js +0 -18
- package/src/invoke/EarlGrey.js +0 -8
- package/src/servicelocator/android/genycloudServiceLocator.js +0 -21
- package/src/servicelocator/android/index.js +0 -25
- package/src/servicelocator/ios.js +0 -7
- /package/src/devices/{common → allocation}/drivers/android/genycloud/exec/GenyCloudExec.js +0 -0
- /package/src/devices/{common → allocation}/drivers/android/genycloud/services/GenyAuthService.js +0 -0
@@ -4,7 +4,7 @@ class ArtifactPluginsProvider {
|
|
4
4
|
|
5
5
|
class AndroidArtifactPluginsProvider extends ArtifactPluginsProvider {
|
6
6
|
declareArtifactPlugins({ client }) {
|
7
|
-
const serviceLocator = require('../../servicelocator/android');
|
7
|
+
const serviceLocator = require('../../devices/servicelocator/android');
|
8
8
|
const adb = serviceLocator.adb;
|
9
9
|
const devicePathBuilder = serviceLocator.devicePathBuilder;
|
10
10
|
|
@@ -34,8 +34,8 @@ class IosArtifactPluginsProvider extends ArtifactPluginsProvider {
|
|
34
34
|
|
35
35
|
class IosSimulatorArtifactPluginsProvider extends IosArtifactPluginsProvider {
|
36
36
|
declareArtifactPlugins({ client }) {
|
37
|
-
const
|
38
|
-
const appleSimUtils =
|
37
|
+
const AppleSimUtils = require('../../devices/common/drivers/ios/tools/AppleSimUtils');
|
38
|
+
const appleSimUtils = new AppleSimUtils();
|
39
39
|
|
40
40
|
const SimulatorInstrumentsPlugin = require('../instruments/ios/SimulatorInstrumentsPlugin');
|
41
41
|
const SimulatorLogPlugin = require('../log/ios/SimulatorLogPlugin');
|
@@ -22,23 +22,6 @@ class SimulatorScreenshotPlugin extends ScreenshotArtifactPlugin {
|
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
25
|
-
async onBootDevice(event) {
|
26
|
-
await super.onBootDevice(event);
|
27
|
-
|
28
|
-
if (this.enabled && event.coldBoot) {
|
29
|
-
await this.appleSimUtils.takeScreenshot(event.deviceId, '/dev/null').catch(() => {
|
30
|
-
log.debug({}, `
|
31
|
-
NOTE: For an unknown yet reason, taking the first screenshot is apt
|
32
|
-
to fail when booting iOS Simulator in a hidden window mode (or on CI).
|
33
|
-
Detox applies a workaround by taking a dummy screenshot to ensure
|
34
|
-
that the future ones are going to work fine. This screenshot is not
|
35
|
-
saved anywhere, and the error above is suppressed for all log levels
|
36
|
-
except for "debug" and "trace."
|
37
|
-
`.trim());
|
38
|
-
});
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
25
|
async onBeforeUninstallApp(event) {
|
43
26
|
await this.api.requestIdleCallback(async () => {
|
44
27
|
const snapshots = [
|
@@ -32,6 +32,7 @@ function composeRunnerConfig(opts) {
|
|
32
32
|
retries: 0,
|
33
33
|
inspectBrk: inspectBrkHookDefault,
|
34
34
|
forwardEnv: false,
|
35
|
+
detached: false,
|
35
36
|
bail: false,
|
36
37
|
jest: {
|
37
38
|
setupTimeout: 300000,
|
@@ -56,8 +57,9 @@ function composeRunnerConfig(opts) {
|
|
56
57
|
|
57
58
|
if (typeof merged.inspectBrk === 'function') {
|
58
59
|
if (cliConfig.inspectBrk) {
|
59
|
-
merged.
|
60
|
+
merged.detached = false;
|
60
61
|
merged.forwardEnv = true;
|
62
|
+
merged.retries = 0;
|
61
63
|
merged.inspectBrk(merged);
|
62
64
|
}
|
63
65
|
|
@@ -1,43 +1,89 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/**
|
2
|
+
* @typedef {import('./drivers/AllocationDriverBase').AllocationDriverBase} AllocationDriverBase
|
3
|
+
* @typedef {import('./drivers/AllocationDriverBase').DeallocOptions} DeallocOptions
|
4
|
+
* @typedef {import('../common/drivers/DeviceCookie').DeviceCookie} DeviceCookie
|
5
|
+
*/
|
6
|
+
|
7
|
+
const log = require('../../utils/logger').child({ cat: 'device,device-allocation' });
|
3
8
|
const traceMethods = require('../../utils/traceMethods');
|
4
9
|
|
5
10
|
class DeviceAllocator {
|
6
11
|
/**
|
7
|
-
* @param
|
12
|
+
* @param {AllocationDriverBase} allocationDriver
|
8
13
|
*/
|
9
14
|
constructor(allocationDriver) {
|
10
15
|
this._driver = allocationDriver;
|
11
|
-
|
16
|
+
this._counter = 0;
|
17
|
+
this._ids = new Map();
|
18
|
+
traceMethods(log, this, ['init', 'cleanup', 'emergencyCleanup']);
|
12
19
|
}
|
13
20
|
|
14
21
|
/**
|
15
|
-
* @
|
16
|
-
* @return {Promise<DeviceCookie>}
|
22
|
+
* @returns {Promise<void>}
|
17
23
|
*/
|
18
|
-
|
19
|
-
|
24
|
+
async init() {
|
25
|
+
if (typeof this._driver.init === 'function') {
|
26
|
+
await this._driver.init();
|
27
|
+
}
|
20
28
|
}
|
21
29
|
|
22
30
|
/**
|
23
|
-
* @param {
|
24
|
-
* @
|
31
|
+
* @param {Detox.DetoxDeviceConfig} deviceConfig
|
32
|
+
* @returns {Promise<DeviceCookie>}
|
25
33
|
*/
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
async allocate(deviceConfig) {
|
35
|
+
const tid = this._counter++;
|
36
|
+
return await log.trace.complete({ data: deviceConfig, id: tid }, 'allocate', async () => {
|
37
|
+
const cookie = await this._driver.allocate(deviceConfig);
|
38
|
+
log.debug({ data: cookie }, `settled on ${cookie.name || cookie.id}`);
|
39
|
+
this._ids.set(cookie.id, tid);
|
40
|
+
return cookie;
|
41
|
+
});
|
42
|
+
}
|
30
43
|
|
31
|
-
|
44
|
+
/**
|
45
|
+
* @param {DeviceCookie} cookie
|
46
|
+
* @returns {Promise<DeviceCookie>}
|
47
|
+
*/
|
48
|
+
async postAllocate(cookie) {
|
49
|
+
const tid = this._ids.get(cookie.id);
|
50
|
+
return await log.trace.complete({ data: cookie, id: tid }, `post-allocate: ${cookie.id}`, async () => {
|
51
|
+
const updatedCookie = typeof this._driver.postAllocate === 'function'
|
52
|
+
? await this._driver.postAllocate(cookie)
|
53
|
+
: undefined;
|
54
|
+
|
55
|
+
return updatedCookie || cookie;
|
56
|
+
});
|
32
57
|
}
|
33
58
|
|
34
59
|
/**
|
35
|
-
* @param
|
36
|
-
* @param
|
37
|
-
* @
|
60
|
+
* @param {DeviceCookie} cookie
|
61
|
+
* @param {DeallocOptions} options
|
62
|
+
* @returns {Promise<void>}
|
38
63
|
*/
|
39
|
-
free(cookie, options) {
|
40
|
-
|
64
|
+
async free(cookie, options = {}) {
|
65
|
+
const tid = this._ids.get(cookie.id);
|
66
|
+
await log.trace.complete({ data: options, id: tid }, `free: ${cookie.id}`, async () => {
|
67
|
+
await this._driver.free(cookie, options);
|
68
|
+
});
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* @returns {Promise<void>}
|
73
|
+
*/
|
74
|
+
async cleanup() {
|
75
|
+
if (typeof this._driver.cleanup === 'function') {
|
76
|
+
await this._driver.cleanup();
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* @returns {void}
|
82
|
+
*/
|
83
|
+
emergencyCleanup() {
|
84
|
+
if (typeof this._driver.emergencyCleanup === 'function') {
|
85
|
+
this._driver.emergencyCleanup();
|
86
|
+
}
|
41
87
|
}
|
42
88
|
}
|
43
89
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class DeviceListReadonly {
|
2
|
+
constructor(devices = []) {
|
3
|
+
this._devices = new Map(devices.map(device => [device.id, device]));
|
4
|
+
}
|
5
|
+
|
6
|
+
concat(other) {
|
7
|
+
return new DeviceListReadonly([...this, ...other]);
|
8
|
+
}
|
9
|
+
|
10
|
+
getIds() {
|
11
|
+
return [...this._devices.keys()];
|
12
|
+
}
|
13
|
+
|
14
|
+
[Symbol.iterator]() {
|
15
|
+
return this._devices.values();
|
16
|
+
}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @param {string} deviceId
|
20
|
+
* @returns {boolean}
|
21
|
+
*/
|
22
|
+
includes(deviceId) {
|
23
|
+
return this._devices.has(deviceId);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
class DeviceList extends DeviceListReadonly {
|
28
|
+
filter(predicate) {
|
29
|
+
return new DeviceListReadonly([...this].filter(predicate));
|
30
|
+
}
|
31
|
+
|
32
|
+
add(deviceId, data) {
|
33
|
+
this._devices.set(deviceId, {
|
34
|
+
id: deviceId,
|
35
|
+
...data,
|
36
|
+
});
|
37
|
+
}
|
38
|
+
|
39
|
+
delete(deviceId) {
|
40
|
+
this._devices.delete(deviceId);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
module.exports = DeviceList;
|
@@ -0,0 +1,189 @@
|
|
1
|
+
const ExclusiveLockfile = require('../../utils/ExclusiveLockfile');
|
2
|
+
const PIDService = require('../../utils/PIDService');
|
3
|
+
const { getDeviceRegistryPath } = require('../../utils/environment');
|
4
|
+
const safeAsync = require('../../utils/safeAsync');
|
5
|
+
|
6
|
+
const DeviceList = require('./DeviceList');
|
7
|
+
|
8
|
+
const readOptions = {
|
9
|
+
encoding: 'utf8',
|
10
|
+
};
|
11
|
+
|
12
|
+
class DeviceRegistry {
|
13
|
+
constructor({
|
14
|
+
lockfilePath = getDeviceRegistryPath(),
|
15
|
+
sessionId = '',
|
16
|
+
pidService = new PIDService(),
|
17
|
+
} = {}) {
|
18
|
+
/***
|
19
|
+
* @private
|
20
|
+
* @type {string}
|
21
|
+
*/
|
22
|
+
this._lockfilePath = lockfilePath;
|
23
|
+
/***
|
24
|
+
* @private
|
25
|
+
* @type {string}
|
26
|
+
*/
|
27
|
+
this._sessionId = sessionId;
|
28
|
+
/***
|
29
|
+
* @private
|
30
|
+
*/
|
31
|
+
this._pidService = pidService;
|
32
|
+
/***
|
33
|
+
* @protected
|
34
|
+
* @type {ExclusiveLockfile}
|
35
|
+
*/
|
36
|
+
this._lockfile = new ExclusiveLockfile(this._lockfilePath, {
|
37
|
+
getInitialState: this._getInitialLockFileState.bind(this),
|
38
|
+
readOptions,
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
42
|
+
get lockFilePath() {
|
43
|
+
return this._lockfilePath;
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Safety method to ensure that there are no remains of previously crashed Detox sessions.
|
48
|
+
*/
|
49
|
+
async reset() {
|
50
|
+
await this._lockfile.exclusively(() => {
|
51
|
+
const empty = this._getInitialLockFileState();
|
52
|
+
this._lockfile.write(empty);
|
53
|
+
});
|
54
|
+
}
|
55
|
+
|
56
|
+
/***
|
57
|
+
* @param {string|Function} getDeviceId
|
58
|
+
* @returns {Promise<string>}
|
59
|
+
*/
|
60
|
+
async registerDevice(getDeviceId) {
|
61
|
+
return this._lockfile.exclusively(async () => {
|
62
|
+
const deviceId = await safeAsync(getDeviceId);
|
63
|
+
if (deviceId) {
|
64
|
+
this._upsertDevice(deviceId, {
|
65
|
+
busy: true,
|
66
|
+
sessionId: this._sessionId,
|
67
|
+
pid: this._pidService.getPid(),
|
68
|
+
});
|
69
|
+
}
|
70
|
+
return deviceId;
|
71
|
+
});
|
72
|
+
}
|
73
|
+
|
74
|
+
/***
|
75
|
+
* @param {string|Function} getDeviceId
|
76
|
+
* @returns {Promise<string>}
|
77
|
+
*/
|
78
|
+
async releaseDevice(getDeviceId) {
|
79
|
+
return this._lockfile.exclusively(async () => {
|
80
|
+
const deviceId = await safeAsync(getDeviceId);
|
81
|
+
if (deviceId) {
|
82
|
+
this._upsertDevice(deviceId, {
|
83
|
+
busy: false,
|
84
|
+
sessionId: this._sessionId,
|
85
|
+
pid: this._pidService.getPid(),
|
86
|
+
});
|
87
|
+
}
|
88
|
+
return deviceId;
|
89
|
+
});
|
90
|
+
}
|
91
|
+
|
92
|
+
/***
|
93
|
+
* @param {string|Function} getDeviceId
|
94
|
+
* @returns {Promise<void>}
|
95
|
+
*/
|
96
|
+
async unregisterDevice(getDeviceId) {
|
97
|
+
await this._lockfile.exclusively(async () => {
|
98
|
+
const deviceId = await safeAsync(getDeviceId);
|
99
|
+
if (deviceId) {
|
100
|
+
this._deleteDevice(deviceId);
|
101
|
+
}
|
102
|
+
});
|
103
|
+
}
|
104
|
+
|
105
|
+
async unregisterSessionDevices() {
|
106
|
+
await this._lockfile.exclusively(async () => {
|
107
|
+
const allDevices = this._getRegisteredDevices();
|
108
|
+
const sessionDevices = allDevices.filter(device => device.sessionId === this._sessionId);
|
109
|
+
for (const id of sessionDevices.getIds()) {
|
110
|
+
allDevices.delete(id);
|
111
|
+
}
|
112
|
+
this._lockfile.write([...allDevices]);
|
113
|
+
});
|
114
|
+
}
|
115
|
+
|
116
|
+
async unregisterZombieDevices() {
|
117
|
+
await this._lockfile.exclusively(async () => {
|
118
|
+
const allDevices = this._getRegisteredDevices();
|
119
|
+
const zombieDevices = allDevices.filter(device => {
|
120
|
+
return device.sessionId !== this._sessionId && !this._pidService.isAlive(device.pid);
|
121
|
+
});
|
122
|
+
|
123
|
+
for (const id of zombieDevices.getIds()) {
|
124
|
+
allDevices.delete(id);
|
125
|
+
}
|
126
|
+
this._lockfile.write([...allDevices]);
|
127
|
+
});
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* @returns {Promise<DeviceList>}
|
132
|
+
*/
|
133
|
+
async readSessionDevices() {
|
134
|
+
let devices;
|
135
|
+
await this._lockfile.exclusively(() => {
|
136
|
+
devices = this._getSessionDevicesSync();
|
137
|
+
});
|
138
|
+
return devices;
|
139
|
+
}
|
140
|
+
|
141
|
+
getTakenDevicesSync() {
|
142
|
+
const allDevices = this._getRegisteredDevices();
|
143
|
+
const busyDevices = allDevices.filter(device => device.busy);
|
144
|
+
const externalDevices = allDevices.filter(device => device.sessionId !== this._sessionId);
|
145
|
+
return busyDevices.concat(externalDevices);
|
146
|
+
}
|
147
|
+
|
148
|
+
/***
|
149
|
+
* @private
|
150
|
+
*/
|
151
|
+
_getInitialLockFileState() {
|
152
|
+
return [];
|
153
|
+
}
|
154
|
+
|
155
|
+
/**
|
156
|
+
* @private
|
157
|
+
*/
|
158
|
+
_upsertDevice(deviceId, data) {
|
159
|
+
const devices = this._getRegisteredDevices();
|
160
|
+
devices.add(deviceId, data);
|
161
|
+
this._lockfile.write([...devices]);
|
162
|
+
}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* @private
|
166
|
+
*/
|
167
|
+
_deleteDevice(deviceId) {
|
168
|
+
const devices = this._getRegisteredDevices();
|
169
|
+
devices.delete(deviceId);
|
170
|
+
this._lockfile.write([...devices]);
|
171
|
+
}
|
172
|
+
|
173
|
+
/***
|
174
|
+
* @private
|
175
|
+
* @returns {DeviceList}
|
176
|
+
*/
|
177
|
+
_getRegisteredDevices() {
|
178
|
+
const devices = this._lockfile.read();
|
179
|
+
return new DeviceList(devices);
|
180
|
+
}
|
181
|
+
|
182
|
+
_getSessionDevicesSync() {
|
183
|
+
const devices = this._getRegisteredDevices();
|
184
|
+
const sessionDevices = devices.filter(device => device.sessionId === this._sessionId);
|
185
|
+
return sessionDevices;
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
module.exports = DeviceRegistry;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/* eslint-disable import/no-unresolved,node/no-missing-import,node/no-unsupported-features/es-syntax */
|
2
|
+
import { DeviceCookie } from '../../common/drivers/DeviceCookie';
|
3
|
+
|
4
|
+
export interface DeallocOptions {
|
5
|
+
shutdown?: boolean;
|
6
|
+
}
|
7
|
+
|
8
|
+
export interface AllocationDriverBase {
|
9
|
+
init?(): Promise<void>;
|
10
|
+
allocate(deviceConfig: any): Promise<DeviceCookie>;
|
11
|
+
postAllocate?(deviceCookie: DeviceCookie): Promise<DeviceCookie | void>;
|
12
|
+
free(cookie: DeviceCookie, options: DeallocOptions): Promise<void>;
|
13
|
+
cleanup?(): Promise<void>;
|
14
|
+
emergencyCleanup?(): void;
|
15
|
+
}
|
package/src/devices/{common/drivers/android/tools → allocation/drivers/android}/FreeDeviceFinder.js
RENAMED
@@ -1,6 +1,6 @@
|
|
1
|
-
const log = require('
|
1
|
+
const log = require('../../../../utils/logger').child({ cat: 'device' });
|
2
2
|
|
3
|
-
const
|
3
|
+
const DEVICE_LOOKUP = { event: 'DEVICE_LOOKUP' };
|
4
4
|
|
5
5
|
class FreeDeviceFinder {
|
6
6
|
constructor(adb, deviceRegistry) {
|
@@ -10,8 +10,9 @@ class FreeDeviceFinder {
|
|
10
10
|
|
11
11
|
async findFreeDevice(deviceQuery) {
|
12
12
|
const { devices } = await this.adb.devices();
|
13
|
+
const takenDevices = this.deviceRegistry.getTakenDevicesSync();
|
13
14
|
for (const candidate of devices) {
|
14
|
-
if (await this._isDeviceFreeAndMatching(candidate, deviceQuery)) {
|
15
|
+
if (await this._isDeviceFreeAndMatching(takenDevices, candidate, deviceQuery)) {
|
15
16
|
return candidate.adbName;
|
16
17
|
}
|
17
18
|
}
|
@@ -19,30 +20,30 @@ class FreeDeviceFinder {
|
|
19
20
|
}
|
20
21
|
|
21
22
|
/**
|
22
|
-
* @
|
23
|
+
* @private
|
23
24
|
*/
|
24
|
-
async _isDeviceFreeAndMatching(candidate, deviceQuery) {
|
25
|
+
async _isDeviceFreeAndMatching(takenDevices, candidate, deviceQuery) {
|
25
26
|
const { adbName } = candidate;
|
26
27
|
|
27
|
-
const isTaken =
|
28
|
+
const isTaken = takenDevices.includes(adbName);
|
28
29
|
if (isTaken) {
|
29
|
-
log.debug(
|
30
|
+
log.debug(DEVICE_LOOKUP, `Device ${adbName} is already taken, skipping...`);
|
30
31
|
return false;
|
31
32
|
}
|
32
33
|
|
33
34
|
const isOffline = candidate.status === 'offline';
|
34
35
|
if (isOffline) {
|
35
|
-
log.debug(
|
36
|
+
log.debug(DEVICE_LOOKUP, `Device ${adbName} is offline, skipping...`);
|
36
37
|
return false;
|
37
38
|
}
|
38
39
|
|
39
40
|
const isMatching = await this._isDeviceMatching(candidate, deviceQuery);
|
40
41
|
if (!isMatching) {
|
41
|
-
log.debug(
|
42
|
+
log.debug(DEVICE_LOOKUP, `Device ${adbName} does not match "${deviceQuery}"`);
|
42
43
|
return false;
|
43
44
|
}
|
44
45
|
|
45
|
-
log.debug(
|
46
|
+
log.debug(DEVICE_LOOKUP, `Found a matching & free device ${candidate.adbName}`);
|
46
47
|
return true;
|
47
48
|
}
|
48
49
|
|
@@ -1,20 +1,26 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/**
|
2
|
+
* @typedef {import('../../AllocationDriverBase').AllocationDriverBase} AllocationDriverBase
|
3
|
+
* @typedef {import('../../../../common/drivers/android/cookies').AndroidDeviceCookie} AndroidDeviceCookie
|
4
|
+
*/
|
4
5
|
|
5
|
-
|
6
|
+
/**
|
7
|
+
* @implements {AllocationDriverBase}
|
8
|
+
*/
|
9
|
+
class AttachedAndroidAllocDriver {
|
6
10
|
/**
|
7
|
-
* @param
|
8
|
-
* @param
|
9
|
-
* @param
|
10
|
-
* @param
|
11
|
+
* @param {object} options
|
12
|
+
* @param {import('../../../../common/drivers/android/exec/ADB')} options.adb
|
13
|
+
* @param {import('../../../DeviceRegistry')} options.deviceRegistry
|
14
|
+
* @param {import('../FreeDeviceFinder')} options.freeDeviceFinder
|
11
15
|
*/
|
12
|
-
constructor({ adb, deviceRegistry, freeDeviceFinder
|
13
|
-
super();
|
16
|
+
constructor({ adb, deviceRegistry, freeDeviceFinder }) {
|
14
17
|
this._adb = adb;
|
15
18
|
this._deviceRegistry = deviceRegistry;
|
16
19
|
this._freeDeviceFinder = freeDeviceFinder;
|
17
|
-
|
20
|
+
}
|
21
|
+
|
22
|
+
async init() {
|
23
|
+
await this._deviceRegistry.unregisterZombieDevices();
|
18
24
|
}
|
19
25
|
|
20
26
|
/**
|
@@ -23,13 +29,13 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
|
|
23
29
|
*/
|
24
30
|
async allocate(deviceConfig) {
|
25
31
|
const adbNamePattern = deviceConfig.device.adbName;
|
26
|
-
const adbName = await this._deviceRegistry.
|
32
|
+
const adbName = await this._deviceRegistry.registerDevice(() => this._freeDeviceFinder.findFreeDevice(adbNamePattern));
|
27
33
|
|
28
|
-
return
|
34
|
+
return { id: adbName, adbName };
|
29
35
|
}
|
30
36
|
|
31
37
|
/**
|
32
|
-
* @param {
|
38
|
+
* @param {AndroidDeviceCookie} deviceCookie
|
33
39
|
* @returns {Promise<void>}
|
34
40
|
*/
|
35
41
|
async postAllocate(deviceCookie) {
|
@@ -38,16 +44,15 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
|
|
38
44
|
// TODO Also disable native animations?
|
39
45
|
await this._adb.apiLevel(adbName);
|
40
46
|
await this._adb.unlockScreen(adbName);
|
41
|
-
await this._attachedAndroidLauncher.notifyLaunchCompleted(adbName);
|
42
47
|
}
|
43
48
|
|
44
49
|
/**
|
45
|
-
* @param cookie {
|
50
|
+
* @param cookie { AndroidDeviceCookie }
|
46
51
|
* @return {Promise<void>}
|
47
52
|
*/
|
48
53
|
async free(cookie) {
|
49
54
|
const { adbName } = cookie;
|
50
|
-
await this._deviceRegistry.
|
55
|
+
await this._deviceRegistry.unregisterDevice(adbName);
|
51
56
|
}
|
52
57
|
}
|
53
58
|
|