@@ -13,6 +13,7 @@ import androidx.compose.runtime.setValue
1313import androidx.compose.ui.Modifier
1414import androidx.compose.ui.graphics.Color
1515import androidx.compose.ui.graphics.toArgb
16+ import androidx.compose.ui.platform.LocalDensity
1617import androidx.compose.ui.platform.testTag
1718import androidx.compose.ui.test.SemanticsNodeInteraction
1819import androidx.compose.ui.test.junit4.ComposeContentTestRule
@@ -27,7 +28,6 @@ import androidx.core.content.ContextCompat
2728import androidx.core.graphics.drawable.toBitmap
2829import com.mapbox.geojson.Point
2930import com.mapbox.maps.Style
30- import com.mapbox.maps.coroutine.awaitStyle
3131import com.mapbox.maps.extension.compose.MapEffect
3232import com.mapbox.maps.extension.compose.MapboxMap
3333import com.mapbox.maps.extension.compose.MapboxMapComposable
@@ -59,7 +59,6 @@ import com.mapbox.maps.plugin.annotation.generated.PolygonAnnotationOptions
5959import com.mapbox.maps.plugin.annotation.generated.PolylineAnnotation
6060import com.mapbox.maps.plugin.annotation.generated.PolylineAnnotationOptions
6161import org.junit.Assert.assertEquals
62- import org.junit.Ignore
6362import org.junit.Rule
6463import org.junit.Test
6564
@@ -96,11 +95,11 @@ public class AnnotationTests {
9695 }
9796
9897 composeTestRule.onNodeWithTag(testTag).performClick()
99- composeTestRule.waitUntil { clickedAnnotation != null }
98+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
10099 assertEquals(SINGLE_POINT , clickedAnnotation!! .point)
101100
102101 composeTestRule.onNodeWithTag(testTag).performLongClick()
103- composeTestRule.waitUntil(timeoutMillis = 5000L ) { longClickedAnnotation != null }
102+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
104103 assertEquals(SINGLE_POINT , longClickedAnnotation!! .point)
105104 }
106105
@@ -145,12 +144,12 @@ public class AnnotationTests {
145144 }
146145 }
147146 composeTestRule.onNodeWithTag(testTag).performClick()
148- composeTestRule.waitUntil { clickedAnnotation != null }
147+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
149148 assertEquals(CLUSTER_POINTS [2 ], clickedAnnotation!! .point)
150149 assertEquals(Color .Red .toArgb(), clickedAnnotation!! .circleColorInt)
151150
152151 composeTestRule.onNodeWithTag(testTag).performLongClick()
153- composeTestRule.waitUntil(5000L ) { longClickedAnnotation != null }
152+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
154153 assertEquals(CLUSTER_POINTS [2 ], longClickedAnnotation!! .point)
155154 assertEquals(Color .Red .toArgb(), longClickedAnnotation!! .circleColorInt)
156155 }
@@ -201,21 +200,20 @@ public class AnnotationTests {
201200 }
202201 }
203202 composeTestRule.onNodeWithTag(testTag).performClick()
204- composeTestRule.waitUntil { actualPointsInClickedCluster != null }
203+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { actualPointsInClickedCluster != null }
205204 assertEquals(expectedPointsInCluster, actualPointsInClickedCluster)
206205
207206 composeTestRule.onNodeWithTag(testTag).performLongClick()
208- composeTestRule.waitUntil(5000L ) { actualPointsInLongClickedCluster != null }
207+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { actualPointsInLongClickedCluster != null }
209208 assertEquals(expectedPointsInCluster, actualPointsInLongClickedCluster)
210209 }
211210
212211 @Test
213- @Ignore(" Flaky test, times out" )
214212 public fun testPointAnnotation () {
215213 var clickedAnnotation: PointAnnotation ? = null
216214 var longClickedAnnotation: PointAnnotation ? = null
217215 val testTag = " point_annotation"
218-
216+ val annotationIconAnchor = IconAnchor . BOTTOM_LEFT
219217 setMapContent(
220218 cameraCenter = HELSINKI ,
221219 annotationPoint = SINGLE_POINT ,
@@ -226,7 +224,7 @@ public class AnnotationTests {
226224 point = SINGLE_POINT
227225 ) {
228226 iconImage = icon
229- iconAnchor = IconAnchor . BOTTOM_LEFT
227+ iconAnchor = annotationIconAnchor
230228 interactionsState.onClicked {
231229 clickedAnnotation = it
232230 true
@@ -239,12 +237,12 @@ public class AnnotationTests {
239237 }
240238
241239 composeTestRule.onNodeWithTag(testTag).performClick()
242- composeTestRule.waitUntil { clickedAnnotation != null }
240+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
243241 assertEquals(SINGLE_POINT , clickedAnnotation!! .point)
244- assertEquals(IconAnchor . BOTTOM_LEFT , clickedAnnotation!! .iconAnchor)
242+ assertEquals(annotationIconAnchor , clickedAnnotation!! .iconAnchor)
245243
246244 composeTestRule.onNodeWithTag(testTag).performLongClick()
247- composeTestRule.waitUntil(timeoutMillis = 5000L ) { longClickedAnnotation != null }
245+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
248246 assertEquals(SINGLE_POINT , longClickedAnnotation!! .point)
249247 }
250248
@@ -300,12 +298,12 @@ public class AnnotationTests {
300298 }
301299
302300 composeTestRule.onNodeWithTag(testTag).performClick()
303- composeTestRule.waitUntil { clickedAnnotation != null }
301+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
304302 assertEquals(CLUSTER_POINTS [2 ], clickedAnnotation!! .point)
305303 assertEquals(TextAnchor .TOP_LEFT , clickedAnnotation!! .textAnchor)
306304
307305 composeTestRule.onNodeWithTag(testTag).performLongClick()
308- composeTestRule.waitUntil(5000L ) { longClickedAnnotation != null }
306+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
309307 assertEquals(CLUSTER_POINTS [2 ], longClickedAnnotation!! .point)
310308 }
311309
@@ -365,11 +363,11 @@ public class AnnotationTests {
365363 }
366364
367365 composeTestRule.onNodeWithTag(testTag).performClick()
368- composeTestRule.waitUntil { actualPointsInClickedCluster != null }
366+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { actualPointsInClickedCluster != null }
369367 assertEquals(expectedPointsInCluster, actualPointsInClickedCluster)
370368
371369 composeTestRule.onNodeWithTag(testTag).performLongClick()
372- composeTestRule.waitUntil(5000L ) { actualPointsInLongClickedCluster != null }
370+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { actualPointsInLongClickedCluster != null }
373371 assertEquals(expectedPointsInCluster, actualPointsInLongClickedCluster)
374372 }
375373
@@ -381,7 +379,7 @@ public class AnnotationTests {
381379
382380 setMapContent(
383381 cameraCenter = HELSINKI ,
384- annotationPoint = POLYGON_POINTS .first().first() ,
382+ annotationPoint = POLYGON_CENTER ,
385383 testTag = testTag
386384 ) {
387385 PolygonAnnotation (
@@ -399,12 +397,12 @@ public class AnnotationTests {
399397 }
400398 }
401399 composeTestRule.onNodeWithTag(testTag).performClick()
402- composeTestRule.waitUntil { clickedAnnotation != null }
400+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
403401 assertEquals(Color .Red .toArgb(), clickedAnnotation!! .fillColorInt)
404402 assertEquals(POLYGON_POINTS , clickedAnnotation!! .points)
405403
406404 composeTestRule.onNodeWithTag(testTag).performLongClick()
407- composeTestRule.waitUntil(timeoutMillis = 5000L ) { longClickedAnnotation != null }
405+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
408406 assertEquals(Color .Red .toArgb(), clickedAnnotation!! .fillColorInt)
409407 assertEquals(POLYGON_POINTS , longClickedAnnotation!! .points)
410408 }
@@ -417,7 +415,7 @@ public class AnnotationTests {
417415
418416 setMapContent(
419417 cameraCenter = HELSINKI ,
420- annotationPoint = POLYGON_POINTS .first().first() ,
418+ annotationPoint = POLYGON_CENTER ,
421419 testTag = testTag
422420 ) {
423421 PolygonAnnotationGroup (
@@ -439,18 +437,17 @@ public class AnnotationTests {
439437 }
440438 }
441439 composeTestRule.onNodeWithTag(testTag).performClick()
442- composeTestRule.waitUntil { clickedAnnotation != null }
440+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
443441 assertEquals(Color .Yellow .toArgb(), clickedAnnotation!! .fillColorInt)
444442 assertEquals(POLYGON_POINTS , clickedAnnotation!! .points)
445443
446444 composeTestRule.onNodeWithTag(testTag).performLongClick()
447- composeTestRule.waitUntil(timeoutMillis = 50000L ) { longClickedAnnotation != null }
445+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
448446 assertEquals(Color .Yellow .toArgb(), clickedAnnotation!! .fillColorInt)
449447 assertEquals(POLYGON_POINTS , longClickedAnnotation!! .points)
450448 }
451449
452450 @Test
453- @Ignore(" Flaky test, times out" )
454451 public fun testPolylineAnnotation () {
455452 var clickedAnnotation: PolylineAnnotation ? = null
456453 var longClickedAnnotation: PolylineAnnotation ? = null
@@ -476,12 +473,12 @@ public class AnnotationTests {
476473 }
477474 }
478475 composeTestRule.onNodeWithTag(testTag).performClick()
479- composeTestRule.waitUntil { clickedAnnotation != null }
476+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
480477 assertEquals(Color .Red .toArgb(), clickedAnnotation!! .lineColorInt)
481478 assertEquals(POLYLINE_POINTS , clickedAnnotation!! .points)
482479
483480 composeTestRule.onNodeWithTag(testTag).performLongClick()
484- composeTestRule.waitUntil(5000 ) { longClickedAnnotation != null }
481+ composeTestRule.waitUntil(WAIT_TIMEOUT ) { longClickedAnnotation != null }
485482 assertEquals(Color .Red .toArgb(), longClickedAnnotation!! .lineColorInt)
486483 assertEquals(POLYLINE_POINTS , longClickedAnnotation!! .points)
487484 }
@@ -516,12 +513,12 @@ public class AnnotationTests {
516513 }
517514 }
518515 composeTestRule.onNodeWithTag(testTag).performClick()
519- composeTestRule.waitUntil { clickedAnnotation != null }
516+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { clickedAnnotation != null }
520517 assertEquals(Color .Blue .toArgb(), clickedAnnotation!! .lineColorInt)
521518 assertEquals(POLYLINE_POINTS , clickedAnnotation!! .points)
522519
523520 composeTestRule.onNodeWithTag(testTag).performLongClick()
524- composeTestRule.waitUntil { longClickedAnnotation != null }
521+ composeTestRule.waitUntil( WAIT_TIMEOUT ) { longClickedAnnotation != null }
525522 assertEquals(Color .Blue .toArgb(), longClickedAnnotation!! .lineColorInt)
526523 assertEquals(POLYLINE_POINTS , longClickedAnnotation!! .points)
527524 }
@@ -538,6 +535,7 @@ public class AnnotationTests {
538535 annotationBlock : @MapboxMapComposable @Composable () -> Unit ,
539536 ) {
540537 composeTestRule.setContent {
538+ val density = LocalDensity .current
541539 // screen coordinate of given annotation which can be used for adding Box with testTag
542540 var offset: IntOffset ? by remember {
543541 mutableStateOf(null )
@@ -557,9 +555,16 @@ public class AnnotationTests {
557555 ) {
558556 annotationBlock()
559557 MapEffect (Unit ) { mapView ->
560- mapView.mapboxMap.awaitStyle()
561- val screenCoordinate = mapView.mapboxMap.pixelForCoordinate(annotationPoint)
562- offset = IntOffset (screenCoordinate.x.toInt(), screenCoordinate.y.toInt())
558+ mapView.mapboxMap.subscribeMapLoaded {
559+ val screenCoordinate = mapView.mapboxMap.pixelForCoordinate(annotationPoint)
560+ // Center the box on the coordinate
561+ val boxSizePx = with (density) { 5 .dp.roundToPx() }
562+ val halfSize = boxSizePx / 2
563+ offset = IntOffset (
564+ screenCoordinate.x.toInt() - halfSize,
565+ screenCoordinate.y.toInt() - halfSize
566+ )
567+ }
563568 }
564569 }
565570 if (offset != null ) {
@@ -574,7 +579,7 @@ public class AnnotationTests {
574579 }
575580 }
576581
577- composeTestRule.waitUntil(5_000 ) {
582+ composeTestRule.waitUntil(WAIT_TIMEOUT ) {
578583 composeTestRule.onAllNodesWithTag(testTag)
579584 .fetchSemanticsNodes().size == 1
580585 }
@@ -592,6 +597,8 @@ public class AnnotationTests {
592597
593598 public companion object {
594599 public const val MAP_TEST_TAG : String = " map_tag"
600+ // Increase timeout for Firebase/CI environments
601+ public const val WAIT_TIMEOUT : Long = 10_000L
595602 public const val ZOOM : Double = 10.0
596603 private const val INTERVAL = 0.01
597604 public val CLUSTER_POINTS : List <Point > by lazy {
@@ -619,6 +626,12 @@ public class AnnotationTests {
619626 )
620627 )
621628
629+ // Center point of POLYGON_POINTS for click testing
630+ private val POLYGON_CENTER = Point .fromLngLat(
631+ (24.9349 + 24.9429 ) / 2 ,
632+ (60.1725 + 60.1673 ) / 2
633+ )
634+
622635 private val POLYGON_POINTS_2 = listOf (
623636 listOf (
624637 Point .fromLngLat(24.9349 , 60.1825 ),
0 commit comments