Skip to content

Commit 332ea30

Browse files
authored
chore: added test for MapsInLazyColumn (#695)
* chore: added test for MapsInLazyColumn * chore: test for scrolling * chore: test for scrolling
1 parent 9589e49 commit 332ea30

2 files changed

Lines changed: 151 additions & 13 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package com.google.maps.android.compose
2+
3+
import androidx.compose.foundation.lazy.rememberLazyListState
4+
import androidx.compose.runtime.LaunchedEffect
5+
import androidx.compose.runtime.derivedStateOf
6+
import androidx.compose.runtime.getValue
7+
import androidx.compose.runtime.mutableStateOf
8+
import androidx.compose.runtime.remember
9+
import androidx.compose.ui.test.assertIsDisplayed
10+
import androidx.compose.ui.test.junit4.createComposeRule
11+
import androidx.compose.ui.test.onNodeWithTag
12+
import androidx.compose.ui.test.onRoot
13+
import androidx.compose.ui.test.performTouchInput
14+
import androidx.compose.ui.test.swipeUp
15+
import com.google.android.gms.maps.model.CameraPosition
16+
import com.google.android.gms.maps.model.LatLng
17+
import org.junit.Assert.assertTrue
18+
import org.junit.Before
19+
import org.junit.Rule
20+
import org.junit.Test
21+
import java.util.concurrent.CountDownLatch
22+
import java.util.concurrent.TimeUnit
23+
24+
class MapsInLazyColumnTests {
25+
@get:Rule
26+
val composeTestRule = createComposeRule()
27+
28+
private val mapItems = listOf(
29+
MapListItem(id = "1", location = LatLng(1.23, 4.56), zoom = 10f, title = "Item 1"),
30+
MapListItem(id = "2", location = LatLng(7.89, 0.12), zoom = 12f, title = "Item 2"),
31+
MapListItem(id = "3", location = LatLng(3.45, 6.78), zoom = 11f, title = "Item 3"),
32+
MapListItem(id = "4", location = LatLng(9.01, 2.34), zoom = 13f, title = "Item 4"),
33+
MapListItem(id = "5", location = LatLng(5.67, 8.90), zoom = 9f, title = "Item 5"),
34+
MapListItem(id = "6", location = LatLng(4.32, 7.65), zoom = 14f, title = "Item 6"),
35+
MapListItem(id = "7", location = LatLng(8.76, 1.23), zoom = 10f, title = "Item 7"),
36+
MapListItem(id = "8", location = LatLng(2.98, 6.54), zoom = 12f, title = "Item 8"),
37+
MapListItem(id = "9", location = LatLng(7.65, 3.21), zoom = 11f, title = "Item 9"),
38+
MapListItem(id = "10", location = LatLng(0.12, 9.87), zoom = 13f, title = "Item 10"),
39+
)
40+
41+
42+
private lateinit var cameraPositionStates: Map<MapItemId, CameraPositionState>
43+
44+
private fun initMaps() {
45+
check(hasValidApiKey) { "Maps API key not specified" }
46+
47+
composeTestRule.setContent {
48+
val lazyListState = rememberLazyListState()
49+
val visibleMapCount = remember { mutableStateOf(0) }
50+
51+
val visibleItems by remember {
52+
derivedStateOf {
53+
lazyListState.layoutInfo.visibleItemsInfo.size
54+
}
55+
}
56+
57+
LaunchedEffect(visibleItems) {
58+
visibleMapCount.value = visibleItems
59+
}
60+
61+
val countDownLatch = CountDownLatch(visibleMapCount.value)
62+
63+
MapsInLazyColumn(
64+
mapItems,
65+
lazyListState = lazyListState,
66+
onMapLoaded = {
67+
countDownLatch.countDown()
68+
}
69+
)
70+
71+
LaunchedEffect(Unit) {
72+
val mapsLoaded = countDownLatch.await(30, TimeUnit.SECONDS)
73+
assertTrue("Visible maps loaded", mapsLoaded)
74+
}
75+
}
76+
}
77+
78+
@Before
79+
fun setUp() {
80+
cameraPositionStates = mapItems.associate { item ->
81+
item.id to CameraPositionState(
82+
position = CameraPosition.fromLatLngZoom(item.location, item.zoom)
83+
)
84+
}
85+
}
86+
87+
@Test
88+
fun testStartingCameraPositions() {
89+
initMaps()
90+
mapItems.forEach { item ->
91+
item.location.assertEquals(cameraPositionStates[item.id]?.position?.target!!)
92+
}
93+
}
94+
95+
@Test
96+
fun testLazyColumnScrolls_MapPositionsRemain() {
97+
initMaps()
98+
composeTestRule.onRoot().performTouchInput { swipeUp() }
99+
composeTestRule.waitForIdle()
100+
101+
mapItems.forEach { item ->
102+
item.location.assertEquals(cameraPositionStates[item.id]?.position?.target!!)
103+
}
104+
}
105+
106+
@Test
107+
fun testScrollToBottom() {
108+
initMaps()
109+
composeTestRule.onRoot().performTouchInput { swipeUp(durationMillis = 1000) }
110+
composeTestRule.waitForIdle()
111+
//We do not need to check anything on the test, just to make sure the scroll down doesnt crash
112+
}
113+
}

maps-app/src/main/java/com/google/maps/android/compose/MapsInLazyColumnActivity.kt

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.height
2020
import androidx.compose.foundation.layout.padding
2121
import androidx.compose.foundation.layout.systemBarsPadding
2222
import androidx.compose.foundation.lazy.LazyColumn
23+
import androidx.compose.foundation.lazy.LazyListState
2324
import androidx.compose.foundation.lazy.items
2425
import androidx.compose.foundation.lazy.rememberLazyListState
2526
import androidx.compose.foundation.rememberScrollState
@@ -40,7 +41,7 @@ import androidx.compose.runtime.setValue
4041
import androidx.compose.ui.Alignment
4142
import androidx.compose.ui.Modifier
4243
import androidx.compose.ui.graphics.Color
43-
import androidx.compose.ui.text.TextStyle
44+
import androidx.compose.ui.platform.testTag
4445
import androidx.compose.ui.text.font.FontWeight
4546
import androidx.compose.ui.unit.dp
4647
import androidx.compose.ui.unit.sp
@@ -51,12 +52,16 @@ import com.google.android.gms.maps.model.LatLng
5152

5253
private data class CountryLocation(val name: String, val latLng: LatLng, val zoom: Float)
5354

54-
private typealias MapItemId = String
55+
typealias MapItemId = String
5556

5657
// From https://developers.google.com/public-data/docs/canonical/countries_csv
5758
private val countries = listOf(
5859
CountryLocation("Hong Kong", LatLng(22.396428, 114.109497), 5f),
59-
CountryLocation("Madison Square Garden (has indoor mode)", LatLng(40.7504656, -73.9937246), 19.33f),
60+
CountryLocation(
61+
"Madison Square Garden (has indoor mode)",
62+
LatLng(40.7504656, -73.9937246),
63+
19.33f
64+
),
6065
CountryLocation("Bolivia", LatLng(-16.290154, -63.588653), 5f),
6166
CountryLocation("Ecuador", LatLng(-1.831239, -78.183406), 5f),
6267
CountryLocation("Sweden", LatLng(60.128161, 18.643501), 5f),
@@ -74,7 +79,7 @@ private val countries = listOf(
7479
CountryLocation("Burundi", LatLng(-3.373056, 29.918886), 5f)
7580
)
7681

77-
private data class MapListItem(
82+
data class MapListItem(
7883
val title: String,
7984
val location: LatLng,
8085
val zoom: Float,
@@ -98,7 +103,8 @@ class MapsInLazyColumnActivity : ComponentActivity() {
98103
}
99104

100105
Column(
101-
Modifier.fillMaxSize()
106+
Modifier
107+
.fillMaxSize()
102108
.systemBarsPadding(),
103109
) {
104110
Row(
@@ -125,7 +131,7 @@ class MapsInLazyColumnActivity : ComponentActivity() {
125131
}
126132
if (showLazyColumn) {
127133
Box(Modifier.border(1.dp, Color.LightGray.copy(0.5f))) {
128-
MapsInLazyColumn(visibleItems)
134+
MapsInLazyColumn(visibleItems, onMapLoaded = { })
129135
}
130136
}
131137
}
@@ -134,8 +140,15 @@ class MapsInLazyColumnActivity : ComponentActivity() {
134140
}
135141

136142
@Composable
137-
private fun MapsInLazyColumn(mapItems: List<MapListItem>) {
138-
val lazyListState = rememberLazyListState()
143+
fun MapsInLazyColumn(
144+
mapItems: List<MapListItem>,
145+
lazyListState: LazyListState = rememberLazyListState(),
146+
onMapLoaded: () -> Unit
147+
) {
148+
149+
var isMapLoaded by remember { mutableStateOf(false) }
150+
151+
val lazyListState = lazyListState
139152

140153
val cameraPositionStates = mapItems.associate { item ->
141154
item.id to rememberCameraPositionState(
@@ -168,7 +181,10 @@ private fun MapsInLazyColumn(mapItems: List<MapListItem>) {
168181
.height(300.dp),
169182
contentAlignment = Alignment.Center
170183
) {
171-
MapCard(item, cameraPositionState)
184+
MapCard(item, cameraPositionState, onMapLoaded = {
185+
isMapLoaded = true
186+
onMapLoaded()
187+
})
172188
}
173189
}
174190
}
@@ -177,7 +193,11 @@ private fun MapsInLazyColumn(mapItems: List<MapListItem>) {
177193

178194
@OptIn(MapsComposeExperimentalApi::class)
179195
@Composable
180-
private fun MapCard(item: MapListItem, cameraPositionState: CameraPositionState) {
196+
private fun MapCard(
197+
item: MapListItem,
198+
cameraPositionState: CameraPositionState,
199+
onMapLoaded: () -> Unit,
200+
) {
181201
Card(
182202
Modifier.padding(16.dp),
183203
elevation = 4.dp
@@ -192,11 +212,13 @@ private fun MapCard(item: MapListItem, cameraPositionState: CameraPositionState)
192212
var map: GoogleMap? by remember { mutableStateOf(null) }
193213

194214
fun updateIndoorLevel() {
195-
activatedIndoorLevel = map!!.focusedBuilding?.run { levels.getOrNull(activeLevelIndex)?.name }
215+
activatedIndoorLevel =
216+
map!!.focusedBuilding?.run { levels.getOrNull(activeLevelIndex)?.name }
196217
}
197218

198219
Box {
199220
GoogleMap(
221+
modifier = Modifier.testTag("Map"),
200222
onMapClick = {
201223
onMapClickCount++
202224
},
@@ -207,7 +229,10 @@ private fun MapCard(item: MapListItem, cameraPositionState: CameraPositionState)
207229
)
208230
},
209231
cameraPositionState = cameraPositionState,
210-
onMapLoaded = { mapLoaded = true },
232+
onMapLoaded = {
233+
onMapLoaded.invoke()
234+
mapLoaded = true
235+
},
211236
indoorStateChangeListener = object : IndoorStateChangeListener {
212237
override fun onIndoorBuildingFocused() {
213238
super.onIndoorBuildingFocused()
@@ -242,7 +267,7 @@ private fun MapCard(item: MapListItem, cameraPositionState: CameraPositionState)
242267
@Composable
243268
fun TextWithBackground(text: String, fontWeight: FontWeight = FontWeight.Medium) {
244269
Text(
245-
modifier = Modifier.background(Color.White.copy(0.7f)),
270+
modifier = Modifier.background(Color.White.copy(0.7f)).testTag(text),
246271
text = text,
247272
fontWeight = fontWeight,
248273
fontSize = 10.sp

0 commit comments

Comments
 (0)