Skip to content

Commit 4ca22af

Browse files
committed
User waitUntil instead of delay
1 parent d7f1d30 commit 4ca22af

2 files changed

Lines changed: 62 additions & 55 deletions

File tree

compose/ui/ui/src/uikitInstrumentedTest/kotlin/androidx/compose/ui/interop/UIKitNavigationSwipeBackTest.kt

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.compose.foundation.layout.systemBarsPadding
2525
import androidx.compose.foundation.pager.HorizontalPager
2626
import androidx.compose.foundation.pager.rememberPagerState
2727
import androidx.compose.runtime.Composable
28+
import androidx.compose.runtime.LaunchedEffect
2829
import androidx.compose.runtime.MutableIntState
2930
import androidx.compose.runtime.mutableIntStateOf
3031
import androidx.compose.ui.Modifier
@@ -55,38 +56,36 @@ internal abstract class UIKitNavigationSwipeBackTest(
5556
) {
5657
@Test
5758
fun testSwipeRightOnPagerDoesNotPopController() = runUIKitInstrumentedTest {
58-
val currentPage = mutableIntStateOf(0)
59+
val initialPage = 0
60+
val currentPage = mutableIntStateOf(initialPage)
5961

6062
setNavigationControllerContent {
6163
TestContent(currentPage = currentPage)
6264
}
6365

64-
delay(10)
65-
6666
findNodeWithTag("pager").swipeRight()
6767

68-
delay(500)
68+
waitForIdle()
6969

7070
assertEquals(2, navigationController.viewControllers.size)
7171
assertNotNull(findNodeWithTagOrNull("pager"))
72-
assertEquals(0, currentPage.value)
72+
assertEquals(initialPage, currentPage.value)
7373
}
7474

7575
@Test
7676
fun testSwipeLeftOnPagerChangesPage() = runUIKitInstrumentedTest {
77-
val currentPage = mutableIntStateOf(0)
77+
val initialPage = 0
78+
val currentPage = mutableIntStateOf(initialPage)
7879

7980
setNavigationControllerContent {
8081
TestContent(currentPage = currentPage)
8182
}
8283

83-
delay(10)
84-
8584
findNodeWithTag("pager").swipeLeft()
8685

8786
waitForIdle()
8887

89-
assertEquals(1, currentPage.value)
88+
assertEquals(initialPage + 1, currentPage.value)
9089
assertEquals(2, navigationController.viewControllers.size)
9190
}
9291

@@ -99,8 +98,6 @@ internal abstract class UIKitNavigationSwipeBackTest(
9998
TestContent(currentPage = currentPage)
10099
}
101100

102-
delay(10)
103-
104101
findNodeWithTag("outsideBox").swipeLeft()
105102

106103
assertEquals(initialPage, currentPage.value)
@@ -113,16 +110,14 @@ internal abstract class UIKitNavigationSwipeBackTest(
113110
TestContent(currentPage = mutableIntStateOf(1))
114111
}
115112

116-
delay(10)
117-
118113
swipeRightFromEdge()
119114

120-
// wait for pop animation to finish
121-
delay(500)
115+
waitUntil("Waiting for view controller to be popped") {
116+
navigationController.viewControllers.size == 1
117+
}
122118

123119
assertNull(findNodeWithTagOrNull("pager"))
124120
assertNull(findNodeWithTagOrNull("outsideBox"))
125-
assertEquals(1, navigationController.viewControllers.size)
126121
}
127122

128123
@Test
@@ -137,15 +132,12 @@ internal abstract class UIKitNavigationSwipeBackTest(
137132
TestContent(currentPage = currentPage)
138133
}
139134

140-
delay(10)
141-
142135
findNodeWithTag("outsideBox").swipe(
143136
fromPosition = { center() },
144137
toPosition = { rightCenter() },
145138
)
146139

147-
// wait for pop animation to finish if any
148-
delay(500)
140+
waitForIdle()
149141

150142
assertNotNull(findNodeWithTagOrNull("pager"))
151143
assertNotNull(findNodeWithTagOrNull("outsideBox"))
@@ -164,16 +156,11 @@ internal abstract class UIKitNavigationSwipeBackTest(
164156
TestContent(currentPage = currentPage)
165157
}
166158

167-
delay(10)
168-
169159
findNodeWithTag("outsideBox").swipeRight()
170160

171-
// wait for pop animation to finish
172-
delay(500)
173-
174-
assertNull(findNodeWithTagOrNull("pager"))
175-
assertNull(findNodeWithTagOrNull("outsideBox"))
176-
assertEquals(1, navigationController.viewControllers.size)
161+
waitUntil("Waiting for view controller to be popped") {
162+
navigationController.viewControllers.size == 1
163+
}
177164
}
178165

179166
@Test
@@ -188,16 +175,11 @@ internal abstract class UIKitNavigationSwipeBackTest(
188175
TestContent(currentPage = currentPage)
189176
}
190177

191-
delay(10)
192-
193178
swipeRightFromEdge()
194179

195-
// wait for pop animation to finish
196-
delay(500)
197-
198-
assertNull(findNodeWithTagOrNull("pager"))
199-
assertNull(findNodeWithTagOrNull("outsideBox"))
200-
assertEquals(1, navigationController.viewControllers.size)
180+
waitUntil("Waiting for view controller to be popped") {
181+
navigationController.viewControllers.size == 1
182+
}
201183
}
202184

203185
@Test
@@ -212,19 +194,16 @@ internal abstract class UIKitNavigationSwipeBackTest(
212194
TestContent(currentPage = currentPage)
213195
}
214196

215-
delay(10)
216-
217197
findNodeWithTag("outsideBox").swipe(
218198
fromPosition = { center() },
219199
toPosition = { rightCenter() },
220200
)
221201

222-
// wait for pop animation to finish
223-
delay(500)
202+
waitForIdle()
224203

225-
assertNull(findNodeWithTagOrNull("pager"))
226-
assertNull(findNodeWithTagOrNull("outsideBox"))
227-
assertEquals(1, navigationController.viewControllers.size)
204+
waitUntil("Waiting for view controller to be popped") {
205+
navigationController.viewControllers.size == 1
206+
}
228207
}
229208

230209
private val UIKitInstrumentedTest.navigationController: UINavigationController get() {
@@ -233,12 +212,17 @@ internal abstract class UIKitNavigationSwipeBackTest(
233212

234213
private fun UIKitInstrumentedTest.setNavigationControllerContent(
235214
content: @Composable () -> Unit = {}
236-
) = setupWindow {
237-
val firstViewController = UIViewController()
238-
val secondViewController = createRootViewController(content = content)
215+
) {
216+
val composeViewController = createViewControllerHostingCompose(content = content)
239217

240-
UINavigationController().also {
241-
it.setViewControllers(listOf(firstViewController, secondViewController), false)
218+
setupWindow {
219+
UINavigationController().also {
220+
it.setViewControllers(listOf(UIViewController(), composeViewController), false)
221+
}
222+
}
223+
224+
waitUntil {
225+
composeViewController.view.window != null
242226
}
243227
}
244228

@@ -260,6 +244,10 @@ private fun TestContent(
260244
val pagerColors = listOf(Color.Red, Color.Green, Color.Blue)
261245
val pagerState = rememberPagerState(initialPage = currentPage.value) { 3 }
262246

247+
LaunchedEffect(pagerState.currentPage) {
248+
currentPage.value = pagerState.currentPage
249+
}
250+
263251
Column(
264252
modifier = Modifier
265253
.fillMaxSize()

compose/ui/ui/src/uikitInstrumentedTest/kotlin/androidx/compose/ui/test/UIKitInstrumentedTest.kt

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,16 @@ internal class UIKitInstrumentedTest(
265265
content: @Composable () -> Unit
266266
) = setupWindow(
267267
interfaceOrientation = interfaceOrientation,
268-
rootViewController = { createRootViewController(configure, content) }
268+
rootViewController = { createViewControllerHostingCompose(configure, content) }
269269
)
270270

271+
/**
272+
* Installs [rootViewController] into the test window and waits until the Compose scene owned by
273+
* this [UIKitInstrumentedTest] is idle.
274+
*
275+
* Use this when a test needs a custom UIKit hierarchy around Compose, for example a navigation
276+
* controller or a view controller presented by UIKit.
277+
*/
271278
fun setupWindow(
272279
interfaceOrientation: UIInterfaceOrientation = UIInterfaceOrientationPortrait,
273280
rootViewController: () -> UIViewController,
@@ -286,18 +293,26 @@ internal class UIKitInstrumentedTest(
286293
}
287294
}
288295

289-
fun createRootViewController(
296+
/**
297+
* Creates a [UIViewController] that hosts [content] using the container variant selected by
298+
* [useHostingView].
299+
*/
300+
fun createViewControllerHostingCompose(
290301
configure: ComposeContainerConfiguration.() -> Unit = {},
291302
content: @Composable () -> Unit
292303
): UIViewController = if (useHostingView) {
293304
UIViewController().also {
294-
it.view.embedSubview(createHostingView(configure, content))
305+
it.view.embedSubview(createComposeHostingView(configure, content))
295306
}
296307
} else {
297-
createHostingViewController(configure, content)
308+
createComposeHostingViewController(configure, content)
298309
}
299310

300-
fun createHostingView(
311+
/**
312+
* Creates a [ComposeHostingView] for [content] and records it as the active Compose container
313+
* for idleness and redrawer checks.
314+
*/
315+
fun createComposeHostingView(
301316
configure: ComposeUIViewConfiguration.() -> Unit = {},
302317
content: @Composable () -> Unit
303318
): ComposeHostingView {
@@ -314,7 +329,11 @@ internal class UIKitInstrumentedTest(
314329
}
315330
}
316331

317-
fun createHostingViewController(
332+
/**
333+
* Creates a [ComposeHostingViewController] for [content] and records it as the active Compose
334+
* container for idleness and redrawer checks.
335+
*/
336+
fun createComposeHostingViewController(
318337
configure: ComposeUIViewControllerConfiguration.() -> Unit = {},
319338
content: @Composable () -> Unit
320339
): ComposeHostingViewController {
@@ -812,4 +831,4 @@ internal fun UIKitInstrumentedTest.waitForContextMenu() {
812831
} != null
813832
}
814833
delay(500) // wait for toolbar animation
815-
}
834+
}

0 commit comments

Comments
 (0)