detox 20.28.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.28.0/detox-20.28.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.28.0/detox-20.28.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 +1 -1
- package/android/detox/src/full/java/com/wix/detox/espresso/web/DetoxWebAtomMatcher.java +3 -3
- package/android/detox/src/full/java/com/wix/detox/espresso/web/WebElement.java +0 -1
- 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/package.json +11 -8
- package/scripts/postinstall.js +2 -2
- package/scripts/updateGradle.js +41 -8
- package/src/DetoxWorker.js +11 -6
- package/src/copilot/DetoxCopilot.js +3 -15
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.28.0/detox-20.28.0.pom.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar +0 -0
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom +0 -100
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox-legacy/20.28.0/detox-legacy-20.28.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/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
@@ -0,0 +1,248 @@
|
|
1
|
+
package com.wix.detox.reactnative.idlingresources
|
2
|
+
|
3
|
+
import androidx.test.espresso.IdlingResource
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
5
|
+
import com.wix.detox.UTHelpers.yieldToOtherThreads
|
6
|
+
import com.wix.detox.reactnative.idlingresources.storage.AsyncStorageIdlingResource
|
7
|
+
import com.wix.detox.reactnative.idlingresources.storage.SerialExecutorReflected
|
8
|
+
import org.assertj.core.api.Assertions.assertThat
|
9
|
+
import org.junit.Before
|
10
|
+
import org.junit.Test
|
11
|
+
import org.junit.runner.RunWith
|
12
|
+
import org.mockito.kotlin.any
|
13
|
+
import org.mockito.kotlin.argumentCaptor
|
14
|
+
import org.mockito.kotlin.eq
|
15
|
+
import org.mockito.kotlin.mock
|
16
|
+
import org.mockito.kotlin.never
|
17
|
+
import org.mockito.kotlin.times
|
18
|
+
import org.mockito.kotlin.verify
|
19
|
+
import org.mockito.kotlin.whenever
|
20
|
+
import org.robolectric.RobolectricTestRunner
|
21
|
+
import java.util.concurrent.Executor
|
22
|
+
import java.util.concurrent.Executors
|
23
|
+
|
24
|
+
private class AsyncStorageModuleStub : NativeModule {
|
25
|
+
val executor: Executor = mock(name = "native-module's executor")
|
26
|
+
override fun getName() = "stub"
|
27
|
+
override fun initialize() {}
|
28
|
+
override fun canOverrideExistingModule() = false
|
29
|
+
override fun onCatalystInstanceDestroy() {}
|
30
|
+
override fun invalidate() {}
|
31
|
+
}
|
32
|
+
|
33
|
+
@RunWith(RobolectricTestRunner::class)
|
34
|
+
class AsyncStorageIdlingResourceTest {
|
35
|
+
private lateinit var sexecutor: Executor
|
36
|
+
private lateinit var sexecutorReflected: SerialExecutorReflected
|
37
|
+
private lateinit var sexecutorReflectedGenFn: (executor: Executor) -> SerialExecutorReflected
|
38
|
+
private lateinit var module: AsyncStorageModuleStub
|
39
|
+
private lateinit var uut: AsyncStorageIdlingResource
|
40
|
+
|
41
|
+
@Before
|
42
|
+
fun setup() {
|
43
|
+
sexecutor = mock()
|
44
|
+
module = AsyncStorageModuleStub()
|
45
|
+
sexecutorReflected = mock() {
|
46
|
+
on { executor() }.thenReturn(sexecutor)
|
47
|
+
}
|
48
|
+
sexecutorReflectedGenFn = mock() {
|
49
|
+
on { invoke(eq(module.executor)) }.thenReturn(sexecutorReflected)
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
uut = AsyncStorageIdlingResource(module, sexecutorReflectedGenFn)
|
54
|
+
}
|
55
|
+
|
56
|
+
fun givenNoActiveTasks() = whenever(sexecutorReflected.hasActiveTask()).thenReturn(false)
|
57
|
+
fun givenAnActiveTask() = whenever(sexecutorReflected.hasActiveTask()).thenReturn(true)
|
58
|
+
fun givenNoPendingTasks() = whenever(sexecutorReflected.hasPendingTasks()).thenReturn(false)
|
59
|
+
fun givenPendingTasks() = whenever(sexecutorReflected.hasPendingTasks()).thenReturn(true)
|
60
|
+
fun givenIdleSExecutor() {
|
61
|
+
givenNoActiveTasks()
|
62
|
+
givenNoPendingTasks()
|
63
|
+
}
|
64
|
+
|
65
|
+
fun givenBusySExecutor() {
|
66
|
+
givenAnActiveTask()
|
67
|
+
givenNoPendingTasks()
|
68
|
+
}
|
69
|
+
|
70
|
+
fun verifyNoTasksEnqueued() = verify(sexecutorReflected, never()).executeTask(any())
|
71
|
+
fun verifyTaskEnqueuedOnce() = verify(sexecutorReflected, times(1)).executeTask(any())
|
72
|
+
fun verifyTaskEnqueuedTwice() = verify(sexecutorReflected, times(2)).executeTask(any())
|
73
|
+
|
74
|
+
@Test
|
75
|
+
fun `should have a name`() {
|
76
|
+
assertThat(uut.name).isEqualTo("com.wix.detox.reactnative.idlingresources.storage.AsyncStorageIdlingResource")
|
77
|
+
}
|
78
|
+
|
79
|
+
@Test
|
80
|
+
fun `should have a debug-name`() {
|
81
|
+
assertThat(uut.getDebugName()).isEqualTo("io")
|
82
|
+
}
|
83
|
+
|
84
|
+
@Test
|
85
|
+
fun `should be idle`() {
|
86
|
+
givenIdleSExecutor()
|
87
|
+
assertThat(uut.isIdleNow).isTrue()
|
88
|
+
}
|
89
|
+
|
90
|
+
@Test
|
91
|
+
fun `should be busy if executor is executing`() {
|
92
|
+
givenAnActiveTask()
|
93
|
+
givenNoPendingTasks()
|
94
|
+
assertThat(uut.isIdleNow).isFalse()
|
95
|
+
}
|
96
|
+
|
97
|
+
@Test
|
98
|
+
fun `should be busy if executor has pending tasks`() {
|
99
|
+
givenNoActiveTasks()
|
100
|
+
givenPendingTasks()
|
101
|
+
assertThat(uut.isIdleNow).isFalse()
|
102
|
+
}
|
103
|
+
|
104
|
+
@Test
|
105
|
+
fun `should be synchronized over actual executor`() {
|
106
|
+
val localExecutor = Executors.newSingleThreadExecutor()
|
107
|
+
var isIdle: Boolean? = null
|
108
|
+
synchronized(sexecutor) {
|
109
|
+
localExecutor.submit {
|
110
|
+
isIdle = uut.isIdleNow
|
111
|
+
}
|
112
|
+
yieldToOtherThreads(localExecutor)
|
113
|
+
assertThat(isIdle).isNull()
|
114
|
+
}
|
115
|
+
yieldToOtherThreads(localExecutor)
|
116
|
+
}
|
117
|
+
|
118
|
+
@Test
|
119
|
+
fun `should enqueue an idle-check task if resource is busy`() {
|
120
|
+
givenBusySExecutor()
|
121
|
+
uut.isIdleNow
|
122
|
+
verifyTaskEnqueuedOnce()
|
123
|
+
}
|
124
|
+
|
125
|
+
@Test
|
126
|
+
fun `should not enqueue an idle-check task if resource if idle`() {
|
127
|
+
givenIdleSExecutor()
|
128
|
+
uut.isIdleNow
|
129
|
+
verifyNoTasksEnqueued()
|
130
|
+
}
|
131
|
+
|
132
|
+
@Test
|
133
|
+
fun `should not enqueue more than one idle-check task`() {
|
134
|
+
givenBusySExecutor()
|
135
|
+
|
136
|
+
repeat(2) {
|
137
|
+
uut.isIdleNow
|
138
|
+
}
|
139
|
+
verifyTaskEnqueuedOnce()
|
140
|
+
}
|
141
|
+
|
142
|
+
private val callback: IdlingResource.ResourceCallback = mock()
|
143
|
+
|
144
|
+
|
145
|
+
fun verifyTransitionToIdleCalled() = verify(callback).onTransitionToIdle()
|
146
|
+
fun verifyTransitionToIdleNotCalled() = verify(callback, never()).onTransitionToIdle()
|
147
|
+
|
148
|
+
@Test
|
149
|
+
fun `should enqueue an idle-check task`() {
|
150
|
+
uut.registerIdleTransitionCallback(callback)
|
151
|
+
verifyTaskEnqueuedOnce()
|
152
|
+
}
|
153
|
+
|
154
|
+
@Test
|
155
|
+
fun `callback registration - should be synchronized over actual executor`() {
|
156
|
+
val localExecutor = Executors.newSingleThreadExecutor()
|
157
|
+
|
158
|
+
synchronized(sexecutor) {
|
159
|
+
localExecutor.submit {
|
160
|
+
uut.registerIdleTransitionCallback(callback)
|
161
|
+
}
|
162
|
+
yieldToOtherThreads(localExecutor)
|
163
|
+
verifyNoTasksEnqueued()
|
164
|
+
}
|
165
|
+
yieldToOtherThreads(localExecutor)
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
fun executeIdleCheckTask() {
|
170
|
+
argumentCaptor<Runnable>().also {
|
171
|
+
verify(sexecutorReflected).executeTask(it.capture())
|
172
|
+
}.firstValue.run()
|
173
|
+
}
|
174
|
+
|
175
|
+
@Test
|
176
|
+
fun `should transition to idle`() {
|
177
|
+
givenIdleSExecutor()
|
178
|
+
|
179
|
+
uut.registerIdleTransitionCallback(callback)
|
180
|
+
executeIdleCheckTask()
|
181
|
+
|
182
|
+
verifyTransitionToIdleCalled()
|
183
|
+
}
|
184
|
+
|
185
|
+
@Test
|
186
|
+
fun `should not transition to idle if busy`() {
|
187
|
+
givenAnActiveTask()
|
188
|
+
givenPendingTasks()
|
189
|
+
|
190
|
+
uut.registerIdleTransitionCallback(callback)
|
191
|
+
executeIdleCheckTask()
|
192
|
+
|
193
|
+
verifyTransitionToIdleNotCalled()
|
194
|
+
}
|
195
|
+
|
196
|
+
@Test
|
197
|
+
fun `should not inspect sexecutor for activity, because it runs on the executor itself`() {
|
198
|
+
givenAnActiveTask()
|
199
|
+
givenPendingTasks()
|
200
|
+
|
201
|
+
uut.registerIdleTransitionCallback(callback)
|
202
|
+
executeIdleCheckTask()
|
203
|
+
|
204
|
+
verify(sexecutorReflected, never()).hasActiveTask()
|
205
|
+
}
|
206
|
+
|
207
|
+
@Test
|
208
|
+
fun `should reenqueue if still busy`() {
|
209
|
+
givenAnActiveTask()
|
210
|
+
givenPendingTasks()
|
211
|
+
|
212
|
+
uut.registerIdleTransitionCallback(callback)
|
213
|
+
executeIdleCheckTask()
|
214
|
+
|
215
|
+
verifyTaskEnqueuedTwice()
|
216
|
+
}
|
217
|
+
|
218
|
+
@Test
|
219
|
+
fun `should be synchronized`() {
|
220
|
+
val localExecutor = Executors.newSingleThreadExecutor()
|
221
|
+
|
222
|
+
givenIdleSExecutor()
|
223
|
+
uut.registerIdleTransitionCallback(callback)
|
224
|
+
|
225
|
+
synchronized(sexecutor) {
|
226
|
+
localExecutor.submit {
|
227
|
+
executeIdleCheckTask()
|
228
|
+
}
|
229
|
+
yieldToOtherThreads(localExecutor)
|
230
|
+
verifyTransitionToIdleNotCalled()
|
231
|
+
}
|
232
|
+
yieldToOtherThreads(localExecutor)
|
233
|
+
}
|
234
|
+
|
235
|
+
|
236
|
+
@Test
|
237
|
+
fun `should allow for an enqueuing of more tasks after idle-transition`() {
|
238
|
+
uut.registerIdleTransitionCallback(callback)
|
239
|
+
|
240
|
+
givenIdleSExecutor()
|
241
|
+
executeIdleCheckTask()
|
242
|
+
|
243
|
+
givenBusySExecutor()
|
244
|
+
uut.isIdleNow
|
245
|
+
|
246
|
+
verifyTaskEnqueuedTwice()
|
247
|
+
}
|
248
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
package com.wix.detox.reactnative.idlingresources
|
2
2
|
|
3
3
|
import com.wix.detox.UTHelpers.yieldToOtherThreads
|
4
|
+
import com.wix.detox.reactnative.idlingresources.network.NetworkIdlingResource
|
4
5
|
import org.assertj.core.api.Assertions.assertThat
|
5
6
|
|
6
7
|
import okhttp3.Dispatcher
|
@@ -18,7 +19,10 @@ class NetworkIdlingResourcesTest {
|
|
18
19
|
@Before
|
19
20
|
fun setup() {
|
20
21
|
dispatcher = Dispatcher()
|
21
|
-
uut =
|
22
|
+
uut =
|
23
|
+
NetworkIdlingResource(
|
24
|
+
dispatcher
|
25
|
+
)
|
22
26
|
}
|
23
27
|
|
24
28
|
// Note: Ideally, we should test that the list of busy resources is protected,
|
@@ -0,0 +1,212 @@
|
|
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.facebook.react.modules.core.TimingModule
|
7
|
+
import org.assertj.core.api.Assertions
|
8
|
+
import org.junit.Before
|
9
|
+
import org.junit.Test
|
10
|
+
import org.junit.runner.RunWith
|
11
|
+
import org.mockito.kotlin.*
|
12
|
+
import org.robolectric.RobolectricTestRunner
|
13
|
+
import org.spekframework.spek2.Spek
|
14
|
+
import org.spekframework.spek2.style.specification.describe
|
15
|
+
|
16
|
+
private fun anIdlingResourceCallback() = mock<IdlingResource.ResourceCallback>()
|
17
|
+
|
18
|
+
@RunWith(RobolectricTestRunner::class)
|
19
|
+
class TimersIdlingResourceTest {
|
20
|
+
private val choreographer: Choreographer = mock()
|
21
|
+
private val context: ReactContext = mock()
|
22
|
+
private val timersModule: TimingModule = mock()
|
23
|
+
private lateinit var timersIdlingResource: TimersIdlingResource
|
24
|
+
|
25
|
+
@Before
|
26
|
+
fun setup() {
|
27
|
+
whenever(context.getNativeModule(eq(TimingModule::class.java))).thenReturn(timersModule)
|
28
|
+
timersIdlingResource = TimersIdlingResource(context) { choreographer }
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
private fun givenIdleStrategy() {
|
33
|
+
whenever(timersModule.hasActiveTimersInRange(any())).thenReturn(false)
|
34
|
+
}
|
35
|
+
|
36
|
+
private fun givenBusyStrategy() {
|
37
|
+
whenever(timersModule.hasActiveTimersInRange(any())).thenReturn(true)
|
38
|
+
}
|
39
|
+
|
40
|
+
private fun getChoreographerCallback(): Choreographer.FrameCallback {
|
41
|
+
argumentCaptor<Choreographer.FrameCallback>().apply {
|
42
|
+
verify(choreographer).postFrameCallback(capture())
|
43
|
+
return firstValue
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
private fun invokeChoreographerCallback() {
|
48
|
+
getChoreographerCallback().doFrame(0L)
|
49
|
+
}
|
50
|
+
|
51
|
+
@Test
|
52
|
+
fun `should return a debug-name`() {
|
53
|
+
Assertions.assertThat(timersIdlingResource.getDebugName()).isEqualTo("timers")
|
54
|
+
}
|
55
|
+
|
56
|
+
@Test
|
57
|
+
fun `should be idle if strategy says so`() {
|
58
|
+
givenIdleStrategy()
|
59
|
+
Assertions.assertThat(timersIdlingResource.isIdleNow).isTrue()
|
60
|
+
}
|
61
|
+
|
62
|
+
@Test
|
63
|
+
fun `should be busy if strategy says so`() {
|
64
|
+
givenBusyStrategy()
|
65
|
+
Assertions.assertThat(timersIdlingResource.isIdleNow).isFalse()
|
66
|
+
}
|
67
|
+
|
68
|
+
@Test
|
69
|
+
fun `should transition to idle if found idle by strategy`() {
|
70
|
+
givenIdleStrategy()
|
71
|
+
|
72
|
+
val callback = anIdlingResourceCallback()
|
73
|
+
|
74
|
+
with(timersIdlingResource) {
|
75
|
+
registerIdleTransitionCallback(callback)
|
76
|
+
isIdleNow
|
77
|
+
}
|
78
|
+
|
79
|
+
verify(callback).onTransitionToIdle()
|
80
|
+
}
|
81
|
+
|
82
|
+
@Test
|
83
|
+
fun `should NOT transition to idle if found busy by strategy`() {
|
84
|
+
givenBusyStrategy()
|
85
|
+
|
86
|
+
val callback = anIdlingResourceCallback()
|
87
|
+
|
88
|
+
with(timersIdlingResource) {
|
89
|
+
registerIdleTransitionCallback(callback)
|
90
|
+
isIdleNow
|
91
|
+
}
|
92
|
+
|
93
|
+
verify(callback, never()).onTransitionToIdle()
|
94
|
+
}
|
95
|
+
|
96
|
+
@Test
|
97
|
+
fun `should be idle if paused`() {
|
98
|
+
givenBusyStrategy()
|
99
|
+
|
100
|
+
val uut = timersIdlingResource.apply {
|
101
|
+
pause()
|
102
|
+
}
|
103
|
+
|
104
|
+
Assertions.assertThat(uut.isIdleNow).isTrue()
|
105
|
+
}
|
106
|
+
|
107
|
+
@Test
|
108
|
+
fun `should be busy if paused and resumed`() {
|
109
|
+
givenBusyStrategy()
|
110
|
+
|
111
|
+
val uut = timersIdlingResource.apply {
|
112
|
+
pause()
|
113
|
+
resume()
|
114
|
+
}
|
115
|
+
|
116
|
+
Assertions.assertThat(uut.isIdleNow).isFalse()
|
117
|
+
}
|
118
|
+
|
119
|
+
@Test
|
120
|
+
fun `should notify of transition to idle upon pausing`() {
|
121
|
+
givenBusyStrategy()
|
122
|
+
|
123
|
+
val callback = anIdlingResourceCallback()
|
124
|
+
|
125
|
+
with(timersIdlingResource) {
|
126
|
+
registerIdleTransitionCallback(callback)
|
127
|
+
pause()
|
128
|
+
}
|
129
|
+
|
130
|
+
verify(callback).onTransitionToIdle()
|
131
|
+
}
|
132
|
+
|
133
|
+
@Test
|
134
|
+
fun `should enqueue an is-idle check using choreographer when a callback gets registered`() {
|
135
|
+
with(timersIdlingResource) {
|
136
|
+
registerIdleTransitionCallback(mock())
|
137
|
+
}
|
138
|
+
|
139
|
+
verify(choreographer).postFrameCallback(any())
|
140
|
+
}
|
141
|
+
|
142
|
+
@Test
|
143
|
+
fun `should transition to idle when preregistered choreographer is dispatched`() {
|
144
|
+
givenIdleStrategy()
|
145
|
+
|
146
|
+
val callback = anIdlingResourceCallback()
|
147
|
+
|
148
|
+
timersIdlingResource.registerIdleTransitionCallback(callback)
|
149
|
+
invokeChoreographerCallback()
|
150
|
+
|
151
|
+
verify(callback).onTransitionToIdle()
|
152
|
+
}
|
153
|
+
|
154
|
+
@Test
|
155
|
+
fun `should NOT transition to idle if not idle when preregistered choreographer is dispatched`() {
|
156
|
+
givenBusyStrategy()
|
157
|
+
|
158
|
+
val callback = anIdlingResourceCallback()
|
159
|
+
|
160
|
+
timersIdlingResource.registerIdleTransitionCallback(callback)
|
161
|
+
invokeChoreographerCallback()
|
162
|
+
|
163
|
+
verify(callback, never()).onTransitionToIdle()
|
164
|
+
}
|
165
|
+
|
166
|
+
@Test
|
167
|
+
fun `should re-register choreographer if found idle while preregistered choreographer is dispatched`() {
|
168
|
+
givenBusyStrategy()
|
169
|
+
|
170
|
+
val callback = anIdlingResourceCallback()
|
171
|
+
|
172
|
+
val uut = timersIdlingResource
|
173
|
+
uut.registerIdleTransitionCallback(callback)
|
174
|
+
invokeChoreographerCallback()
|
175
|
+
|
176
|
+
verify(choreographer, times(2)).postFrameCallback(any())
|
177
|
+
}
|
178
|
+
|
179
|
+
@Test
|
180
|
+
fun `should adhere to pausing also when invoked via choreographer callback`() {
|
181
|
+
givenBusyStrategy()
|
182
|
+
|
183
|
+
val callback = anIdlingResourceCallback()
|
184
|
+
|
185
|
+
timersIdlingResource.apply {
|
186
|
+
pause()
|
187
|
+
registerIdleTransitionCallback(callback)
|
188
|
+
}
|
189
|
+
val runtimeChoreographerCallback = getChoreographerCallback()
|
190
|
+
|
191
|
+
reset(callback, choreographer)
|
192
|
+
runtimeChoreographerCallback.doFrame(0L)
|
193
|
+
|
194
|
+
verify(callback, never()).onTransitionToIdle()
|
195
|
+
verify(choreographer, never()).postFrameCallback(any())
|
196
|
+
}
|
197
|
+
|
198
|
+
@Test
|
199
|
+
fun `should enqueue an additional idle check (using choreographer) if found busy`() {
|
200
|
+
givenBusyStrategy()
|
201
|
+
timersIdlingResource.isIdleNow
|
202
|
+
verify(choreographer).postFrameCallback(any())
|
203
|
+
}
|
204
|
+
|
205
|
+
@Test
|
206
|
+
fun `should NOT enqueue an additional idle check (using choreographer) if found idle`() {
|
207
|
+
givenIdleStrategy()
|
208
|
+
timersIdlingResource.isIdleNow
|
209
|
+
verify(choreographer, never()).postFrameCallback(any())
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
distributionBase=GRADLE_USER_HOME
|
2
2
|
distributionPath=wrapper/dists
|
3
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.
|
3
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
4
4
|
networkTimeout=10000
|
5
5
|
validateDistributionUrl=true
|
6
6
|
zipStoreBase=GRADLE_USER_HOME
|
package/android/rninfo.gradle
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
import groovy.json.JsonSlurper
|
2
2
|
|
3
|
-
def
|
4
|
-
|
3
|
+
def getRNPackageJsonDir() {
|
4
|
+
def currentDir = rootDir
|
5
|
+
while (currentDir != null) {
|
6
|
+
def nodeModulesDir = new File(currentDir, "node_modules/react-native")
|
7
|
+
def file = new File(nodeModulesDir, 'package.json')
|
8
|
+
if (file.exists()) {
|
9
|
+
return file.path
|
10
|
+
}
|
11
|
+
currentDir = currentDir.parentFile
|
12
|
+
}
|
13
|
+
throw new GradleException("Unable to find module: $moduleName")
|
14
|
+
}
|
15
|
+
|
16
|
+
def getRNVersion = { rnPackageJsonPath ->
|
17
|
+
println("RNInfo: package.json=$rnPackageJsonPath")
|
5
18
|
def jsonSlurper = new JsonSlurper()
|
6
|
-
def packageFile =
|
7
|
-
println("RNInfo: reading $
|
8
|
-
Map<String, Object> packageJSON = jsonSlurper.parse(new File(
|
19
|
+
def packageFile =
|
20
|
+
println("RNInfo: reading $rnPackageJsonPath")
|
21
|
+
Map<String, Object> packageJSON = jsonSlurper.parse(new File(rnPackageJsonPath))
|
9
22
|
String rnVersion = packageJSON.get('version')
|
10
23
|
return rnVersion
|
11
24
|
}
|
@@ -15,24 +28,18 @@ def getMajorVersionInternal = { semanticVersion ->
|
|
15
28
|
return rnVersionMajor
|
16
29
|
}
|
17
30
|
|
18
|
-
|
19
|
-
String rnVersion = getRNVersion(workingDir)
|
20
|
-
Integer rnVersionMajor = getMajorVersionInternal(rnVersion)
|
21
|
-
return rnVersionMajor
|
22
|
-
}
|
23
|
-
|
24
|
-
def rnVersion = getRNVersion(rootDir)
|
31
|
+
def rnVersion = getRNVersion(getRNPackageJsonDir())
|
25
32
|
def rnMajorVer = getMajorVersionInternal(rnVersion)
|
26
|
-
|
27
|
-
println "[$project] RNInfo: detected React Native version: $rnVersion (major=$rnMajorVer)"
|
33
|
+
println "RNInfo: detected React Native version: $rnVersion (major=$rnMajorVer)"
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
ext.rnInfo = [
|
36
|
+
version : rnVersion,
|
37
|
+
majorVersion : rnMajorVer,
|
38
|
+
isRN69OrHigher: rnMajorVer >= 69,
|
39
|
+
isRN70OrHigher: rnMajorVer >= 70,
|
40
|
+
isRN71OrHigher: rnMajorVer >= 71,
|
41
|
+
isRN72OrHigher: rnMajorVer >= 72,
|
42
|
+
isRN73OrHigher: rnMajorVer >= 73,
|
43
|
+
isRN74OrHigher: rnMajorVer >= 74,
|
44
|
+
isRN75OrHigher: rnMajorVer >= 75,
|
45
|
+
]
|
package/android/settings.gradle
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
+
// RN75+_BLOCK_START
|
2
|
+
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
|
3
|
+
plugins { id("com.facebook.react.settings") }
|
4
|
+
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
|
5
|
+
// RN75+_BLOCK_END
|
6
|
+
|
7
|
+
|
1
8
|
apply from: '../android/rninfo.gradle'
|
2
9
|
include ':detox'
|
3
10
|
|
4
11
|
println("RNInfo: rootDir=$rootDir")
|
12
|
+
println "[settings] RNInfo: detected React Native version: (major=${ext.rnInfo.version})"
|
5
13
|
|
6
|
-
def rnMajorVer = getRnMajorVersion(rootDir)
|
7
|
-
println "[settings] RNInfo: detected React Native version: (major=$rnMajorVer)"
|
8
14
|
|
9
|
-
if (
|
10
|
-
includeBuild('../node_modules/react-native-gradle-plugin')
|
11
|
-
} else {
|
15
|
+
if (ext.rnInfo.isRN72OrHigher) {
|
12
16
|
includeBuild('../node_modules/@react-native/gradle-plugin')
|
17
|
+
} else {
|
18
|
+
includeBuild('../node_modules/react-native-gradle-plugin')
|
13
19
|
}
|
14
|
-
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "detox",
|
3
3
|
"description": "E2E tests and automation for mobile",
|
4
|
-
"version": "20.
|
4
|
+
"version": "20.31.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -34,10 +34,13 @@
|
|
34
34
|
"postinstall": "node scripts/postinstall.js"
|
35
35
|
},
|
36
36
|
"devDependencies": {
|
37
|
-
"@react-native/
|
38
|
-
"@react-native/
|
39
|
-
"@react-native/
|
40
|
-
"@react-native/
|
37
|
+
"@react-native-community/cli": "15.0.1",
|
38
|
+
"@react-native-community/cli-platform-android": "15.0.1",
|
39
|
+
"@react-native-community/cli-platform-ios": "15.0.1",
|
40
|
+
"@react-native/babel-preset": "0.76.3",
|
41
|
+
"@react-native/eslint-config": "0.76.3",
|
42
|
+
"@react-native/metro-config": "0.76.3",
|
43
|
+
"@react-native/typescript-config": "0.76.3",
|
41
44
|
"@tsconfig/react-native": "^3.0.0",
|
42
45
|
"@types/bunyan": "^1.8.8",
|
43
46
|
"@types/child-process-promise": "^2.2.1",
|
@@ -59,7 +62,7 @@
|
|
59
62
|
"jest-allure2-reporter": "^2.0.0-beta.18",
|
60
63
|
"metro-react-native-babel-preset": "0.76.8",
|
61
64
|
"prettier": "^3.1.1",
|
62
|
-
"react-native": "0.
|
65
|
+
"react-native": "0.76.3",
|
63
66
|
"react-native-codegen": "^0.0.8",
|
64
67
|
"typescript": "^5.3.3",
|
65
68
|
"wtfnode": "^0.9.1"
|
@@ -71,7 +74,7 @@
|
|
71
74
|
"caf": "^15.0.1",
|
72
75
|
"chalk": "^4.0.0",
|
73
76
|
"child-process-promise": "^2.2.0",
|
74
|
-
"detox-copilot": "^0.0.
|
77
|
+
"detox-copilot": "^0.0.27",
|
75
78
|
"execa": "^5.1.1",
|
76
79
|
"find-up": "^5.0.0",
|
77
80
|
"fs-extra": "^11.0.0",
|
@@ -116,5 +119,5 @@
|
|
116
119
|
"browserslist": [
|
117
120
|
"node 14"
|
118
121
|
],
|
119
|
-
"gitHead": "
|
122
|
+
"gitHead": "89a3f0efbac69cd37db886a53f712d51db8f857d"
|
120
123
|
}
|
package/scripts/postinstall.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
const { platform, env } = process;
|
2
2
|
|
3
|
-
const {
|
3
|
+
const { patchGradleByRNVersion } = require('./updateGradle');
|
4
4
|
|
5
5
|
const isDarwin = platform === 'darwin';
|
6
6
|
const shouldInstallDetox = !env.DETOX_DISABLE_POSTINSTALL;
|
@@ -12,4 +12,4 @@ if (isDarwin && shouldInstallDetox) {
|
|
12
12
|
execFileSync(`${__dirname}/build_local_xcuitest.ios.sh`, { stdio: 'inherit' });
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
patchGradleByRNVersion();
|