detox 20.32.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.32.0/detox-20.32.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.32.0/detox-20.32.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/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeReloader.kt +0 -16
@@ -1,32 +1,21 @@
|
|
1
1
|
package com.wix.detox.reactnative.idlingresources.factory
|
2
2
|
|
3
|
-
import com.facebook.react.
|
3
|
+
import com.facebook.react.ReactApplication
|
4
4
|
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
5
|
-
import com.wix.detox.reactnative.
|
6
|
-
import com.wix.detox.reactnative.idlingresources.bridge.BridgeIdlingResource
|
7
|
-
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource
|
8
|
-
import com.wix.detox.reactnative.idlingresources.storage.AsyncStorageIdlingResource
|
9
|
-
import com.wix.detox.reactnative.idlingresources.timers.TimersIdlingResource
|
10
|
-
import com.wix.detox.reactnative.idlingresources.uimodule.UIModuleIdlingResource
|
5
|
+
import com.wix.detox.reactnative.isFabricEnabled
|
11
6
|
import kotlinx.coroutines.Dispatchers
|
12
7
|
import kotlinx.coroutines.withContext
|
13
8
|
|
14
|
-
class DetoxIdlingResourceFactory(private val reactContext: ReactContext) {
|
15
|
-
suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource> = withContext(Dispatchers.Main) {
|
16
|
-
val result = mutableMapOf(
|
17
|
-
IdlingResourcesName.Timers to TimersIdlingResource(reactContext),
|
18
|
-
IdlingResourcesName.RNBridge to BridgeIdlingResource(reactContext),
|
19
|
-
IdlingResourcesName.UIModule to UIModuleIdlingResource(reactContext),
|
20
|
-
IdlingResourcesName.Animations to AnimatedModuleIdlingResource(reactContext),
|
21
|
-
IdlingResourcesName.Network to NetworkIdlingResource(reactContext)
|
22
|
-
)
|
23
9
|
|
24
|
-
|
25
|
-
|
26
|
-
|
10
|
+
class DetoxIdlingResourceFactory(private val reactApplication: ReactApplication) {
|
11
|
+
suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource> = withContext(Dispatchers.Main) {
|
12
|
+
val strategy = if (isFabricEnabled()) {
|
13
|
+
FabricDetoxIdlingResourceFactoryStrategy(reactApplication)
|
14
|
+
} else {
|
15
|
+
OldArchitectureDetoxIdlingResourceFactoryStrategy(reactApplication)
|
27
16
|
}
|
28
17
|
|
29
|
-
return@withContext
|
18
|
+
return@withContext strategy.create()
|
30
19
|
}
|
31
20
|
}
|
32
21
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.factory
|
2
|
+
|
3
|
+
import com.facebook.react.ReactApplication
|
4
|
+
import com.wix.detox.reactnative.getCurrentReactContext
|
5
|
+
import com.wix.detox.reactnative.getCurrentReactContextSafe
|
6
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
7
|
+
import com.wix.detox.reactnative.idlingresources.animations.AnimatedModuleIdlingResource
|
8
|
+
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource
|
9
|
+
import com.wix.detox.reactnative.idlingresources.storage.AsyncStorageIdlingResource
|
10
|
+
import com.wix.detox.reactnative.idlingresources.timers.FabricTimersIdlingResource
|
11
|
+
import com.wix.detox.reactnative.idlingresources.uimodule.fabric.FabricUIManagerIdlingResources
|
12
|
+
import kotlinx.coroutines.Dispatchers
|
13
|
+
import kotlinx.coroutines.withContext
|
14
|
+
|
15
|
+
class FabricDetoxIdlingResourceFactoryStrategy(private val reactApplication: ReactApplication) :
|
16
|
+
DetoxIdlingResourceFactoryStrategy {
|
17
|
+
override suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource> =
|
18
|
+
withContext(Dispatchers.Main) {
|
19
|
+
val reactContext = reactApplication.getCurrentReactContextSafe()
|
20
|
+
|
21
|
+
val result = mutableMapOf(
|
22
|
+
IdlingResourcesName.UI to FabricUIManagerIdlingResources(reactContext),
|
23
|
+
IdlingResourcesName.Animations to AnimatedModuleIdlingResource(reactContext),
|
24
|
+
IdlingResourcesName.Timers to FabricTimersIdlingResource(reactContext),
|
25
|
+
IdlingResourcesName.Network to NetworkIdlingResource(reactContext),
|
26
|
+
IdlingResourcesName.AsyncStorage to AsyncStorageIdlingResource(reactContext)
|
27
|
+
)
|
28
|
+
|
29
|
+
return@withContext result
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.factory
|
2
|
+
|
3
|
+
import com.facebook.react.ReactApplication
|
4
|
+
import com.wix.detox.reactnative.getCurrentReactContext
|
5
|
+
import com.wix.detox.reactnative.getCurrentReactContextSafe
|
6
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
7
|
+
import com.wix.detox.reactnative.idlingresources.animations.AnimatedModuleIdlingResource
|
8
|
+
import com.wix.detox.reactnative.idlingresources.bridge.BridgeIdlingResource
|
9
|
+
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource
|
10
|
+
import com.wix.detox.reactnative.idlingresources.storage.AsyncStorageIdlingResource
|
11
|
+
import com.wix.detox.reactnative.idlingresources.timers.TimersIdlingResource
|
12
|
+
import com.wix.detox.reactnative.idlingresources.uimodule.paper.UIModuleIdlingResource
|
13
|
+
import kotlinx.coroutines.Dispatchers
|
14
|
+
import kotlinx.coroutines.withContext
|
15
|
+
|
16
|
+
class OldArchitectureDetoxIdlingResourceFactoryStrategy(private val reactApplication: ReactApplication) :
|
17
|
+
DetoxIdlingResourceFactoryStrategy {
|
18
|
+
override suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource> =
|
19
|
+
withContext(Dispatchers.Main) {
|
20
|
+
val reactContext = reactApplication.getCurrentReactContextSafe()
|
21
|
+
|
22
|
+
val result = mutableMapOf(
|
23
|
+
IdlingResourcesName.Timers to TimersIdlingResource(reactContext),
|
24
|
+
IdlingResourcesName.RNBridge to BridgeIdlingResource(reactContext),
|
25
|
+
IdlingResourcesName.UI to UIModuleIdlingResource(reactContext),
|
26
|
+
IdlingResourcesName.Animations to AnimatedModuleIdlingResource(reactContext),
|
27
|
+
IdlingResourcesName.Network to NetworkIdlingResource(reactContext),
|
28
|
+
IdlingResourcesName.AsyncStorage to AsyncStorageIdlingResource(reactContext)
|
29
|
+
)
|
30
|
+
|
31
|
+
return@withContext result
|
32
|
+
}
|
33
|
+
}
|
@@ -39,6 +39,11 @@ class NetworkIdlingResource(private val dispatcher: Dispatcher) : DetoxIdlingRes
|
|
39
39
|
Choreographer.getInstance().postFrameCallback(this)
|
40
40
|
}
|
41
41
|
|
42
|
+
override fun onUnregistered() {
|
43
|
+
super.onUnregistered()
|
44
|
+
Choreographer.getInstance().removeFrameCallback(this)
|
45
|
+
}
|
46
|
+
|
42
47
|
override fun doFrame(frameTimeNanos: Long) {
|
43
48
|
isIdleNow
|
44
49
|
}
|
@@ -7,22 +7,19 @@ import okhttp3.OkHttpClient
|
|
7
7
|
import org.joor.Reflect
|
8
8
|
import org.joor.ReflectException
|
9
9
|
|
10
|
+
|
11
|
+
private const val LOG_TAG = "RNNetworkingModuleRefl"
|
12
|
+
|
13
|
+
private const val FIELD_OKHTTP_CLIENT = "mClient"
|
14
|
+
|
10
15
|
internal class NetworkingModuleReflected(private val reactContext: ReactContext) {
|
11
16
|
fun getHttpClient(): OkHttpClient? {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}
|
17
|
+
val networkNativeModule = reactContext.getNativeModule(NetworkingModule::class.java)
|
18
|
+
try {
|
19
|
+
return Reflect.on(networkNativeModule).field(FIELD_OKHTTP_CLIENT).get()
|
20
|
+
} catch (e: ReflectException) {
|
21
|
+
Log.e(LOG_TAG, "Can't set up Networking Module listener", e)
|
22
|
+
return null
|
19
23
|
}
|
20
|
-
return null
|
21
|
-
}
|
22
|
-
|
23
|
-
companion object {
|
24
|
-
private const val LOG_TAG = "RNNetworkingModuleRefl"
|
25
|
-
|
26
|
-
private const val FIELD_OKHTTP_CLIENT = "mClient"
|
27
24
|
}
|
28
25
|
}
|
@@ -9,6 +9,8 @@ import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
|
9
9
|
import org.joor.Reflect
|
10
10
|
import java.util.concurrent.Executor
|
11
11
|
|
12
|
+
private const val LOG_TAG = "AsyncStorageIR"
|
13
|
+
|
12
14
|
private typealias SExecutorReflectedGenFnType = (executor: Executor) -> SerialExecutorReflected
|
13
15
|
|
14
16
|
private val defaultSExecutorReflectedGenFn: SExecutorReflectedGenFnType =
|
@@ -29,17 +31,19 @@ private class ModuleReflected(module: NativeModule, sexecutorReflectedGen: SExec
|
|
29
31
|
|
30
32
|
class AsyncStorageIdlingResource
|
31
33
|
@JvmOverloads constructor(
|
32
|
-
|
33
|
-
sexecutorReflectedGenFn: SExecutorReflectedGenFnType = defaultSExecutorReflectedGenFn
|
34
|
+
private val reactContext: ReactContext,
|
35
|
+
private val sexecutorReflectedGenFn: SExecutorReflectedGenFnType = defaultSExecutorReflectedGenFn,
|
36
|
+
private val rnHelpers: RNHelpers = RNHelpers()
|
34
37
|
) : DetoxIdlingResource() {
|
35
38
|
|
36
39
|
val logTag: String
|
37
40
|
get() = LOG_TAG
|
38
41
|
|
39
|
-
private val moduleReflected =
|
42
|
+
private val moduleReflected: ModuleReflected? = null
|
40
43
|
private var idleCheckTask: Runnable? = null
|
41
44
|
private val idleCheckTaskImpl = Runnable {
|
42
|
-
|
45
|
+
val module = getModuleReflected() ?: return@Runnable
|
46
|
+
with(module.sexecutor) {
|
43
47
|
synchronized(executor()) {
|
44
48
|
if (hasPendingTasks()) {
|
45
49
|
executeTask(idleCheckTask!!)
|
@@ -49,19 +53,36 @@ class AsyncStorageIdlingResource
|
|
49
53
|
}
|
50
54
|
}
|
51
55
|
}
|
56
|
+
|
52
57
|
}
|
53
58
|
|
54
59
|
override fun getName(): String = javaClass.name
|
55
60
|
override fun getDebugName() = "io"
|
56
61
|
override fun getBusyHint(): Map<String, Any>? = null
|
57
62
|
|
63
|
+
private fun getModuleReflected(): ModuleReflected? {
|
64
|
+
|
65
|
+
fun className(): String {
|
66
|
+
val packageName = "com.reactnativecommunity.asyncstorage"
|
67
|
+
return "$packageName.AsyncStorageModule"
|
68
|
+
}
|
69
|
+
|
70
|
+
if (moduleReflected != null) {
|
71
|
+
return moduleReflected
|
72
|
+
}
|
73
|
+
|
74
|
+
val nativeModule = rnHelpers.getNativeModule(reactContext, className()) ?: return null
|
75
|
+
return ModuleReflected(nativeModule, sexecutorReflectedGenFn)
|
76
|
+
}
|
58
77
|
|
59
|
-
private fun checkIdleInternal(): Boolean
|
60
|
-
|
78
|
+
private fun checkIdleInternal(): Boolean {
|
79
|
+
val module = getModuleReflected() ?: return true
|
80
|
+
return with(module.sexecutor) {
|
61
81
|
synchronized(executor()) {
|
62
82
|
!hasActiveTask() && !hasPendingTasks()
|
63
83
|
}
|
64
84
|
}
|
85
|
+
}
|
65
86
|
|
66
87
|
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
67
88
|
super.registerIdleTransitionCallback(callback)
|
@@ -76,8 +97,9 @@ class AsyncStorageIdlingResource
|
|
76
97
|
}
|
77
98
|
}
|
78
99
|
|
79
|
-
private fun enqueueIdleCheckTask()
|
80
|
-
|
100
|
+
private fun enqueueIdleCheckTask() {
|
101
|
+
val module = getModuleReflected() ?: return
|
102
|
+
with(module.sexecutor) {
|
81
103
|
synchronized(executor()) {
|
82
104
|
if (idleCheckTask == null) {
|
83
105
|
initIdleCheckTask()
|
@@ -85,6 +107,7 @@ class AsyncStorageIdlingResource
|
|
85
107
|
}
|
86
108
|
}
|
87
109
|
}
|
110
|
+
}
|
88
111
|
|
89
112
|
private fun initIdleCheckTask() {
|
90
113
|
idleCheckTask = idleCheckTaskImpl
|
@@ -93,25 +116,4 @@ class AsyncStorageIdlingResource
|
|
93
116
|
private fun clearIdleCheckTask() {
|
94
117
|
idleCheckTask = null
|
95
118
|
}
|
96
|
-
|
97
|
-
companion object {
|
98
|
-
private const val LOG_TAG = "AsyncStorageIR"
|
99
|
-
|
100
|
-
fun createIfNeeded(reactContext: ReactContext): AsyncStorageIdlingResource? {
|
101
|
-
Log.d(LOG_TAG, "Checking whether a custom IR for Async-Storage is required...")
|
102
|
-
|
103
|
-
return RNHelpers.getNativeModule(reactContext, className())?.let { module ->
|
104
|
-
Log.d(LOG_TAG, "IR for Async-Storage is required!")
|
105
|
-
createInstance(module)
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
private fun className(): String {
|
110
|
-
val packageName = "com.reactnativecommunity.asyncstorage"
|
111
|
-
return "$packageName.AsyncStorageModule"
|
112
|
-
}
|
113
|
-
|
114
|
-
private fun createInstance(module: NativeModule) =
|
115
|
-
AsyncStorageIdlingResource(module)
|
116
|
-
}
|
117
119
|
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.timers
|
2
|
+
|
3
|
+
import android.view.Choreographer
|
4
|
+
import androidx.test.espresso.IdlingResource
|
5
|
+
import com.facebook.react.bridge.ReactContext
|
6
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
7
|
+
|
8
|
+
class FabricTimersIdlingResource(
|
9
|
+
private val reactContext: ReactContext,
|
10
|
+
private val getChoreographer: () -> Choreographer = { Choreographer.getInstance() }
|
11
|
+
) : DetoxIdlingResource(), Choreographer.FrameCallback {
|
12
|
+
|
13
|
+
override fun checkIdle(): Boolean {
|
14
|
+
val hasActiveTimers = JavaTimersReflected.hasActiveTimers(reactContext)
|
15
|
+
|
16
|
+
if (hasActiveTimers) {
|
17
|
+
getChoreographer().postFrameCallback(this@FabricTimersIdlingResource)
|
18
|
+
} else {
|
19
|
+
notifyIdle()
|
20
|
+
}
|
21
|
+
|
22
|
+
return !hasActiveTimers
|
23
|
+
}
|
24
|
+
|
25
|
+
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
26
|
+
super.registerIdleTransitionCallback(callback)
|
27
|
+
getChoreographer().postFrameCallback(this)
|
28
|
+
}
|
29
|
+
|
30
|
+
override fun onUnregistered() {
|
31
|
+
super.onUnregistered()
|
32
|
+
getChoreographer().removeFrameCallback(this)
|
33
|
+
}
|
34
|
+
|
35
|
+
override fun getDebugName(): String {
|
36
|
+
return "timers"
|
37
|
+
}
|
38
|
+
|
39
|
+
override fun getBusyHint(): Map<String, Any>? = null
|
40
|
+
|
41
|
+
override fun getName(): String {
|
42
|
+
return FabricTimersIdlingResource::class.java.name
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
override fun doFrame(frameTimeNanos: Long) {
|
48
|
+
isIdleNow()
|
49
|
+
}
|
50
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.timers
|
2
|
+
|
3
|
+
import com.facebook.react.bridge.ReactContext
|
4
|
+
import com.facebook.react.modules.core.JavaTimerManager
|
5
|
+
import org.joor.Reflect
|
6
|
+
import kotlin.reflect.full.declaredFunctions
|
7
|
+
import kotlin.reflect.jvm.isAccessible
|
8
|
+
|
9
|
+
object JavaTimersReflected {
|
10
|
+
|
11
|
+
fun hasActiveTimers(reactContext: ReactContext): Boolean {
|
12
|
+
val timersManager = getTimersManager(reactContext)
|
13
|
+
val hasActiveTimersInRangeInstanceClass = timersManager::class
|
14
|
+
val method =
|
15
|
+
hasActiveTimersInRangeInstanceClass.declaredFunctions.first { it.name.contains("hasActiveTimersInRange") }
|
16
|
+
method.isAccessible = true
|
17
|
+
val hasActiveTimers: Boolean = method.call(timersManager, BUSY_WINDOW_THRESHOLD) as? Boolean ?: false
|
18
|
+
return hasActiveTimers
|
19
|
+
}
|
20
|
+
|
21
|
+
private fun getTimersManager(reactContext: ReactContext): JavaTimerManager {
|
22
|
+
val reactHost = Reflect.on(reactContext).field("mReactHost").get<Any>()
|
23
|
+
val reactInstance = Reflect.on(reactHost).field("mReactInstance").get<Any>()
|
24
|
+
return Reflect.on(reactInstance).field("mJavaTimerManager").get() as JavaTimerManager
|
25
|
+
}
|
26
|
+
}
|
@@ -7,7 +7,7 @@ import com.facebook.react.bridge.ReactContext
|
|
7
7
|
import com.facebook.react.modules.core.TimingModule
|
8
8
|
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
9
9
|
|
10
|
-
|
10
|
+
const val BUSY_WINDOW_THRESHOLD: Long = 1500L
|
11
11
|
|
12
12
|
class TimersIdlingResource @JvmOverloads constructor(
|
13
13
|
reactContext: ReactContext,
|
@@ -25,6 +25,11 @@ class TimersIdlingResource @JvmOverloads constructor(
|
|
25
25
|
getChoreographer().postFrameCallback(this)
|
26
26
|
}
|
27
27
|
|
28
|
+
override fun onUnregistered() {
|
29
|
+
super.onUnregistered()
|
30
|
+
getChoreographer().removeFrameCallback(this)
|
31
|
+
}
|
32
|
+
|
28
33
|
@SuppressLint("VisibleForTests")
|
29
34
|
override fun checkIdle(): Boolean {
|
30
35
|
val isIdle = !timingModule.hasActiveTimersInRange(BUSY_WINDOW_THRESHOLD)
|
@@ -41,8 +46,4 @@ class TimersIdlingResource @JvmOverloads constructor(
|
|
41
46
|
override fun doFrame(frameTimeNanos: Long) {
|
42
47
|
isIdleNow
|
43
48
|
}
|
44
|
-
|
45
|
-
companion object {
|
46
|
-
internal const val LOG_TAG = "TimersIdlingResource"
|
47
|
-
}
|
48
49
|
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule.fabric
|
2
|
+
|
3
|
+
import android.view.Choreographer
|
4
|
+
import androidx.test.espresso.IdlingResource
|
5
|
+
import com.facebook.react.bridge.ReactContext
|
6
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
7
|
+
import com.facebook.react.uimanager.common.UIManagerType
|
8
|
+
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
9
|
+
import org.joor.Reflect
|
10
|
+
import java.util.concurrent.ConcurrentLinkedQueue
|
11
|
+
|
12
|
+
|
13
|
+
class FabricUIManagerIdlingResources(
|
14
|
+
private val reactContext: ReactContext
|
15
|
+
) : DetoxIdlingResource(), Choreographer.FrameCallback {
|
16
|
+
|
17
|
+
override fun checkIdle(): Boolean {
|
18
|
+
return if (getViewCommandMountItemsSize() == 0 && getMountItemsSize() == 0) {
|
19
|
+
notifyIdle()
|
20
|
+
true
|
21
|
+
} else {
|
22
|
+
Choreographer.getInstance().postFrameCallback(this)
|
23
|
+
false
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
28
|
+
super.registerIdleTransitionCallback(callback)
|
29
|
+
Choreographer.getInstance().postFrameCallback(this)
|
30
|
+
}
|
31
|
+
|
32
|
+
override fun onUnregistered() {
|
33
|
+
super.onUnregistered()
|
34
|
+
Choreographer.getInstance().removeFrameCallback(this)
|
35
|
+
}
|
36
|
+
|
37
|
+
override fun getDebugName(): String {
|
38
|
+
return "Fabric UI"
|
39
|
+
}
|
40
|
+
|
41
|
+
override fun getBusyHint(): Map<String, Any> {
|
42
|
+
return mapOf("mountItems" to getMountItemsSize(), "viewCommandMountItems" to getViewCommandMountItemsSize())
|
43
|
+
}
|
44
|
+
|
45
|
+
override fun getName() = FabricUIManagerIdlingResources::class.java.name
|
46
|
+
|
47
|
+
override fun doFrame(frameTimeNanos: Long) {
|
48
|
+
isIdleNow()
|
49
|
+
}
|
50
|
+
|
51
|
+
private fun getMountItemsSize(): Int {
|
52
|
+
val mountItemDispatcher = getMountItemDispatcher()
|
53
|
+
val mountItems = Reflect.on(mountItemDispatcher).field("mMountItems").get<ConcurrentLinkedQueue<*>>()
|
54
|
+
return mountItems.size
|
55
|
+
}
|
56
|
+
|
57
|
+
private fun getMountItemDispatcher(): Any {
|
58
|
+
val fabricUIManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC)
|
59
|
+
val mountItemDispatcher = Reflect.on(fabricUIManager).field("mMountItemDispatcher").get<Any>()
|
60
|
+
return mountItemDispatcher
|
61
|
+
}
|
62
|
+
|
63
|
+
private fun getViewCommandMountItemsSize(): Int {
|
64
|
+
val mountItemDispatcher = getMountItemDispatcher()
|
65
|
+
val viewCommandMountItems =
|
66
|
+
Reflect.on(mountItemDispatcher).field("mViewCommandMountItems").get<ConcurrentLinkedQueue<*>>()
|
67
|
+
return viewCommandMountItems.size
|
68
|
+
}
|
69
|
+
|
70
|
+
}
|
@@ -1,15 +1,17 @@
|
|
1
|
-
package com.wix.detox.reactnative.idlingresources.uimodule
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule.paper
|
2
2
|
|
3
3
|
import android.util.Log
|
4
4
|
import android.view.View
|
5
5
|
import com.facebook.react.uimanager.NativeViewHierarchyManager
|
6
6
|
import com.facebook.react.uimanager.UIViewOperationQueue
|
7
|
-
import com.wix.detox.common.DetoxLog
|
7
|
+
import com.wix.detox.common.DetoxLog
|
8
8
|
import org.joor.Reflect
|
9
9
|
import org.joor.ReflectException
|
10
10
|
|
11
11
|
private const val FIELD_NATIVE_HIERARCHY_MANAGER = "mNativeViewHierarchyManager"
|
12
12
|
|
13
|
+
|
14
|
+
|
13
15
|
class NativeHierarchyManagerReflected(uIViewOperationQueueInstance: UIViewOperationQueue) {
|
14
16
|
private val reflected = Reflect.on(uIViewOperationQueueInstance)
|
15
17
|
|
@@ -21,7 +23,7 @@ class NativeHierarchyManagerReflected(uIViewOperationQueueInstance: UIViewOperat
|
|
21
23
|
return try {
|
22
24
|
reflected.field(FIELD_NATIVE_HIERARCHY_MANAGER).get<NativeViewHierarchyManager>()
|
23
25
|
} catch(e: ReflectException) {
|
24
|
-
Log.e(LOG_TAG, "failed to get $FIELD_NATIVE_HIERARCHY_MANAGER ", e.cause)
|
26
|
+
Log.e(DetoxLog.LOG_TAG, "failed to get $FIELD_NATIVE_HIERARCHY_MANAGER ", e.cause)
|
25
27
|
null
|
26
28
|
}
|
27
29
|
}
|
@@ -1,9 +1,9 @@
|
|
1
|
-
package com.wix.detox.reactnative.idlingresources.uimodule
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule.paper
|
2
2
|
|
3
3
|
import android.util.Log
|
4
4
|
import com.facebook.react.bridge.ReactContext
|
5
5
|
import com.facebook.react.uimanager.UIViewOperationQueue
|
6
|
-
import com.wix.detox.common.DetoxLog
|
6
|
+
import com.wix.detox.common.DetoxLog
|
7
7
|
import org.joor.Reflect
|
8
8
|
|
9
9
|
private const val CLASS_UI_MANAGER_MODULE = "com.facebook.react.uimanager.UIManagerModule"
|
@@ -16,6 +16,8 @@ private const val FIELD_DISPATCH_RUNNABLES_LOCK = "mDispatchRunnablesLock"
|
|
16
16
|
private const val FIELD_NON_BATCHED_OPS = "mNonBatchedOperations"
|
17
17
|
private const val FIELD_NON_BATCHED_OPS_LOCK = "mNonBatchedOperationsLock"
|
18
18
|
|
19
|
+
|
20
|
+
|
19
21
|
class UIManagerModuleReflected(private val reactContext: ReactContext) {
|
20
22
|
|
21
23
|
fun isRunnablesListEmpty(): Boolean =
|
@@ -56,7 +58,7 @@ class UIManagerModuleReflected(private val reactContext: ReactContext) {
|
|
56
58
|
.field(FIELD_UI_OPERATION_QUEUE)
|
57
59
|
.get()
|
58
60
|
} catch (e: Exception) {
|
59
|
-
Log.e(LOG_TAG, "failed to get $CLASS_UI_MANAGER_MODULE instance ", e)
|
61
|
+
Log.e(DetoxLog.LOG_TAG, "failed to get $CLASS_UI_MANAGER_MODULE instance ", e)
|
60
62
|
null
|
61
63
|
}
|
62
64
|
}
|
@@ -1,8 +1,8 @@
|
|
1
|
-
package com.wix.detox.reactnative.idlingresources.uimodule
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule.paper
|
2
2
|
|
3
3
|
import android.util.Log
|
4
4
|
import android.view.Choreographer
|
5
|
-
import androidx.test.espresso.IdlingResource
|
5
|
+
import androidx.test.espresso.IdlingResource
|
6
6
|
import com.facebook.react.bridge.ReactContext
|
7
7
|
import com.wix.detox.reactnative.helpers.RNHelpers
|
8
8
|
import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
|
@@ -30,7 +30,10 @@ class UIModuleIdlingResource(private val reactContext: ReactContext)
|
|
30
30
|
return false
|
31
31
|
}
|
32
32
|
|
33
|
-
if (RNHelpers.getNativeModule(
|
33
|
+
if (RNHelpers().getNativeModule(
|
34
|
+
reactContext,
|
35
|
+
"com.facebook.react.uimanager.UIManagerModule"
|
36
|
+
) == null) {
|
34
37
|
notifyIdle()
|
35
38
|
return true
|
36
39
|
}
|
@@ -54,11 +57,16 @@ class UIModuleIdlingResource(private val reactContext: ReactContext)
|
|
54
57
|
return true
|
55
58
|
}
|
56
59
|
|
57
|
-
override fun registerIdleTransitionCallback(callback: ResourceCallback?) {
|
60
|
+
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
58
61
|
super.registerIdleTransitionCallback(callback)
|
59
62
|
Choreographer.getInstance().postFrameCallback(this)
|
60
63
|
}
|
61
64
|
|
65
|
+
override fun onUnregistered() {
|
66
|
+
super.onUnregistered()
|
67
|
+
Choreographer.getInstance().removeFrameCallback(this)
|
68
|
+
}
|
69
|
+
|
62
70
|
override fun doFrame(frameTimeNanos: Long) {
|
63
71
|
isIdleNow
|
64
72
|
}
|
@@ -1,8 +1,8 @@
|
|
1
|
-
package com.wix.detox.reactnative.idlingresources.uimodule
|
1
|
+
package com.wix.detox.reactnative.idlingresources.uimodule.paper
|
2
2
|
|
3
3
|
import android.util.Log
|
4
4
|
import com.facebook.react.uimanager.UIViewOperationQueue
|
5
|
-
import com.wix.detox.common.DetoxLog
|
5
|
+
import com.wix.detox.common.DetoxLog
|
6
6
|
import org.joor.Reflect
|
7
7
|
import org.joor.ReflectException
|
8
8
|
|
@@ -21,7 +21,7 @@ class ViewCommandOpsQueueReflected(uiViewOperationQueueInstance: UIViewOperation
|
|
21
21
|
try {
|
22
22
|
instance.field(FIELD_VIEW_COMMAND_OPERATIONS).get<Collection<Any>>()
|
23
23
|
} catch(e: ReflectException) {
|
24
|
-
Log.e(LOG_TAG, "could not get reflected field mViewCommandOperations ", e)
|
24
|
+
Log.e(DetoxLog.LOG_TAG, "could not get reflected field mViewCommandOperations ", e)
|
25
25
|
null
|
26
26
|
}
|
27
27
|
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
package com.wix.detox.reactnative.reloader
|
2
|
+
|
3
|
+
import android.app.Instrumentation
|
4
|
+
import com.facebook.react.ReactApplication
|
5
|
+
|
6
|
+
interface ReactNativeReLoader {
|
7
|
+
fun reloadInBackground()
|
8
|
+
}
|
9
|
+
|
10
|
+
class OldArchReactNativeReLoader(
|
11
|
+
private val instrumentation: Instrumentation,
|
12
|
+
private val rnApplication: ReactApplication
|
13
|
+
) : ReactNativeReLoader {
|
14
|
+
|
15
|
+
override fun reloadInBackground() {
|
16
|
+
val rnInstanceManager = rnApplication.reactNativeHost.reactInstanceManager
|
17
|
+
instrumentation.runOnMainSync {
|
18
|
+
rnInstanceManager.recreateReactContextInBackground()
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
class NewArchitectureNativeReLoader(
|
24
|
+
private val instrumentation: Instrumentation,
|
25
|
+
private val rnApplication: ReactApplication
|
26
|
+
) : ReactNativeReLoader {
|
27
|
+
override fun reloadInBackground() {
|
28
|
+
val reactHost = rnApplication.reactHost ?: throw IllegalStateException("ReactHost is null. Check implementation of you Application class")
|
29
|
+
|
30
|
+
instrumentation.runOnMainSync {
|
31
|
+
reactHost.reload("Detox")
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
package/android/detox/src/full/java/com/wix/detox/reactnative/reloader/ReactNativeReloaderFactory.kt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
package com.wix.detox.reactnative.reloader
|
2
|
+
|
3
|
+
import android.app.Instrumentation
|
4
|
+
import com.facebook.react.ReactApplication
|
5
|
+
import com.wix.detox.reactnative.isFabricEnabled
|
6
|
+
|
7
|
+
class ReactNativeReloaderFactory(
|
8
|
+
private val instrumentation: Instrumentation,
|
9
|
+
private val rnApplication: ReactApplication
|
10
|
+
) {
|
11
|
+
|
12
|
+
fun create(): ReactNativeReLoader {
|
13
|
+
return when {
|
14
|
+
isFabricEnabled() -> NewArchitectureNativeReLoader(instrumentation, rnApplication)
|
15
|
+
else -> OldArchReactNativeReLoader(instrumentation, rnApplication)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|