detox 20.31.0 → 20.33.0-prerelease.0
Sign up to get free protection for your applications and to get access to all the features.
- package/Detox-android/com/wix/detox/{20.30.0/detox-20.30.0-sources.jar → 20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.30.0/detox-20.30.0.pom → 20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom} +13 -1
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.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/detox/build.gradle +6 -1
- package/android/detox/proguard-rules-app.pro +12 -0
- package/android/detox/src/full/java/com/wix/detox/DetoxMain.kt +4 -3
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactApplicationExt.kt +34 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +22 -27
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt +51 -71
- package/android/detox/src/full/java/com/wix/detox/reactnative/helpers/RNHelpers.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +4 -2
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +17 -13
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +5 -2
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +9 -20
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactoryStrategy.kt +7 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/FabricDetoxIdlingResourceFactoryStrategy.kt +31 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/OldArchitectureDetoxIdlingResourceFactoryStrategy.kt +33 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +5 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkingModuleReflected.kt +11 -14
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/storage/AsyncStorageIdlingResource.kt +31 -29
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/FabricTimersIdlingResource.kt +50 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/JavaTimersReflected.kt +26 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +6 -5
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/fabric/FabricUIManagerIdlingResources.kt +70 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{DispatchCommandOperationReflected.kt → paper/DispatchCommandOperationReflected.kt} +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{NativeHierarchyManagerReflected.kt → paper/NativeHierarchyManagerReflected.kt} +5 -3
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{UIManagerModuleReflected.kt → paper/UIManagerModuleReflected.kt} +5 -3
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{UIModuleIdlingResource.kt → paper/UIModuleIdlingResource.kt} +12 -4
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{ViewCommandOpsQueueReflected.kt → paper/ViewCommandOpsQueueReflected.kt} +3 -3
- package/android/detox/src/full/java/com/wix/detox/reactnative/reloader/ReactNativeReloader.kt +34 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/reloader/ReactNativeReloaderFactory.kt +18 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +9 -2
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +9 -3
- package/package.json +2 -2
- package/scripts/updateGradle.js +37 -0
- package/src/DetoxWorker.js +1 -2
- package/src/devices/allocation/drivers/android/genycloud/exec/GenyCloudExec.js +14 -8
- package/src/devices/validation/android/GenycloudEnvValidator.js +20 -3
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeReloader.kt +0 -16
Binary file
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.md5
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1d5caeb258300c395eb77d0578fc82c0
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha1
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
f8170fd9458971b52edf5cac9c405b006897dfda
|
@@ -0,0 +1 @@
|
|
1
|
+
a8cf832ed05547b999c437611e921271ae2aaafe7a19bfda8bc6737e4d3ba7d0
|
@@ -0,0 +1 @@
|
|
1
|
+
8bd107bedd83c2784c3d19782e9a1f8ee6d7d66eb8bd4fe04a2a7603a23d257ac6cc516552a8238ec8e13fbabcd406cb1a458ae270d18f1b45094f22a69b3e6a
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
4ab2c960e9f1d12a9daa555f3db6554c
|
@@ -0,0 +1 @@
|
|
1
|
+
4068d06887f8949b32a0cf36fed6f3e70bb4f922
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha256
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
189187fc397bdb111df5485b64ff7154c84ce232240594646896f11c6f433ef6
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha512
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3906c9b7a0dc913a2697a735819c907f62c4eb516f40e492bba0df74e54ee99927b36d5771f942e29054a94dd03c573bfed9a372756c5fcb42f0d3f0b53f85df
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
4
4
|
<groupId>com.wix</groupId>
|
5
5
|
<artifactId>detox</artifactId>
|
6
|
-
<version>20.
|
6
|
+
<version>20.33.0-prerelease.0</version>
|
7
7
|
<packaging>aar</packaging>
|
8
8
|
<name>Detox</name>
|
9
9
|
<description>Gray box end-to-end testing and automation library for mobile apps</description>
|
@@ -84,6 +84,18 @@
|
|
84
84
|
<version>2.2.0</version>
|
85
85
|
<scope>compile</scope>
|
86
86
|
</dependency>
|
87
|
+
<dependency>
|
88
|
+
<groupId>androidx.test</groupId>
|
89
|
+
<artifactId>core-ktx</artifactId>
|
90
|
+
<version>1.6.1</version>
|
91
|
+
<scope>compile</scope>
|
92
|
+
</dependency>
|
93
|
+
<dependency>
|
94
|
+
<groupId>org.jetbrains.kotlin</groupId>
|
95
|
+
<artifactId>kotlin-reflect</artifactId>
|
96
|
+
<version>1.9.24</version>
|
97
|
+
<scope>runtime</scope>
|
98
|
+
</dependency>
|
87
99
|
<dependency>
|
88
100
|
<groupId>org.apache.commons</groupId>
|
89
101
|
<artifactId>commons-lang3</artifactId>
|
@@ -0,0 +1 @@
|
|
1
|
+
92a1842fd8b468f7d2617fdd5818460d
|
@@ -0,0 +1 @@
|
|
1
|
+
53fac1636a7713666c932f139c9ee11e57e1ebc2
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha256
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
798ac5edd34d8550949f1ccd01997146980586ba5d2ddb898f55352119dd0cdc
|
package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha512
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ad694f20be729a5ee85ce82a6c40c38d00519123e4fdba9147f460ee13e5fdde200007689394e1f358f66df81951153f3b25d2f99e1d9af7c504f16e14174dcd
|
@@ -3,11 +3,11 @@
|
|
3
3
|
<groupId>com.wix</groupId>
|
4
4
|
<artifactId>detox</artifactId>
|
5
5
|
<versioning>
|
6
|
-
<latest>20.
|
7
|
-
<release>20.
|
6
|
+
<latest>20.33.0-prerelease.0</latest>
|
7
|
+
<release>20.33.0-prerelease.0</release>
|
8
8
|
<versions>
|
9
|
-
<version>20.
|
9
|
+
<version>20.33.0-prerelease.0</version>
|
10
10
|
</versions>
|
11
|
-
<lastUpdated>
|
11
|
+
<lastUpdated>20250128142241</lastUpdated>
|
12
12
|
</versioning>
|
13
13
|
</metadata>
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
f16f4bdb9f7dde7c65d8b063da273ae1
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
da85452d2eeb7463aece46e69ccb689c12c06844
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
223da53f8133c03f92bd33fc684cff73fe42cedf782a035c6e54c885a8c6cae7
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
5537372f15749a8bc0c294de80fb75a785a209fa10e7bd897696ee58947b316c17508ab02c7160f223ebc956a9d994f2e4a448d6bab473f074b682bcda309d0c
|
package/Detox-ios-framework.tbz
CHANGED
Binary file
|
package/Detox-ios-src.tbz
CHANGED
Binary file
|
package/Detox-ios-xcuitest.tbz
CHANGED
Binary file
|
@@ -147,6 +147,12 @@ dependencies {
|
|
147
147
|
api('androidx.test.uiautomator:uiautomator:2.2.0') {
|
148
148
|
because 'Needed by Detox but also makes UIAutomator seamlessly provided to Detox users with hybrid apps/E2E-tests.'
|
149
149
|
}
|
150
|
+
api('androidx.test:core-ktx:1.6.1') {
|
151
|
+
because 'Needed by Detox but also makes AndroidX test core seamlessly provided to Detox users with hybrid apps/E2E-tests.'
|
152
|
+
}
|
153
|
+
implementation("org.jetbrains.kotlin:kotlin-reflect:$_kotlinVersion") {
|
154
|
+
because('Needed by Detox for kotlin reflection')
|
155
|
+
}
|
150
156
|
}
|
151
157
|
|
152
158
|
// Third-party/extension deps.
|
@@ -199,7 +205,6 @@ if (rootProject.hasProperty('isOfficialDetoxLib') ||
|
|
199
205
|
dependencies {
|
200
206
|
testImplementation 'org.spekframework.spek2:spek-dsl-jvm:2.0.15'
|
201
207
|
testImplementation 'org.spekframework.spek2:spek-runner-junit5:2.0.15'
|
202
|
-
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$_kotlinVersion"
|
203
208
|
}
|
204
209
|
}
|
205
210
|
|
@@ -1,10 +1,18 @@
|
|
1
1
|
-keepattributes InnerClasses, Exceptions
|
2
2
|
|
3
|
+
-keep class com.facebook.react.fabric.FabricUIManager { *; }
|
4
|
+
-keep class com.facebook.react.fabric.mounting.MountItemDispatcher { *; }
|
3
5
|
-keep class com.facebook.react.modules.** { *; }
|
4
6
|
-keep class com.facebook.react.uimanager.** { *; }
|
5
7
|
-keep class com.facebook.react.animated.** { *; }
|
6
8
|
-keep class com.facebook.react.ReactApplication { *; }
|
7
9
|
-keep class com.facebook.react.ReactNativeHost { *; }
|
10
|
+
-keep class com.facebook.react.ReactHost { *; }
|
11
|
+
-keep class com.facebook.react.runtime.ReactHostImpl { *; }
|
12
|
+
-keep class com.facebook.react.runtime.BridgelessReactContext { *; }
|
13
|
+
-keep class com.facebook.react.runtime.ReactInstance { *; }
|
14
|
+
-keep class com.facebook.react.modules.core.JavaTimerManager { *; }
|
15
|
+
|
8
16
|
-keep class com.facebook.react.ReactInstanceManager { *; }
|
9
17
|
-keep class com.facebook.react.ReactInstanceManager** { *; }
|
10
18
|
-keep class com.facebook.react.ReactInstanceEventListener { *; }
|
@@ -18,6 +26,10 @@
|
|
18
26
|
-keep class com.reactnativecommunity.asyncstorage.** { *; }
|
19
27
|
|
20
28
|
-keep class kotlin.reflect.** { *; }
|
29
|
+
-keep class kotlin.KotlinVersion { *; }
|
30
|
+
-keep class kotlin.sequences.** { *; }
|
31
|
+
-keep class kotlin.Triple { *; }
|
32
|
+
-keep class kotlin.properties.** { *; }
|
21
33
|
-keep class kotlin.coroutines.CoroutineDispatcher { *; }
|
22
34
|
-keep class kotlin.coroutines.CoroutineScope { *; }
|
23
35
|
-keep class kotlin.coroutines.CoroutineContext { *; }
|
@@ -47,10 +47,11 @@ object DetoxMain {
|
|
47
47
|
* not by instrumentation itself, but based on the `AppWillTerminateWithError` message; In it's own, it is a good
|
48
48
|
* thing, but for a reason we're not sure of yet, it is ignored by the test runner at this point in the flow.
|
49
49
|
*/
|
50
|
-
@Synchronized
|
51
50
|
private fun launchActivityOnCue(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
|
52
|
-
|
53
|
-
|
51
|
+
synchronized(this) {
|
52
|
+
awaitHandshake()
|
53
|
+
launchActivity(rnHostHolder, activityLaunchHelper)
|
54
|
+
}
|
54
55
|
}
|
55
56
|
|
56
57
|
private fun awaitHandshake() {
|
@@ -0,0 +1,34 @@
|
|
1
|
+
package com.wix.detox.reactnative
|
2
|
+
|
3
|
+
import android.annotation.SuppressLint
|
4
|
+
import com.facebook.react.ReactApplication
|
5
|
+
import com.facebook.react.ReactInstanceManager
|
6
|
+
import com.facebook.react.bridge.ReactContext
|
7
|
+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
|
8
|
+
|
9
|
+
|
10
|
+
fun ReactApplication.getInstanceManagerSafe(): ReactInstanceManager {
|
11
|
+
return reactNativeHost.reactInstanceManager
|
12
|
+
?: throw RuntimeException("ReactInstanceManager is null!")
|
13
|
+
}
|
14
|
+
|
15
|
+
@SuppressLint("VisibleForTests")
|
16
|
+
fun ReactApplication.getCurrentReactContext(): ReactContext? {
|
17
|
+
return if (isFabricEnabled()) {
|
18
|
+
reactHost?.currentReactContext
|
19
|
+
} else {
|
20
|
+
getInstanceManagerSafe().currentReactContext
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
fun ReactApplication.getCurrentReactContextSafe(): ReactContext {
|
25
|
+
return getCurrentReactContext()
|
26
|
+
?: throw RuntimeException("ReactContext is null!")
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* A method to check if Fabric is enabled in the React Native application.
|
31
|
+
*/
|
32
|
+
fun isFabricEnabled(): Boolean {
|
33
|
+
return DefaultNewArchitectureEntryPoint.fabricEnabled
|
34
|
+
}
|
@@ -5,10 +5,10 @@ import android.content.Context
|
|
5
5
|
import android.util.Log
|
6
6
|
import androidx.test.platform.app.InstrumentationRegistry
|
7
7
|
import com.facebook.react.ReactApplication
|
8
|
-
import com.facebook.react.ReactInstanceManager
|
9
8
|
import com.facebook.react.bridge.ReactContext
|
10
9
|
import com.wix.detox.LaunchArgs
|
11
10
|
import com.wix.detox.reactnative.idlingresources.ReactNativeIdlingResources
|
11
|
+
import com.wix.detox.reactnative.reloader.ReactNativeReloaderFactory
|
12
12
|
|
13
13
|
private const val LOG_TAG = "DetoxRNExt"
|
14
14
|
|
@@ -34,9 +34,9 @@ object ReactNativeExtension {
|
|
34
34
|
}
|
35
35
|
|
36
36
|
(applicationContext as ReactApplication).let {
|
37
|
-
|
37
|
+
awaitNewReactNativeContext(it, null)
|
38
38
|
|
39
|
-
enableOrDisableSynchronization(
|
39
|
+
enableOrDisableSynchronization(it)
|
40
40
|
}
|
41
41
|
}
|
42
42
|
|
@@ -59,12 +59,12 @@ object ReactNativeExtension {
|
|
59
59
|
(applicationContext as ReactApplication).let {
|
60
60
|
clearIdlingResources()
|
61
61
|
|
62
|
-
val previousReactContext =
|
62
|
+
val previousReactContext = it.getCurrentReactContext()
|
63
63
|
|
64
64
|
reloadReactNativeInBackground(it)
|
65
|
-
|
65
|
+
awaitNewReactNativeContext(it, previousReactContext)
|
66
66
|
|
67
|
-
enableOrDisableSynchronization(
|
67
|
+
enableOrDisableSynchronization(it)
|
68
68
|
}
|
69
69
|
}
|
70
70
|
|
@@ -75,11 +75,7 @@ object ReactNativeExtension {
|
|
75
75
|
|
76
76
|
@JvmStatic
|
77
77
|
fun enableAllSynchronization(applicationContext: ReactApplication) {
|
78
|
-
|
79
|
-
|
80
|
-
if (reactContext != null) {
|
81
|
-
setupIdlingResources(reactContext)
|
82
|
-
}
|
78
|
+
setupIdlingResources(applicationContext)
|
83
79
|
}
|
84
80
|
|
85
81
|
@JvmStatic
|
@@ -88,7 +84,7 @@ object ReactNativeExtension {
|
|
88
84
|
@JvmStatic
|
89
85
|
fun getRNActivity(applicationContext: Context): Activity? {
|
90
86
|
if (ReactNativeInfo.isReactNativeApp()) {
|
91
|
-
return
|
87
|
+
return (applicationContext as ReactApplication).getCurrentReactContext()?.currentActivity
|
92
88
|
}
|
93
89
|
return null
|
94
90
|
}
|
@@ -115,20 +111,27 @@ object ReactNativeExtension {
|
|
115
111
|
}
|
116
112
|
|
117
113
|
private fun reloadReactNativeInBackground(reactApplication: ReactApplication) {
|
118
|
-
val rnReloader =
|
114
|
+
val rnReloader = ReactNativeReloaderFactory(InstrumentationRegistry.getInstrumentation(), reactApplication).create()
|
119
115
|
rnReloader.reloadInBackground()
|
120
116
|
}
|
121
117
|
|
122
|
-
private fun awaitNewReactNativeContext(
|
123
|
-
|
118
|
+
private fun awaitNewReactNativeContext(
|
119
|
+
reactApplication: ReactApplication,
|
120
|
+
previousReactContext: ReactContext?
|
121
|
+
): ReactContext {
|
122
|
+
val rnLoadingMonitor = ReactNativeLoadingMonitor(
|
123
|
+
InstrumentationRegistry.getInstrumentation(),
|
124
|
+
reactApplication,
|
125
|
+
previousReactContext
|
126
|
+
)
|
124
127
|
return rnLoadingMonitor.getNewContext()!!
|
125
128
|
}
|
126
129
|
|
127
|
-
private fun enableOrDisableSynchronization(
|
130
|
+
private fun enableOrDisableSynchronization(reactApplication: ReactApplication) {
|
128
131
|
if (shouldDisableSynchronization()) {
|
129
132
|
clearAllSynchronization()
|
130
133
|
} else {
|
131
|
-
setupIdlingResources(
|
134
|
+
setupIdlingResources(reactApplication)
|
132
135
|
}
|
133
136
|
}
|
134
137
|
|
@@ -137,10 +140,10 @@ object ReactNativeExtension {
|
|
137
140
|
return launchArgs.hasEnableSynchronization() && launchArgs.enableSynchronization.equals("0")
|
138
141
|
}
|
139
142
|
|
140
|
-
private fun setupIdlingResources(
|
143
|
+
private fun setupIdlingResources(reactApplication: ReactApplication) {
|
141
144
|
val launchArgs = LaunchArgs()
|
142
145
|
|
143
|
-
rnIdlingResources = ReactNativeIdlingResources(
|
146
|
+
rnIdlingResources = ReactNativeIdlingResources(reactApplication, launchArgs).apply {
|
144
147
|
registerAll()
|
145
148
|
}
|
146
149
|
}
|
@@ -150,12 +153,4 @@ object ReactNativeExtension {
|
|
150
153
|
rnIdlingResources = null
|
151
154
|
}
|
152
155
|
|
153
|
-
private fun getInstanceManagerSafe(reactApplication: ReactApplication): ReactInstanceManager {
|
154
|
-
return reactApplication.reactNativeHost.reactInstanceManager
|
155
|
-
?: throw RuntimeException("ReactInstanceManager is null!")
|
156
|
-
}
|
157
|
-
|
158
|
-
private fun getCurrentReactContextSafe(reactApplication: ReactApplication): ReactContext? {
|
159
|
-
return getInstanceManagerSafe(reactApplication).currentReactContext
|
160
|
-
}
|
161
156
|
}
|
@@ -3,25 +3,22 @@ package com.wix.detox.reactnative
|
|
3
3
|
import android.app.Instrumentation
|
4
4
|
import android.util.Log
|
5
5
|
import com.facebook.react.ReactApplication
|
6
|
-
import com.facebook.react.
|
6
|
+
import com.facebook.react.ReactInstanceEventListener
|
7
7
|
import com.facebook.react.bridge.ReactContext
|
8
|
+
import com.facebook.react.runtime.ReactHostImpl
|
8
9
|
import com.wix.detox.common.DetoxErrors
|
9
10
|
import com.wix.detox.config.DetoxConfig
|
10
|
-
import org.joor.Reflect
|
11
|
-
import java.lang.reflect.Proxy
|
12
11
|
import java.util.concurrent.CountDownLatch
|
13
12
|
import java.util.concurrent.TimeUnit
|
14
13
|
|
15
14
|
private const val LOG_TAG = "DetoxRNLoading"
|
16
15
|
|
17
|
-
private const val REACT_INSTANCE_EVENT_LISTENER_CLASS = "com.facebook.react.ReactInstanceEventListener"
|
18
|
-
private const val REACT_INSTANCE_EVENT_LISTENER_CLASS_COMPAT = "com.facebook.react.ReactInstanceManager\$ReactInstanceEventListener"
|
19
|
-
|
20
16
|
open class ReactNativeLoadingMonitor(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
private val instrumentation: Instrumentation,
|
18
|
+
private val rnApplication: ReactApplication,
|
19
|
+
private val previousReactContext: ReactContext?,
|
20
|
+
private val config: DetoxConfig = DetoxConfig.CONFIG
|
21
|
+
) {
|
25
22
|
private val countDownLatch = CountDownLatch(1)
|
26
23
|
|
27
24
|
fun getNewContext(): ReactContext? {
|
@@ -31,24 +28,21 @@ open class ReactNativeLoadingMonitor(
|
|
31
28
|
|
32
29
|
private fun subscribeToNewRNContextUpdates() {
|
33
30
|
instrumentation.runOnMainSync(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
}
|
31
|
+
Runnable {
|
32
|
+
val reactContext = rnApplication.getCurrentReactContext()
|
33
|
+
if (isReactNativeLoaded(reactContext)) {
|
34
|
+
Log.d(LOG_TAG, "Got new RN-context directly and immediately")
|
35
|
+
countDownLatch.countDown()
|
36
|
+
return@Runnable
|
37
|
+
}
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
subscribeAsyncRNContextHandler() {
|
40
|
+
countDownLatch.countDown()
|
41
|
+
}
|
42
|
+
})
|
47
43
|
}
|
48
44
|
|
49
45
|
private fun awaitNewRNContext(): ReactContext? {
|
50
|
-
val rnInstanceManager = rnApplication.reactNativeHost.reactInstanceManager
|
51
|
-
|
52
46
|
var i = 0
|
53
47
|
while (true) {
|
54
48
|
try {
|
@@ -58,19 +52,22 @@ open class ReactNativeLoadingMonitor(
|
|
58
52
|
// First load can take a lot of time. (packager)
|
59
53
|
// Loads afterwards should take less than a second.
|
60
54
|
throw DetoxErrors.DetoxRuntimeException(
|
61
|
-
|
55
|
+
"""Waited for the new RN-context for too long! (${config.rnContextLoadTimeoutSec} seconds)
|
62
56
|
|If you think that's not long enough, consider applying a custom Detox runtime-config in DetoxTest.runTests()."""
|
63
|
-
.trimMargin()
|
57
|
+
.trimMargin()
|
58
|
+
)
|
64
59
|
}
|
65
60
|
} else {
|
66
61
|
break
|
67
62
|
}
|
68
63
|
|
69
|
-
// Due to
|
64
|
+
// Due to timing in RN
|
70
65
|
// it is possible that our listener won't be ever called
|
71
66
|
// That's why we have to check the reactContext regularly.
|
72
|
-
val reactContext =
|
73
|
-
|
67
|
+
val reactContext = rnApplication.getCurrentReactContext()
|
68
|
+
|
69
|
+
// We also need to wait for rect native instance to be initialized
|
70
|
+
if (isReactNativeLoaded(reactContext)) {
|
74
71
|
Log.d(LOG_TAG, "Got new RN-context explicitly while polling (#iteration=$i)")
|
75
72
|
break
|
76
73
|
}
|
@@ -79,51 +76,34 @@ open class ReactNativeLoadingMonitor(
|
|
79
76
|
}
|
80
77
|
}
|
81
78
|
|
82
|
-
return
|
79
|
+
return rnApplication.getCurrentReactContext()
|
83
80
|
}
|
84
|
-
}
|
85
81
|
|
86
|
-
private
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
Log.i(LOG_TAG, "Got new RN-context async'ly through listener")
|
111
|
-
Reflect.on(rnInstanceManager).call("removeReactInstanceEventListener", listener)
|
112
|
-
onReactContextInitialized()
|
113
|
-
}
|
114
|
-
"equals" -> {
|
115
|
-
val candidate = args[0]
|
116
|
-
candidate is DummyListenerIdentifier
|
117
|
-
}
|
118
|
-
else -> Any()
|
82
|
+
private fun isReactNativeLoaded(reactContext: ReactContext?) =
|
83
|
+
reactContext != null && reactContext !== previousReactContext && reactContext.hasActiveReactInstance()
|
84
|
+
|
85
|
+
private fun subscribeAsyncRNContextHandler(onReactContextInitialized: () -> Any) {
|
86
|
+
val isFabric = isFabricEnabled()
|
87
|
+
if (isFabric) {
|
88
|
+
// We do a casting for supporting RN 0.75 and above
|
89
|
+
val host = rnApplication.reactHost as ReactHostImpl?
|
90
|
+
host?.addReactInstanceEventListener(object : ReactInstanceEventListener {
|
91
|
+
override fun onReactContextInitialized(context: ReactContext) {
|
92
|
+
Log.i(LOG_TAG, "Got new RN-context through listener")
|
93
|
+
onReactContextInitialized()
|
94
|
+
host.removeReactInstanceEventListener(this)
|
95
|
+
}
|
96
|
+
})
|
97
|
+
} else {
|
98
|
+
val rnInstanceManager = rnApplication.getInstanceManagerSafe()
|
99
|
+
rnInstanceManager.addReactInstanceEventListener(object : ReactInstanceEventListener {
|
100
|
+
override fun onReactContextInitialized(context: ReactContext) {
|
101
|
+
Log.i(LOG_TAG, "Got new RN-context directly through listener")
|
102
|
+
onReactContextInitialized()
|
103
|
+
rnInstanceManager.removeReactInstanceEventListener(this)
|
104
|
+
}
|
105
|
+
})
|
119
106
|
}
|
120
|
-
|
121
|
-
result
|
122
107
|
}
|
123
|
-
Reflect.on(rnInstanceManager).call("addReactInstanceEventListener", listener)
|
124
108
|
}
|
125
109
|
|
126
|
-
private fun resolveListenerClass(): Class<*> {
|
127
|
-
val className = if (ReactNativeInfo.rnVersion().minor >= 68) REACT_INSTANCE_EVENT_LISTENER_CLASS else REACT_INSTANCE_EVENT_LISTENER_CLASS_COMPAT
|
128
|
-
return Class.forName(className)
|
129
|
-
}
|
@@ -6,7 +6,7 @@ import com.facebook.react.bridge.ReactContext
|
|
6
6
|
|
7
7
|
private const val LOG_TAG = "DetoxRNHelpers"
|
8
8
|
|
9
|
-
|
9
|
+
class RNHelpers {
|
10
10
|
fun getNativeModule(reactContext: ReactContext, className: String): NativeModule? =
|
11
11
|
try {
|
12
12
|
val moduleClass = Class.forName(className) as Class<NativeModule>
|
package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
package com.wix.detox.reactnative.idlingresources
|
2
2
|
|
3
|
+
import androidx.annotation.VisibleForTesting
|
3
4
|
import androidx.test.espresso.IdlingResource
|
4
5
|
import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource
|
5
6
|
import java.util.concurrent.atomic.AtomicBoolean
|
6
7
|
|
7
8
|
abstract class DetoxIdlingResource : DescriptiveIdlingResource {
|
8
9
|
private var callback: IdlingResource.ResourceCallback? = null
|
9
|
-
|
10
|
+
@VisibleForTesting
|
11
|
+
internal var paused: AtomicBoolean = AtomicBoolean(false)
|
10
12
|
|
11
13
|
fun pause() {
|
12
14
|
paused.set(true)
|
@@ -30,7 +32,7 @@ abstract class DetoxIdlingResource : DescriptiveIdlingResource {
|
|
30
32
|
}
|
31
33
|
|
32
34
|
open fun onUnregistered() {
|
33
|
-
|
35
|
+
pause()
|
34
36
|
}
|
35
37
|
|
36
38
|
protected abstract fun checkIdle(): Boolean
|
@@ -5,8 +5,9 @@ import android.util.Log
|
|
5
5
|
import androidx.test.espresso.Espresso
|
6
6
|
import androidx.test.espresso.IdlingRegistry
|
7
7
|
import androidx.test.espresso.base.IdlingResourceRegistry
|
8
|
-
import com.facebook.react.
|
8
|
+
import com.facebook.react.ReactApplication
|
9
9
|
import com.wix.detox.LaunchArgs
|
10
|
+
import com.wix.detox.reactnative.getCurrentReactContext
|
10
11
|
import com.wix.detox.reactnative.idlingresources.factory.DetoxIdlingResourceFactory
|
11
12
|
import com.wix.detox.reactnative.idlingresources.factory.IdlingResourcesName
|
12
13
|
import com.wix.detox.reactnative.idlingresources.factory.LooperName
|
@@ -19,9 +20,9 @@ import org.joor.Reflect
|
|
19
20
|
private const val LOG_TAG = "DetoxRNIdleRes"
|
20
21
|
|
21
22
|
class ReactNativeIdlingResources(
|
22
|
-
private val
|
23
|
+
private val reactApplication: ReactApplication,
|
23
24
|
private var launchArgs: LaunchArgs,
|
24
|
-
private val idlingResourcesFactory: DetoxIdlingResourceFactory = DetoxIdlingResourceFactory(
|
25
|
+
private val idlingResourcesFactory: DetoxIdlingResourceFactory = DetoxIdlingResourceFactory(reactApplication)
|
25
26
|
) {
|
26
27
|
|
27
28
|
private val idlingResources = mutableMapOf<IdlingResourcesName, DetoxIdlingResource>()
|
@@ -52,8 +53,8 @@ class ReactNativeIdlingResources(
|
|
52
53
|
|
53
54
|
fun pauseRNTimersIdlingResource() = pauseIdlingResource(IdlingResourcesName.Timers)
|
54
55
|
fun resumeRNTimersIdlingResource() = resumeIdlingResource(IdlingResourcesName.Timers)
|
55
|
-
fun pauseUIIdlingResource() = pauseIdlingResource(IdlingResourcesName.
|
56
|
-
fun resumeUIIdlingResource() = resumeIdlingResource(IdlingResourcesName.
|
56
|
+
fun pauseUIIdlingResource() = pauseIdlingResource(IdlingResourcesName.UI)
|
57
|
+
fun resumeUIIdlingResource() = resumeIdlingResource(IdlingResourcesName.UI)
|
57
58
|
|
58
59
|
fun setBlacklistUrls(urlList: String) {
|
59
60
|
setIdlingResourceBlacklist(urlList)
|
@@ -77,16 +78,19 @@ class ReactNativeIdlingResources(
|
|
77
78
|
}
|
78
79
|
|
79
80
|
private fun setupMQThreadsInterrogator(looperName: LooperName) {
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
reactApplication.getCurrentReactContext()?.let {
|
82
|
+
val mqThreadsReflector = MQThreadsReflector(it)
|
83
|
+
val looper = when (looperName) {
|
84
|
+
LooperName.JS -> mqThreadsReflector.getJSMQueue()?.getLooper()
|
85
|
+
LooperName.NativeModules -> mqThreadsReflector.getNativeModulesQueue()?.getLooper()
|
86
|
+
}
|
87
|
+
|
88
|
+
looper?.let {
|
89
|
+
IdlingRegistry.getInstance().registerLooperAsIdlingResource(it)
|
90
|
+
loopers[looperName] = it
|
91
|
+
}
|
84
92
|
}
|
85
93
|
|
86
|
-
looper?.let {
|
87
|
-
IdlingRegistry.getInstance().registerLooperAsIdlingResource(it)
|
88
|
-
loopers[looperName] = it
|
89
|
-
}
|
90
94
|
}
|
91
95
|
|
92
96
|
private suspend fun setupIdlingResources() {
|
@@ -53,9 +53,12 @@ class AnimatedModuleIdlingResource(private val reactContext: ReactContext) : Det
|
|
53
53
|
Choreographer.getInstance().postFrameCallback(this)
|
54
54
|
}
|
55
55
|
|
56
|
+
override fun onUnregistered() {
|
57
|
+
super.onUnregistered()
|
58
|
+
Choreographer.getInstance().removeFrameCallback(this)
|
59
|
+
}
|
60
|
+
|
56
61
|
override fun doFrame(frameTimeNanos: Long) {
|
57
62
|
isIdleNow
|
58
63
|
}
|
59
64
|
}
|
60
|
-
|
61
|
-
|