detox 20.27.7-smoke.0 → 20.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. package/Detox-android/com/wix/detox/{20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar → 20.30.0/detox-20.30.0-sources.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar +0 -0
  7. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.27.7-smoke.0/detox-20.27.7-smoke.0.pom → 20.30.0/detox-20.30.0.pom} +2 -2
  12. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.30.0/detox-20.30.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/build.gradle +5 -5
  25. package/android/detox/proguard-rules-app.pro +3 -0
  26. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +54 -3
  27. package/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java +11 -0
  28. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt +2 -2
  29. package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxWebAtomMatcher.java +4 -7
  30. package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +0 -5
  31. package/android/detox/src/full/java/com/wix/detox/espresso/web/WebViewElement.java +33 -8
  32. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +6 -11
  33. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeInfo.kt +4 -11
  34. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +42 -0
  35. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +145 -0
  36. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +61 -0
  37. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/bridge/BridgeIdlingResource.kt +72 -0
  38. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +32 -0
  39. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +10 -0
  40. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/LooperName.kt +6 -0
  41. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/looper/MQThreadsReflector.kt +47 -0
  42. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +105 -0
  43. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{NetworkingModuleReflected.kt → network/NetworkingModuleReflected.kt} +1 -1
  44. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{AsyncStorageIdlingResource.kt → storage/AsyncStorageIdlingResource.kt} +33 -35
  45. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{SerialExecutorReflected.kt → storage/SerialExecutorReflected.kt} +1 -1
  46. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +21 -19
  47. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +19 -27
  48. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +5 -17
  49. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +248 -0
  50. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -1
  51. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/SerialExecutorReflectedSpec.kt +1 -0
  52. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +212 -0
  53. package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  54. package/android/rninfo.gradle +31 -24
  55. package/android/settings.gradle +11 -6
  56. package/detox.d.ts +39 -0
  57. package/package.json +11 -8
  58. package/scripts/postinstall.js +2 -2
  59. package/scripts/updateGradle.js +41 -8
  60. package/src/DetoxWorker.js +11 -6
  61. package/src/android/espressoapi/EspressoDetox.js +83 -0
  62. package/src/copilot/DetoxCopilot.js +3 -15
  63. package/src/copilot/detoxCopilotFrameworkDriver.js +27 -15
  64. package/src/devices/runtime/RuntimeDevice.js +11 -0
  65. package/src/devices/runtime/drivers/DeviceDriverBase.js +8 -0
  66. package/src/devices/runtime/drivers/android/AndroidDriver.js +16 -0
  67. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +35 -0
  68. package/src/utils/assertArgument.js +9 -0
  69. package/src/utils/invocationTraceDescriptions.js +1 -0
  70. package/src/utils/mapDeviceLongPressArguments.js +56 -0
  71. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.md5 +0 -1
  72. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha1 +0 -1
  73. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha256 +0 -1
  74. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha512 +0 -1
  75. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar +0 -0
  76. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.md5 +0 -1
  77. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha1 +0 -1
  78. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha256 +0 -1
  79. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha512 +0 -1
  80. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.md5 +0 -1
  81. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha1 +0 -1
  82. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha256 +0 -1
  83. package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha512 +0 -1
  84. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar +0 -0
  85. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.md5 +0 -1
  86. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha1 +0 -1
  87. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha256 +0 -1
  88. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha512 +0 -1
  89. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar +0 -0
  90. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.md5 +0 -1
  91. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha1 +0 -1
  92. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha256 +0 -1
  93. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha512 +0 -1
  94. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom +0 -100
  95. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.md5 +0 -1
  96. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha1 +0 -1
  97. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha256 +0 -1
  98. package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha512 +0 -1
  99. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +0 -13
  100. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +0 -1
  101. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +0 -1
  102. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +0 -1
  103. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +0 -1
  104. package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxDriverAtoms.java +0 -642
  105. package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +0 -229
  106. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +0 -215
  107. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +0 -94
  108. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +0 -29
  109. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +0 -134
  110. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +0 -23
  111. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +0 -16
  112. package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +0 -71
  113. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +0 -227
  114. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +0 -47
  115. package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceSpec.kt +0 -189
@@ -1,229 +0,0 @@
1
- package com.wix.detox.reactnative
2
-
3
- import android.os.Looper
4
- import android.util.Log
5
- import androidx.test.espresso.Espresso
6
- import androidx.test.espresso.IdlingRegistry
7
- import androidx.test.espresso.base.IdlingResourceRegistry
8
- import com.facebook.react.bridge.ReactContext
9
- import com.wix.detox.LaunchArgs
10
- import com.wix.detox.reactnative.idlingresources.*
11
- import com.wix.detox.reactnative.idlingresources.timers.TimersIdlingResource
12
- import com.wix.detox.reactnative.idlingresources.timers.getInterrogationStrategy
13
- import com.wix.detox.reactnative.idlingresources.uimodule.UIModuleIdlingResource
14
- import org.joor.Reflect
15
- import org.joor.ReflectException
16
-
17
- private const val LOG_TAG = "DetoxRNIdleRes"
18
-
19
- private class MQThreadsReflector(private val reactContext: ReactContext) {
20
- fun getQueue(queueName: String): MQThreadReflected? {
21
- try {
22
- val queue = Reflect.on(reactContext).field(queueName).get() as Any?
23
- return MQThreadReflected(queue, queueName)
24
- } catch (e: ReflectException) {
25
- Log.e(LOG_TAG, "Could not find queue: $queueName", e)
26
- }
27
- return null
28
- }
29
- }
30
-
31
- private class MQThreadReflected(private val queue: Any?, private val queueName: String) {
32
- fun getLooper(): Looper? {
33
- try {
34
- if (queue != null) {
35
- return Reflect.on(queue).call(METHOD_GET_LOOPER).get()
36
- }
37
- } catch (e: ReflectException) {
38
- Log.e(LOG_TAG, "Could not find looper for queue: $queueName", e)
39
- }
40
- return null
41
- }
42
-
43
- companion object {
44
- const val METHOD_GET_LOOPER = "getLooper"
45
- }
46
- }
47
-
48
- class ReactNativeIdlingResources constructor(
49
- private val reactContext: ReactContext,
50
- private var launchArgs: LaunchArgs,
51
- internal var networkSyncEnabled: Boolean = true
52
- ) {
53
- companion object {
54
- private const val FIELD_NATIVE_MODULES_MSG_QUEUE = "mNativeModulesMessageQueueThread"
55
- private const val FIELD_JS_MSG_QUEUE = "mJSMessageQueueThread"
56
- }
57
-
58
- private var timersIdlingResource: TimersIdlingResource? = null
59
- private var asyncStorageIdlingResource: AsyncStorageIdlingResource? = null
60
- private var legacyAsyncStorageIdlingResource: AsyncStorageIdlingResource? = null
61
- private var rnBridgeIdlingResource: BridgeIdlingResource? = null
62
- private var uiModuleIdlingResource: UIModuleIdlingResource? = null
63
- private var animIdlingResource: AnimatedModuleIdlingResource? = null
64
- private var networkIdlingResource: NetworkIdlingResource? = null
65
-
66
- fun registerAll() {
67
- Log.i(LOG_TAG, "Setting up Espresso Idling Resources for React Native")
68
- unregisterAll()
69
-
70
- setupUrlBlacklist()
71
- setupMQThreadsInterrogators()
72
- syncIdlingResources()
73
- setupCustomRNIdlingResources()
74
- syncIdlingResources()
75
- }
76
-
77
- fun unregisterAll() {
78
- unregisterMQThreadsInterrogators()
79
- unregisterCustomRNIdlingResources()
80
- }
81
-
82
- fun setNetworkSynchronization(enable: Boolean) {
83
- if (networkSyncEnabled == enable) {
84
- return
85
- }
86
-
87
- if (enable) {
88
- setupNetworkIdlingResource()
89
- } else {
90
- removeNetworkIdlingResource()
91
- }
92
- networkSyncEnabled = enable
93
- }
94
-
95
- fun pauseNetworkSynchronization() = networkIdlingResource?.pause()
96
- fun resumeNetworkSynchronization() {
97
- if (networkSyncEnabled) {
98
- networkIdlingResource?.resume()
99
- }
100
- }
101
-
102
- fun pauseRNTimersIdlingResource() = timersIdlingResource?.pause()
103
- fun resumeRNTimersIdlingResource() = timersIdlingResource?.resume()
104
- fun pauseUIIdlingResource() = uiModuleIdlingResource?.pause()
105
- fun resumeUIIdlingResource() = uiModuleIdlingResource?.resume()
106
-
107
- fun setBlacklistUrls(urlList: String) {
108
- setIldingResourceBlacklist(urlList)
109
- }
110
-
111
- private fun setIldingResourceBlacklist(urlList: String) {
112
- val urlArray = toFormattedUrlArray(urlList)
113
- NetworkIdlingResource.setURLBlacklist(urlArray)
114
- }
115
-
116
- private fun setupMQThreadsInterrogators() {
117
- if (IdlingRegistry.getInstance().loopers.isEmpty()) {
118
- val mqThreadsReflector = MQThreadsReflector(reactContext)
119
- val mqJS = mqThreadsReflector.getQueue(FIELD_JS_MSG_QUEUE)?.getLooper()
120
- val mqNativeModules =
121
- mqThreadsReflector.getQueue(FIELD_NATIVE_MODULES_MSG_QUEUE)?.getLooper()
122
-
123
- IdlingRegistry.getInstance().apply {
124
- registerLooperAsIdlingResource(mqJS)
125
- registerLooperAsIdlingResource(mqNativeModules)
126
- }
127
- }
128
- }
129
-
130
- private fun setupUrlBlacklist() {
131
- if (launchArgs.hasURLBlacklist()) {
132
- val blacklistUrls = launchArgs.urlBlacklist
133
- setIldingResourceBlacklist(blacklistUrls)
134
- }
135
- }
136
-
137
- private fun setupCustomRNIdlingResources() {
138
- rnBridgeIdlingResource = BridgeIdlingResource(reactContext)
139
- timersIdlingResource = TimersIdlingResource(getInterrogationStrategy(reactContext)!!)
140
- uiModuleIdlingResource = UIModuleIdlingResource(reactContext)
141
- animIdlingResource = AnimatedModuleIdlingResource(reactContext)
142
-
143
- IdlingRegistry.getInstance()
144
- .register(
145
- timersIdlingResource,
146
- rnBridgeIdlingResource,
147
- uiModuleIdlingResource,
148
- animIdlingResource)
149
-
150
- if (networkSyncEnabled) {
151
- setupNetworkIdlingResource()
152
- }
153
- setupAsyncStorageIdlingResource()
154
- }
155
-
156
- private fun syncIdlingResources() {
157
- IdlingRegistry.getInstance().apply {
158
- val irr: IdlingResourceRegistry =
159
- Reflect.on(Espresso::class.java).field("baseRegistry").get()
160
- irr.sync(this.resources, this.loopers)
161
- }
162
- }
163
-
164
- private fun unregisterMQThreadsInterrogators() {
165
- val idlingResourceInstance = IdlingRegistry.getInstance()
166
- val loopersField = Reflect.on(idlingResourceInstance).field("loopers")
167
- loopersField.get<MutableSet<Any>>().clear()
168
- }
169
-
170
- private fun unregisterCustomRNIdlingResources() {
171
- IdlingRegistry.getInstance()
172
- .unregister(
173
- timersIdlingResource,
174
- rnBridgeIdlingResource,
175
- uiModuleIdlingResource,
176
- animIdlingResource
177
- )
178
- rnBridgeIdlingResource?.onDetach()
179
-
180
- removeNetworkIdlingResource()
181
- removeAsyncStorageIdlingResource()
182
- }
183
-
184
- private fun setupAsyncStorageIdlingResource() {
185
- asyncStorageIdlingResource =
186
- AsyncStorageIdlingResource.createIfNeeded(reactContext, false)?.also {
187
- IdlingRegistry.getInstance().register(it)
188
- }
189
-
190
- legacyAsyncStorageIdlingResource =
191
- AsyncStorageIdlingResource.createIfNeeded(reactContext, true)?.also {
192
- IdlingRegistry.getInstance().register(it)
193
- }
194
- }
195
-
196
- private fun removeAsyncStorageIdlingResource() {
197
- asyncStorageIdlingResource?.also {
198
- IdlingRegistry.getInstance().unregister(it)
199
- }
200
-
201
- legacyAsyncStorageIdlingResource?.also {
202
- IdlingRegistry.getInstance().unregister(it)
203
- }
204
- }
205
-
206
- private fun setupNetworkIdlingResource() {
207
- try {
208
- networkIdlingResource = NetworkIdlingResource(reactContext)
209
- IdlingRegistry.getInstance().register(networkIdlingResource)
210
- } catch (e: ReflectException) {
211
- Log.e(LOG_TAG, "Can't set up Networking Module listener", e)
212
- }
213
- }
214
-
215
- private fun removeNetworkIdlingResource() {
216
- networkIdlingResource?.let {
217
- it.pause()
218
- IdlingRegistry.getInstance().unregister(it)
219
- networkIdlingResource = null
220
- }
221
- }
222
-
223
- private fun toFormattedUrlArray(urlList: String): List<String> {
224
- var formattedUrls = urlList
225
- formattedUrls = formattedUrls.replace(Regex("""[()"]"""), "")
226
- formattedUrls = formattedUrls.trim()
227
- return formattedUrls.split(',')
228
- }
229
- }
@@ -1,215 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
- import android.view.Choreographer;
5
-
6
- import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource;
7
- import com.wix.detox.reactnative.ReactNativeInfo;
8
-
9
- import org.joor.Reflect;
10
- import org.joor.ReflectException;
11
-
12
- import java.util.HashMap;
13
- import java.util.Map;
14
-
15
- import androidx.annotation.NonNull;
16
- import androidx.annotation.Nullable;
17
-
18
- /**
19
- * Created by simonracz on 25/08/2017.
20
- */
21
-
22
- /**
23
- * <p>
24
- * Espresso IdlingResource for React Native's Animated Module.
25
- * </p>
26
- * <p>
27
- * <p>
28
- * Hooks up to React Native internals to monitor the state of the animations.
29
- * </p>
30
- * <p>
31
- * This Idling Resource is inherently tied to the UI Module IR. It must be registered after
32
- * the UI Module IR. This order is not enforced now.
33
- *
34
- * @see <a href="https://github.com/facebook/react-native/blob/259eac8c30b536abddab7925f4c51f0bf7ced58d/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java#L143">AnimatedModule</a>
35
- */
36
- public class AnimatedModuleIdlingResource implements DescriptiveIdlingResource, Choreographer.FrameCallback {
37
- private static final String LOG_TAG = "Detox";
38
-
39
- private final static String CLASS_ANIMATED_MODULE = "com.facebook.react.animated.NativeAnimatedModule";
40
- private final static String METHOD_GET_NATIVE_MODULE = "getNativeModule";
41
- private final static String METHOD_HAS_NATIVE_MODULE = "hasNativeModule";
42
- private final static String METHOD_IS_EMPTY = "isEmpty";
43
-
44
- private final static String LOCK_OPERATIONS = "mOperationsCopyLock";
45
- private final static String FIELD_OPERATIONS = "mReadyOperations";
46
- private final static String FIELD_NODES_MANAGER = "mNodesManager";
47
-
48
- private final static String FIELD_ITERATIONS = "mIterations";
49
- private final static String FIELD_ACTIVE_ANIMATIONS = "mActiveAnimations";
50
- private final static String FIELD_UPDATED_NODES = "mUpdatedNodes";
51
- private final static String FIELD_CATALYST_INSTANCE = "mCatalystInstance";
52
-
53
- private final static String METHOD_SIZE = "size";
54
- private final static String METHOD_VALUE_AT = "valueAt";
55
-
56
- private final static String METHOD_HAS_ACTIVE_ANIMATIONS = "hasActiveAnimations";
57
-
58
- private final static Map<String, Object> busyHint = new HashMap<String, Object>() {{
59
- put("reason", "Animations running on screen");
60
- }};
61
-
62
- private ResourceCallback callback = null;
63
- private Object reactContext = null;
64
-
65
- public AnimatedModuleIdlingResource(@NonNull Object reactContext) {
66
- this.reactContext = reactContext;
67
- }
68
-
69
- @Override
70
- public String getName() {
71
- return AnimatedModuleIdlingResource.class.getName();
72
- }
73
-
74
- @NonNull
75
- @Override
76
- public String getDebugName() {
77
- return "ui";
78
- }
79
-
80
- @Nullable
81
- @Override
82
- public Map<String, Object> getBusyHint() {
83
- return busyHint;
84
- }
85
-
86
- @Override
87
- public boolean isIdleNow() {
88
- Class<?> animModuleClass = null;
89
- try {
90
- animModuleClass = Class.forName(CLASS_ANIMATED_MODULE);
91
- } catch (ClassNotFoundException e) {
92
- Log.e(LOG_TAG, "Animated Module is not on classpath.");
93
- if (callback != null) {
94
- callback.onTransitionToIdle();
95
- }
96
- return true;
97
- }
98
-
99
- try {
100
- // reactContext.hasActiveCatalystInstance() should be always true here
101
- // if called right after onReactContextInitialized(...)
102
- if (Reflect.on(reactContext).field(FIELD_CATALYST_INSTANCE).get() == null) {
103
- Log.e(LOG_TAG, "No active CatalystInstance. Should never see this.");
104
- return false;
105
- }
106
-
107
- if (!(boolean) Reflect.on(reactContext).call(METHOD_HAS_NATIVE_MODULE, animModuleClass).get()) {
108
- Log.e(LOG_TAG, "Can't find Animated Module.");
109
- if (callback != null) {
110
- callback.onTransitionToIdle();
111
- }
112
- return true;
113
- }
114
-
115
- if (ReactNativeInfo.rnVersion().getMinor() >= 51) {
116
- if(isIdleRN51(animModuleClass)) {
117
- return true;
118
- }
119
- } else {
120
- if (isIdleRNOld(animModuleClass)) {
121
- return true;
122
- }
123
- }
124
-
125
- Log.i(LOG_TAG, "AnimatedModule is busy.");
126
- Choreographer.getInstance().postFrameCallback(this);
127
- return false;
128
- } catch (ReflectException e) {
129
- Log.e(LOG_TAG, "Couldn't set up RN AnimatedModule listener, old RN version?");
130
- Log.e(LOG_TAG, "Can't set up RN AnimatedModule listener", e.getCause());
131
- }
132
-
133
- if (callback != null) {
134
- callback.onTransitionToIdle();
135
- }
136
- // Log.i(LOG_TAG, "AnimatedModule is idle.");
137
- return true;
138
- }
139
-
140
- private boolean isIdleRN51(Object animModuleClass) {
141
- Object animModule = Reflect.on(reactContext).call(METHOD_GET_NATIVE_MODULE, animModuleClass).get();
142
- Object nodesManager = Reflect.on(animModule).call("getNodesManager").get();
143
- boolean hasActiveAnimations = Reflect.on(nodesManager).call("hasActiveAnimations").get();
144
- if (!hasActiveAnimations) {
145
- if (callback != null) {
146
- callback.onTransitionToIdle();
147
- }
148
- // Log.i(LOG_TAG, "AnimatedModule is idle, no operations");
149
- return true;
150
- }
151
- return false;
152
- }
153
-
154
- private boolean isIdleRNOld(Object animModuleClass) {
155
- Object animModule = Reflect.on(reactContext).call(METHOD_GET_NATIVE_MODULE, animModuleClass).get();
156
- Object operationsLock = Reflect.on(animModule).field(LOCK_OPERATIONS).get();
157
- boolean operationsAreEmpty;
158
- boolean animationsConsideredIdle;
159
- synchronized (operationsLock) {
160
- Object operations = Reflect.on(animModule).field(FIELD_OPERATIONS).get();
161
- if (operations == null) {
162
- operationsAreEmpty = true;
163
- } else {
164
- operationsAreEmpty = Reflect.on(operations).call(METHOD_IS_EMPTY).get();
165
- }
166
- }
167
- Object nodesManager = Reflect.on(animModule).field(FIELD_NODES_MANAGER).get();
168
-
169
- // We do this in this complicated way
170
- // to not consider looped animations
171
- // as a busy state.
172
- int updatedNodesSize = Reflect.on(nodesManager).field(FIELD_UPDATED_NODES).call(METHOD_SIZE).get();
173
- if (updatedNodesSize > 0) {
174
- animationsConsideredIdle = false;
175
- } else {
176
- Object activeAnims = Reflect.on(nodesManager).field(FIELD_ACTIVE_ANIMATIONS).get();
177
- int activeAnimsSize = Reflect.on(activeAnims).call(METHOD_SIZE).get();
178
- if (activeAnimsSize == 0) {
179
- animationsConsideredIdle = true;
180
- } else {
181
- animationsConsideredIdle = true;
182
- for (int i = 0; i < activeAnimsSize; ++i) {
183
- int iterations = Reflect.on(activeAnims).call(METHOD_VALUE_AT, i).field(FIELD_ITERATIONS).get();
184
- // -1 means it is looped
185
- if (iterations != -1) {
186
- animationsConsideredIdle = false;
187
- break;
188
- }
189
- }
190
- }
191
- }
192
-
193
- if (operationsAreEmpty && animationsConsideredIdle) {
194
- if (callback != null) {
195
- callback.onTransitionToIdle();
196
- }
197
- // Log.i(LOG_TAG, "AnimatedModule is idle.");
198
- return true;
199
- }
200
- return false;
201
- }
202
-
203
- @Override
204
- public void registerIdleTransitionCallback(ResourceCallback callback) {
205
- this.callback = callback;
206
-
207
- Choreographer.getInstance().postFrameCallback(this);
208
- }
209
-
210
- @Override
211
- public void doFrame(long frameTimeNanos) {
212
- isIdleNow();
213
- }
214
- }
215
-
@@ -1,94 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
-
5
- import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
6
- import com.facebook.react.bridge.ReactContext;
7
-
8
- import java.util.Map;
9
- import java.util.concurrent.atomic.AtomicBoolean;
10
-
11
- import androidx.annotation.NonNull;
12
- import androidx.annotation.Nullable;
13
-
14
- /**
15
- * Created by simonracz on 01/06/2017.
16
- */
17
-
18
- /**
19
- * <p>
20
- * IdlingResource for Espresso, which monitors the traffic of
21
- * React Native's JS bridge.
22
- * </p>
23
- */
24
- public class BridgeIdlingResource extends DetoxBaseIdlingResource implements NotThreadSafeBridgeIdleDebugListener {
25
- private static final String LOG_TAG = "Detox";
26
- private final ReactContext reactContext;
27
-
28
- private AtomicBoolean idleNow = new AtomicBoolean(true);
29
- private ResourceCallback callback = null;
30
-
31
- public BridgeIdlingResource(ReactContext reactContext) {
32
- this.reactContext = reactContext;
33
- this.reactContext.getCatalystInstance().addBridgeIdleDebugListener(this);
34
- }
35
-
36
- public void onDetach() {
37
- this.reactContext.getCatalystInstance().removeBridgeIdleDebugListener(this);
38
- }
39
-
40
- @Override
41
- public String getName() {
42
- return BridgeIdlingResource.class.getName();
43
- }
44
-
45
- @NonNull
46
- @Override
47
- public String getDebugName() {
48
- return "bridge";
49
- }
50
-
51
- @Nullable
52
- @Override
53
- public Map<String, Object> getBusyHint() {
54
- return null;
55
- }
56
-
57
- @Override
58
- protected boolean checkIdle() {
59
- boolean ret = idleNow.get();
60
- if (!ret) {
61
- Log.i(LOG_TAG, "JS Bridge is busy");
62
- }
63
- return ret;
64
- }
65
-
66
- @Override
67
- public void registerIdleTransitionCallback(ResourceCallback callback) {
68
- this.callback = callback;
69
- }
70
-
71
- @Override
72
- public void onTransitionToBridgeIdle() {
73
- idleNow.set(true);
74
- notifyIdle();
75
- }
76
-
77
- @Override
78
- public void onTransitionToBridgeBusy() {
79
- idleNow.set(false);
80
- // Log.i(LOG_TAG, "JS Bridge transitions to busy.");
81
- }
82
-
83
- @Override
84
- public void onBridgeDestroyed() {
85
- }
86
-
87
- @Override
88
- protected void notifyIdle() {
89
- // Log.i(LOG_TAG, "JS Bridge transitions to idle.");
90
- if (callback != null) {
91
- callback.onTransitionToIdle();
92
- }
93
- }
94
- }
@@ -1,29 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import com.wix.detox.espresso.idlingresources.DescriptiveIdlingResource;
4
-
5
- import java.util.concurrent.atomic.AtomicBoolean;
6
-
7
- public abstract class DetoxBaseIdlingResource implements DescriptiveIdlingResource {
8
- AtomicBoolean paused = new AtomicBoolean(false);
9
-
10
- public void pause() {
11
- paused.set(true);
12
- notifyIdle();
13
- }
14
-
15
- public void resume() {
16
- paused.set(false);
17
- }
18
-
19
- @Override
20
- final public boolean isIdleNow() {
21
- if (paused.get()) {
22
- return true;
23
- }
24
- return checkIdle();
25
- }
26
-
27
- protected abstract boolean checkIdle();
28
- protected abstract void notifyIdle();
29
- }
@@ -1,134 +0,0 @@
1
- package com.wix.detox.reactnative.idlingresources;
2
-
3
- import android.util.Log;
4
- import android.view.Choreographer;
5
-
6
- import com.facebook.react.bridge.ReactContext;
7
-
8
- import java.util.ArrayList;
9
- import java.util.HashMap;
10
- import java.util.HashSet;
11
- import java.util.List;
12
- import java.util.Map;
13
- import java.util.Set;
14
- import java.util.regex.Pattern;
15
- import java.util.regex.PatternSyntaxException;
16
-
17
- import androidx.annotation.NonNull;
18
- import androidx.annotation.Nullable;
19
- import okhttp3.Call;
20
- import okhttp3.Dispatcher;
21
-
22
-
23
- /**
24
- * Created by simonracz on 09/10/2017.
25
- *
26
- * Idling Resource which monitors React Native's OkHttpClient.
27
- * <p>
28
- * Must call stop() on it, before removing it from Espresso.
29
- */
30
- public class NetworkIdlingResource extends DetoxBaseIdlingResource implements Choreographer.FrameCallback {
31
-
32
- private static final String LOG_TAG = "Detox";
33
-
34
- private ResourceCallback callback;
35
- private Dispatcher dispatcher;
36
- private final Set<String> busyResources = new HashSet<>();
37
-
38
- private static final ArrayList<Pattern> blacklist = new ArrayList<>();
39
-
40
- /**
41
- * Must be called on the UI thread.
42
- *
43
- * @param urls list of regexes of blacklisted urls
44
- */
45
- public static void setURLBlacklist(List<String> urls) {
46
- blacklist.clear();
47
- if (urls == null) return;
48
-
49
- for (String url : urls) {
50
- try {
51
- blacklist.add(Pattern.compile(url));
52
- } catch (PatternSyntaxException e) {
53
- Log.e(LOG_TAG, "Couldn't parse regular expression for Black list url: " + url, e);
54
- }
55
- }
56
- }
57
-
58
- public NetworkIdlingResource(@NonNull ReactContext reactContext) {
59
- this(new NetworkingModuleReflected(reactContext).getHttpClient().dispatcher());
60
- }
61
-
62
- public NetworkIdlingResource(@NonNull Dispatcher dispatcher) {
63
- this.dispatcher = dispatcher;
64
- }
65
-
66
- @Override
67
- public String getName() {
68
- return NetworkIdlingResource.class.getName();
69
- }
70
-
71
- @NonNull
72
- @Override
73
- public String getDebugName() {
74
- return "network";
75
- }
76
-
77
- @Nullable
78
- @Override
79
- public synchronized Map<String, Object> getBusyHint() {
80
- return new HashMap<String, Object>() {{
81
- put("urls", new ArrayList<>(busyResources));
82
- }};
83
- }
84
-
85
- @Override
86
- public void registerIdleTransitionCallback(ResourceCallback callback) {
87
- this.callback = callback;
88
- Choreographer.getInstance().postFrameCallback(this);
89
- }
90
-
91
- @Override
92
- public void doFrame(long frameTimeNanos) {
93
- isIdleNow();
94
- }
95
-
96
- @Override
97
- protected synchronized boolean checkIdle() {
98
- busyResources.clear();
99
-
100
- List<Call> calls = dispatcher.runningCalls();
101
- for (Call call: calls) {
102
- final String url = call.request().url().toString();
103
-
104
- if (!isUrlBlacklisted(url)) {
105
- busyResources.add(url);
106
- }
107
- }
108
-
109
- if (!busyResources.isEmpty()) {
110
- Log.i(LOG_TAG, "Network is busy, with " + busyResources.size() + " in-flight calls");
111
- Choreographer.getInstance().postFrameCallback(this);
112
- return false;
113
- }
114
-
115
- notifyIdle();
116
- return true;
117
- }
118
-
119
- @Override
120
- protected void notifyIdle() {
121
- if (callback != null) {
122
- callback.onTransitionToIdle();
123
- }
124
- }
125
-
126
- private boolean isUrlBlacklisted(String url) {
127
- for (Pattern pattern: blacklist) {
128
- if (pattern.matcher(url).matches()) {
129
- return true;
130
- }
131
- }
132
- return false;
133
- }
134
- }