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.
Files changed (71) hide show
  1. 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
  2. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar +0 -0
  7. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.aar.sha512 +1 -0
  11. 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
  12. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.33.0-prerelease.0/detox-20.33.0-prerelease.0.pom.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  17. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  18. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  19. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  20. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  21. package/Detox-ios-framework.tbz +0 -0
  22. package/Detox-ios-src.tbz +0 -0
  23. package/Detox-ios-xcuitest.tbz +0 -0
  24. package/android/detox/build.gradle +6 -1
  25. package/android/detox/proguard-rules-app.pro +12 -0
  26. package/android/detox/src/full/java/com/wix/detox/DetoxMain.kt +4 -3
  27. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactApplicationExt.kt +34 -0
  28. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +22 -27
  29. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeLoadingMonitor.kt +51 -71
  30. package/android/detox/src/full/java/com/wix/detox/reactnative/helpers/RNHelpers.kt +1 -1
  31. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +4 -2
  32. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +17 -13
  33. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +5 -2
  34. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +9 -20
  35. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactoryStrategy.kt +7 -0
  36. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/FabricDetoxIdlingResourceFactoryStrategy.kt +31 -0
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +1 -1
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/OldArchitectureDetoxIdlingResourceFactoryStrategy.kt +33 -0
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +5 -0
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkingModuleReflected.kt +11 -14
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/storage/AsyncStorageIdlingResource.kt +31 -29
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/FabricTimersIdlingResource.kt +50 -0
  43. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/JavaTimersReflected.kt +26 -0
  44. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +6 -5
  45. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/fabric/FabricUIManagerIdlingResources.kt +70 -0
  46. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{DispatchCommandOperationReflected.kt → paper/DispatchCommandOperationReflected.kt} +1 -1
  47. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{NativeHierarchyManagerReflected.kt → paper/NativeHierarchyManagerReflected.kt} +5 -3
  48. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{UIManagerModuleReflected.kt → paper/UIManagerModuleReflected.kt} +5 -3
  49. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{UIModuleIdlingResource.kt → paper/UIModuleIdlingResource.kt} +12 -4
  50. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/{ViewCommandOpsQueueReflected.kt → paper/ViewCommandOpsQueueReflected.kt} +3 -3
  51. package/android/detox/src/full/java/com/wix/detox/reactnative/reloader/ReactNativeReloader.kt +34 -0
  52. package/android/detox/src/full/java/com/wix/detox/reactnative/reloader/ReactNativeReloaderFactory.kt +18 -0
  53. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +9 -2
  54. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +9 -3
  55. package/package.json +2 -2
  56. package/scripts/updateGradle.js +37 -0
  57. package/src/DetoxWorker.js +1 -2
  58. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.md5 +0 -1
  59. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha1 +0 -1
  60. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha256 +0 -1
  61. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0-sources.jar.sha512 +0 -1
  62. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar +0 -0
  63. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.md5 +0 -1
  64. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha1 +0 -1
  65. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha256 +0 -1
  66. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.aar.sha512 +0 -1
  67. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.md5 +0 -1
  68. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha1 +0 -1
  69. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha256 +0 -1
  70. package/Detox-android/com/wix/detox/20.32.0/detox-20.32.0.pom.sha512 +0 -1
  71. 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.bridge.ReactContext
3
+ import com.facebook.react.ReactApplication
4
4
  import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
5
- import com.wix.detox.reactnative.idlingresources.animations.AnimatedModuleIdlingResource
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
- val asyncStorageIdlingResource = AsyncStorageIdlingResource.createIfNeeded(reactContext)
25
- if (asyncStorageIdlingResource != null) {
26
- result[IdlingResourcesName.AsyncStorage] = asyncStorageIdlingResource
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 result
18
+ return@withContext strategy.create()
30
19
  }
31
20
  }
32
21
 
@@ -0,0 +1,7 @@
1
+ package com.wix.detox.reactnative.idlingresources.factory
2
+
3
+ import com.wix.detox.reactnative.idlingresources.DetoxIdlingResource
4
+
5
+ interface DetoxIdlingResourceFactoryStrategy {
6
+ suspend fun create(): Map<IdlingResourcesName, DetoxIdlingResource>
7
+ }
@@ -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
+ }
@@ -4,7 +4,7 @@ enum class IdlingResourcesName {
4
4
  Timers,
5
5
  AsyncStorage,
6
6
  RNBridge,
7
- UIModule,
7
+ UI,
8
8
  Animations,
9
9
  Network
10
10
  }
@@ -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
- if (reactContext.hasNativeModule(NetworkingModule::class.java)) {
13
- val networkNativeModule = reactContext.getNativeModule(NetworkingModule::class.java)
14
- try {
15
- return Reflect.on(networkNativeModule).field(FIELD_OKHTTP_CLIENT).get()
16
- } catch (e: ReflectException) {
17
- Log.e(LOG_TAG, "Can't set up Networking Module listener", e)
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
- module: NativeModule,
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 = ModuleReflected(module, sexecutorReflectedGenFn)
42
+ private val moduleReflected: ModuleReflected? = null
40
43
  private var idleCheckTask: Runnable? = null
41
44
  private val idleCheckTaskImpl = Runnable {
42
- with(moduleReflected.sexecutor) {
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
- with(moduleReflected.sexecutor) {
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
- with(moduleReflected.sexecutor) {
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
- private const val BUSY_WINDOW_THRESHOLD = 1500L
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,4 +1,4 @@
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.wix.detox.common.DetoxLog
@@ -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.Companion.LOG_TAG
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.Companion.LOG_TAG
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.ResourceCallback
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(reactContext, "com.facebook.react.uimanager.UIManagerModule") == null) {
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.Companion.LOG_TAG
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
+ }
@@ -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
+ }