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.
- 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
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.aar.sha512 +1 -0
- 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
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.30.0/detox-20.30.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/build.gradle +5 -5
- package/android/detox/proguard-rules-app.pro +3 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +54 -3
- package/android/detox/src/full/java/com/wix/detox/espresso/UiAutomatorHelper.java +11 -0
- package/android/detox/src/full/java/com/wix/detox/espresso/matcher/IsDisplayingAtLeastDetoxMatcher.kt +2 -2
- package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxWebAtomMatcher.java +4 -7
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +0 -5
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebViewElement.java +33 -8
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeExtension.kt +6 -11
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeInfo.kt +4 -11
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxIdlingResource.kt +42 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/ReactNativeIdlingResources.kt +145 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/animations/AnimatedModuleIdlingResource.kt +61 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/bridge/BridgeIdlingResource.kt +72 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/DetoxIdlingResourceFactory.kt +32 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/IdlingResourcesName.kt +10 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/factory/LooperName.kt +6 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/looper/MQThreadsReflector.kt +47 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/network/NetworkIdlingResource.kt +105 -0
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{NetworkingModuleReflected.kt → network/NetworkingModuleReflected.kt} +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{AsyncStorageIdlingResource.kt → storage/AsyncStorageIdlingResource.kt} +33 -35
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/{SerialExecutorReflected.kt → storage/SerialExecutorReflected.kt} +1 -1
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResource.kt +21 -19
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIManagerModuleReflected.kt +19 -27
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/UIModuleIdlingResource.kt +5 -17
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceTest.kt +248 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResourcesTest.kt +5 -1
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/SerialExecutorReflectedSpec.kt +1 -0
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/TimersIdlingResourceTest.kt +212 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/rninfo.gradle +31 -24
- package/android/settings.gradle +11 -6
- package/detox.d.ts +39 -0
- package/package.json +11 -8
- package/scripts/postinstall.js +2 -2
- package/scripts/updateGradle.js +41 -8
- package/src/DetoxWorker.js +11 -6
- package/src/android/espressoapi/EspressoDetox.js +83 -0
- package/src/copilot/DetoxCopilot.js +3 -15
- package/src/copilot/detoxCopilotFrameworkDriver.js +27 -15
- package/src/devices/runtime/RuntimeDevice.js +11 -0
- package/src/devices/runtime/drivers/DeviceDriverBase.js +8 -0
- package/src/devices/runtime/drivers/android/AndroidDriver.js +16 -0
- package/src/devices/runtime/drivers/ios/SimulatorDriver.js +35 -0
- package/src/utils/assertArgument.js +9 -0
- package/src/utils/invocationTraceDescriptions.js +1 -0
- package/src/utils/mapDeviceLongPressArguments.js +56 -0
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.27.7-smoke.0/detox-20.27.7-smoke.0.pom.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom +0 -100
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.27.7-smoke.0/detox-legacy-20.27.7-smoke.0.pom.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +0 -13
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +0 -1
- package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxDriverAtoms.java +0 -642
- package/android/detox/src/full/java/com/wix/detox/reactnative/ReactNativeIdlingResources.kt +0 -229
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/AnimatedModuleIdlingResource.java +0 -215
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/BridgeIdlingResource.java +0 -94
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/DetoxBaseIdlingResource.java +0 -29
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/NetworkIdlingResource.java +0 -134
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategy.kt +0 -23
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/timers/IdleInterrogationStrategy.kt +0 -16
- package/android/detox/src/full/java/com/wix/detox/reactnative/idlingresources/uimodule/RN66Workaround.kt +0 -71
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/AsyncStorageIdlingResourceSpec.kt +0 -227
- package/android/detox/src/testFull/java/com/wix/detox/reactnative/idlingresources/timers/DelegatedIdleInterrogationStrategySpec.kt +0 -47
- 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
|
-
}
|