Skip to content

Commit

Permalink
fix(Android): update location with hide maps on (#803)
Browse files Browse the repository at this point in the history
* fix(Android): update location with hide maps on

* use helper function to cut down on boilerplate

* stabilize locally flaky test

* fix nonsensical linter error

the ViewportProvider constructor does not, in fact, return Unit
  • Loading branch information
boringcactus authored Mar 3, 2025
1 parent d528c24 commit 0d31007
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mbta.tid.mbta_app.android.component

import android.location.Location
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
Expand All @@ -18,7 +17,7 @@ class LocationAuthButtonTest {
@Test
fun testShowsWhenPermissionsNotGranted() {

val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()
locationManager.hasPermission = false

composeTestRule.setContent { LocationAuthButton(locationDataManager = locationManager) }
Expand All @@ -29,7 +28,7 @@ class LocationAuthButtonTest {
@Test
fun testHiddenWhenHasPermissions() {

val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()
locationManager.hasPermission = true

composeTestRule.setContent { LocationAuthButton(locationDataManager = locationManager) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package com.mbta.tid.mbta_app.android.location

import android.location.Location
import io.github.dellisd.spatialk.geojson.Position
import kotlinx.coroutines.flow.MutableStateFlow

class MockLocationDataManager(location: Location?) : LocationDataManager() {
override val currentLocation = MutableStateFlow(location)
class MockLocationDataManager(position: Position? = Position(latitude = 0.0, longitude = 0.0)) :
LocationDataManager() {
override val currentLocation = MutableStateFlow(position?.let { MockLocation(it) })

fun moveTo(position: Position?) {
currentLocation.value = position?.let { MockLocation(it) }
}

data class MockLocation(val coordinates: Position) : Location("mock") {
override fun getLatitude() = coordinates.latitude

override fun getLongitude() = coordinates.longitude
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mbta.tid.mbta_app.android.map

import android.location.Location
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.test.assertIsDisplayed
Expand Down Expand Up @@ -32,7 +31,7 @@ class HomeMapViewTests {

@Test
fun testRecenterNotShownWhenNoPermissions() = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = false

Expand Down Expand Up @@ -69,7 +68,7 @@ class HomeMapViewTests {

@Test
fun testRecenterNotShownWhenPermissions(): Unit = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = true
val viewModel =
Expand Down Expand Up @@ -136,7 +135,7 @@ class HomeMapViewTests {

@Test
fun testLocationAuthNotShownWhenPermissions() = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = true

Expand Down Expand Up @@ -171,7 +170,7 @@ class HomeMapViewTests {

@Test
fun testLocationAuthNotShownStopDetails() = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = false

Expand Down Expand Up @@ -206,7 +205,7 @@ class HomeMapViewTests {

@Test
fun testOverviewNotShownWhenNoPermissionsStopDetails() = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = false

Expand Down Expand Up @@ -243,7 +242,7 @@ class HomeMapViewTests {

@Test
fun testOverviewShownOnStopDetails(): Unit = runBlocking {
val locationManager = MockLocationDataManager(Location("mock"))
val locationManager = MockLocationDataManager()

locationManager.hasPermission = true
val viewModel =
Expand Down Expand Up @@ -284,7 +283,7 @@ class HomeMapViewTests {
sheetPadding = PaddingValues(0.dp),
lastNearbyTransitLocation = null,
nearbyTransitSelectingLocationState = mutableStateOf(false),
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
viewportProvider = viewportProvider,
currentNavEntry = null,
handleStopNavigation = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.mbta.tid.mbta_app.android.nearbyTransit

import MockRepositories
import android.app.Activity
import android.location.Location
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -292,7 +291,7 @@ class NearbyTransitPageTest : KoinTest {
nearbyTransitSelectingLocationState =
remember { mutableStateOf(false) },
scaffoldState = rememberBottomSheetScaffoldState(),
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
viewportProvider = viewportProvider,
),
false,
Expand All @@ -310,6 +309,7 @@ class NearbyTransitPageTest : KoinTest {
}
}

composeTestRule.waitUntilExactlyOneExists(hasContentDescription("Mapbox Attribution"))
composeTestRule.onNodeWithContentDescription("Mapbox Attribution").assertIsDisplayed()
composeTestRule.waitUntilDoesNotExist(hasContentDescription("Loading..."))
composeTestRule
Expand Down Expand Up @@ -397,7 +397,7 @@ class NearbyTransitPageTest : KoinTest {
nearbyTransitSelectingLocationState =
remember { mutableStateOf(false) },
scaffoldState = rememberBottomSheetScaffoldState(),
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
viewportProvider = viewportProvider,
),
false,
Expand Down Expand Up @@ -443,7 +443,7 @@ class NearbyTransitPageTest : KoinTest {
nearbyTransitSelectingLocationState =
remember { mutableStateOf(false) },
scaffoldState = rememberBottomSheetScaffoldState(),
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
viewportProvider = viewportProvider,
),
false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mbta.tid.mbta_app.android.onboarding

import android.location.Location
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
Expand All @@ -26,7 +25,7 @@ class OnboardingScreenViewTest {
@Test
fun testLocationFlow() {
var advanced = false
val locationDataManager = MockLocationDataManager(Location("mock"))
val locationDataManager = MockLocationDataManager()
composeTestRule.setContent {
OnboardingScreenView(
screen = OnboardingScreen.Location,
Expand Down Expand Up @@ -63,7 +62,7 @@ class OnboardingScreenViewTest {
OnboardingScreenView(
screen = OnboardingScreen.StationAccessibility,
advance = { advanced = true },
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
settingsRepository = settingsRepo
)
}
Expand Down Expand Up @@ -96,7 +95,7 @@ class OnboardingScreenViewTest {
OnboardingScreenView(
screen = OnboardingScreen.HideMaps,
advance = { advanced = true },
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
settingsRepository = settingsRepo
)
}
Expand All @@ -120,7 +119,7 @@ class OnboardingScreenViewTest {
OnboardingScreenView(
screen = OnboardingScreen.Feedback,
advance = { advanced = true },
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
)
}
composeTestRule
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.mbta.tid.mbta_app.android.pages

import MockRepositories
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import com.mapbox.maps.extension.compose.animation.viewport.MapViewportState
import com.mbta.tid.mbta_app.analytics.Analytics
import com.mbta.tid.mbta_app.analytics.MockAnalytics
import com.mbta.tid.mbta_app.android.MainApplication
import com.mbta.tid.mbta_app.android.component.sheet.rememberBottomSheetScaffoldState
import com.mbta.tid.mbta_app.android.location.MockLocationDataManager
import com.mbta.tid.mbta_app.android.location.ViewportProvider
import com.mbta.tid.mbta_app.dependencyInjection.repositoriesModule
import com.mbta.tid.mbta_app.model.ObjectCollectionBuilder
import com.mbta.tid.mbta_app.model.RoutePattern
import com.mbta.tid.mbta_app.model.RouteType
import com.mbta.tid.mbta_app.model.response.AlertsStreamDataResponse
import com.mbta.tid.mbta_app.model.response.GlobalResponse
import com.mbta.tid.mbta_app.model.response.PredictionsByStopJoinResponse
import com.mbta.tid.mbta_app.model.response.ScheduleResponse
import com.mbta.tid.mbta_app.repositories.INearbyRepository
import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.MockGlobalRepository
import com.mbta.tid.mbta_app.repositories.MockPredictionsRepository
import com.mbta.tid.mbta_app.repositories.MockScheduleRepository
import com.mbta.tid.mbta_app.repositories.MockSettingsRepository
import com.mbta.tid.mbta_app.repositories.NearbyRepository
import com.mbta.tid.mbta_app.repositories.Settings
import org.junit.Rule
import org.junit.Test
import org.koin.androidx.compose.koinViewModel
import org.koin.compose.KoinContext
import org.koin.dsl.koinApplication
import org.koin.dsl.module

class NearbyTransitPageTest {
@get:Rule val composeTestRule = createComposeRule()

@OptIn(ExperimentalMaterial3Api::class, ExperimentalTestApi::class)
@Test
fun testHideMapsLocationUpdates() {
val objects = ObjectCollectionBuilder()

val stop1 =
objects.stop {
latitude = 1.0
longitude = 1.0
name = "Stop A"
vehicleType = RouteType.BUS
}
val stop2 =
objects.stop {
latitude = 2.0
longitude = 2.0
name = "Stop B"
vehicleType = RouteType.BUS
}
val route = objects.route { type = RouteType.BUS }
objects.routePattern(route) {
typicality = RoutePattern.Typicality.Typical
representativeTrip { stopIds = listOf(stop1.id, stop2.id) }
}

val alertData = AlertsStreamDataResponse(objects)
val globalResponse = GlobalResponse(objects)

val koin = koinApplication {
modules(
repositoriesModule(
MockRepositories.buildWithDefaults(
global = MockGlobalRepository(globalResponse),
schedules = MockScheduleRepository(ScheduleResponse(objects))
)
),
module {
single<Analytics> { MockAnalytics() }
single<INearbyRepository> { NearbyRepository() }
single<IPredictionsRepository> {
MockPredictionsRepository(
connectV2Response = PredictionsByStopJoinResponse(objects)
)
}
single<ISettingsRepository> {
MockSettingsRepository(mapOf(Settings.HideMaps to true))
}
},
MainApplication.koinViewModelModule
)
}

val locationDataManager = MockLocationDataManager(stop1.position)
val viewportProvider = ViewportProvider(MapViewportState())

composeTestRule.setContent {
KoinContext(koin.koin) {
NearbyTransitPage(
nearbyTransit =
NearbyTransit(
alertData = alertData,
globalResponse = globalResponse,
hideMaps = true,
lastNearbyTransitLocationState = remember { mutableStateOf(null) },
nearbyTransitSelectingLocationState =
remember { mutableStateOf(false) },
scaffoldState = rememberBottomSheetScaffoldState(),
locationDataManager = locationDataManager,
viewportProvider = viewportProvider
),
navBarVisible = false,
showNavBar = {},
hideNavBar = {},
bottomBar = {},
searchResultsViewModel = koinViewModel()
)
}
}

composeTestRule.waitUntilExactlyOneExists(hasText(stop1.name))
composeTestRule.onNodeWithText(stop1.name).assertIsDisplayed()

locationDataManager.moveTo(stop2.position)

composeTestRule.waitUntilExactlyOneExists(hasText(stop2.name))
composeTestRule.onNodeWithText(stop2.name).assertIsDisplayed()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mbta.tid.mbta_app.android.pages

import android.location.Location
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
Expand Down Expand Up @@ -28,7 +27,7 @@ class OnboardingPageTest {
composeTestRule.setContent {
OnboardingPage(
screens = OnboardingScreen.entries,
locationDataManager = MockLocationDataManager(Location("mock")),
locationDataManager = MockLocationDataManager(),
onFinish = { finished = true },
onboardingRepository = onboardingRepository,
skipLocationDialogue = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ fun NearbyTransitPage(
outerSheetPadding ->
if (nearbyTransit.hideMaps) {
val isNearbyTransit = currentNavEntry?.let { it is SheetRoutes.NearbyTransit } ?: true

LaunchedEffect(null) {
nearbyTransit.locationDataManager.currentLocation.collect { location ->
nearbyTransit.viewportProvider.updateCameraState(location)
}
}

SearchBarOverlay(
searchExpanded,
::handleSearchExpandedChange,
Expand Down

0 comments on commit 0d31007

Please sign in to comment.