Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jvc android search recent stops #622

Merged
merged 9 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.mbta.tid.mbta_app.model.response.PredictionsByStopJoinResponse
import com.mbta.tid.mbta_app.model.response.PredictionsByStopMessageResponse
import com.mbta.tid.mbta_app.model.response.PredictionsStreamDataResponse
import com.mbta.tid.mbta_app.repositories.IErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.IGlobalRepository
import com.mbta.tid.mbta_app.repositories.INearbyRepository
import com.mbta.tid.mbta_app.repositories.IPinnedRoutesRepository
import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
Expand All @@ -54,13 +55,17 @@ import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.IVehiclesRepository
import com.mbta.tid.mbta_app.repositories.IVisitHistoryRepository
import com.mbta.tid.mbta_app.repositories.MockErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.MockGlobalRepository
import com.mbta.tid.mbta_app.repositories.MockRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.MockScheduleRepository
import com.mbta.tid.mbta_app.repositories.MockSearchResultRepository
import com.mbta.tid.mbta_app.repositories.MockSettingsRepository
import com.mbta.tid.mbta_app.repositories.MockVehiclesRepository
import com.mbta.tid.mbta_app.repositories.MockVisitHistoryRepository
import com.mbta.tid.mbta_app.usecases.TogglePinnedRouteUsecase
import com.mbta.tid.mbta_app.usecases.VisitHistoryUsecase
import io.github.dellisd.spatialk.geojson.Position
import kotlin.time.Duration.Companion.minutes
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -207,6 +212,9 @@ class NearbyTransitPageTest : KoinTest {
module {
single<ISettingsRepository> { MockSettingsRepository() }
single<IErrorBannerStateRepository> { MockErrorBannerStateRepository() }
single<IGlobalRepository> {
MockGlobalRepository(response = GlobalResponse(builder))
}
single<ISchedulesRepository> { MockScheduleRepository() }
single<IPredictionsRepository> {
object : IPredictionsRepository {
Expand Down Expand Up @@ -263,6 +271,8 @@ class NearbyTransitPageTest : KoinTest {
single<IVehiclesRepository> { MockVehiclesRepository() }
single<ISearchResultRepository> { MockSearchResultRepository() }
viewModelOf(::NearbyTransitViewModel)
single<IVisitHistoryRepository> { MockVisitHistoryRepository() }
single<VisitHistoryUsecase> { VisitHistoryUsecase(get()) }
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
import com.mbta.tid.mbta_app.repositories.IRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.IVisitHistoryRepository
import com.mbta.tid.mbta_app.repositories.MockErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.MockNearbyRepository
import com.mbta.tid.mbta_app.repositories.MockPredictionsRepository
import com.mbta.tid.mbta_app.repositories.MockRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.MockScheduleRepository
import com.mbta.tid.mbta_app.repositories.MockSettingsRepository
import com.mbta.tid.mbta_app.repositories.MockVisitHistoryRepository
import com.mbta.tid.mbta_app.usecases.TogglePinnedRouteUsecase
import com.mbta.tid.mbta_app.usecases.VisitHistoryUsecase
import io.github.dellisd.spatialk.geojson.Position
import kotlin.time.Duration.Companion.minutes
import kotlinx.datetime.Instant
Expand Down Expand Up @@ -236,6 +239,8 @@ class NearbyTransitViewTest : KoinTest {
single<IRailRouteShapeRepository> { MockRailRouteShapeRepository() }
single<TogglePinnedRouteUsecase> { TogglePinnedRouteUsecase(get()) }
viewModelOf(::NearbyTransitViewModel)
single<IVisitHistoryRepository> { MockVisitHistoryRepository() }
single<VisitHistoryUsecase> { VisitHistoryUsecase(get()) }
}
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mbta.tid.mbta_app.android.search

import android.os.Bundle
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.mutableStateOf
Expand All @@ -12,16 +13,26 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.requestFocus
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
import com.mbta.tid.mbta_app.history.Visit
import com.mbta.tid.mbta_app.history.VisitHistory
import com.mbta.tid.mbta_app.model.ObjectCollectionBuilder
import com.mbta.tid.mbta_app.model.RouteType
import com.mbta.tid.mbta_app.model.SearchResults
import com.mbta.tid.mbta_app.model.StopResult
import com.mbta.tid.mbta_app.model.StopResultRoute
import com.mbta.tid.mbta_app.model.response.ApiResult
import com.mbta.tid.mbta_app.model.response.GlobalResponse
import com.mbta.tid.mbta_app.repositories.IErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.IGlobalRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.IVisitHistoryRepository
import com.mbta.tid.mbta_app.repositories.MockErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.MockGlobalRepository
import com.mbta.tid.mbta_app.repositories.MockVisitHistoryRepository
import com.mbta.tid.mbta_app.usecases.VisitHistoryUsecase
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
Expand All @@ -33,11 +44,23 @@ import org.koin.test.KoinTest
@ExperimentalTestApi
@ExperimentalMaterial3Api
class SearchBarOverlayTest : KoinTest {
val mockVisitHistoryRepository = MockVisitHistoryRepository()
val builder = ObjectCollectionBuilder()
val visitedStop =
builder.stop {
id = "visitedStopId"
name = "visitedStopName"
}
val koinApplication = koinApplication {
modules(
module {
single<IErrorBannerStateRepository> { MockErrorBannerStateRepository() }
single<IGlobalRepository> { MockGlobalRepository() }
single<IGlobalRepository> {
MockGlobalRepository(response = GlobalResponse(builder))
}
single<IVisitHistoryRepository> { mockVisitHistoryRepository }
single<VisitHistoryUsecase> { VisitHistoryUsecase(get()) }
single<ISearchResultRepository> {
object : ISearchResultRepository {
override suspend fun getSearchResults(
Expand Down Expand Up @@ -77,13 +100,14 @@ class SearchBarOverlayTest : KoinTest {
@Test
fun testSearchBarOverlayBehavesCorrectly() = runTest {
val navigated = mutableStateOf(false)
var navBackStackEntry = mutableStateOf<NavBackStackEntry?>(null)

composeTestRule.setContent {
KoinContext(koinApplication.koin) {
val focusRequester = remember { FocusRequester() }
SearchBarOverlay(
onStopNavigation = { navigated.value = true },
currentNavEntry = null,
currentNavEntry = navBackStackEntry.value,
inputFieldFocusRequester = focusRequester,
) {
Text("Content")
Expand All @@ -92,10 +116,30 @@ class SearchBarOverlayTest : KoinTest {
}

composeTestRule.onNodeWithText("Content").assertExists()

// Simulate navigating to a stop and back
runBlocking {
mockVisitHistoryRepository.setVisitHistory(
VisitHistory().apply { add(Visit.StopVisit(visitedStop.id)) }
)
}
navBackStackEntry.value =
NavBackStackEntry.create(
context = null,
arguments = Bundle().apply { putString("stopId", "visitedStopId") },
destination = NavDestination("stop")
)
composeTestRule.awaitIdle()
navBackStackEntry.value = null

composeTestRule.waitUntilAtLeastOneExists(hasText("Search by stop"))
val searchNode = composeTestRule.onNodeWithText("Search by stop")
searchNode.assertExists()
searchNode.requestFocus()
composeTestRule.awaitIdle()
composeTestRule.onNodeWithText("Recently Viewed").assertExists()
composeTestRule.waitUntilAtLeastOneExists(hasText(visitedStop.name))
composeTestRule.onNodeWithText(visitedStop.name).assertExists()

searchNode.performTextInput("sto")
composeTestRule.waitUntilAtLeastOneExists(hasText("stopName"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
package com.mbta.tid.mbta_app.android.state

import androidx.compose.ui.test.junit4.createComposeRule
import com.mbta.tid.mbta_app.history.Visit
import com.mbta.tid.mbta_app.history.VisitHistory
import com.mbta.tid.mbta_app.model.ObjectCollectionBuilder
import com.mbta.tid.mbta_app.model.RouteType
import com.mbta.tid.mbta_app.model.SearchResults
import com.mbta.tid.mbta_app.model.StopResult
import com.mbta.tid.mbta_app.model.StopResultRoute
import com.mbta.tid.mbta_app.model.response.ApiResult
import com.mbta.tid.mbta_app.model.response.GlobalResponse
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.MockVisitHistoryRepository
import com.mbta.tid.mbta_app.usecases.VisitHistoryUsecase
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test

class GetSearchResultTest {
val builder = ObjectCollectionBuilder()
val visitedStop =
builder.stop {
id = "visitedStopId"
name = "visitedStopName"
}

val searchResults =
SearchResults(
routes = emptyList(),
Expand Down Expand Up @@ -39,26 +53,42 @@ class GetSearchResultTest {
@Test
fun testSearchResults() = runTest {
var actualSearchResultsViewModel: SearchResultsViewModel? = null
val mockVisitHistoryRepository = MockVisitHistoryRepository()
val visitHistory = VisitHistory()

runBlocking {
visitHistory.add(Visit.StopVisit(visitedStop.id))
mockVisitHistoryRepository.setVisitHistory(visitHistory)
}

composeTestRule.setContent {
actualSearchResultsViewModel =
getSearchResultsVm(
GlobalResponse(builder),
object : ISearchResultRepository {
override suspend fun getSearchResults(
query: String
): ApiResult<SearchResults>? {
return ApiResult.Ok(searchResults)
}
}
},
VisitHistoryUsecase(mockVisitHistoryRepository)
)
}

composeTestRule.waitUntil { actualSearchResultsViewModel != null }
composeTestRule.awaitIdle()

actualSearchResultsViewModel?.getSearchResults("query")

actualSearchResultsViewModel?.getSearchResults("")
composeTestRule.waitUntil { actualSearchResultsViewModel?.searchResults?.value != null }
assert(
actualSearchResultsViewModel?.searchResults?.value?.stops?.first()?.id == visitedStop.id
)

actualSearchResultsViewModel?.getSearchResults("query")
composeTestRule.waitUntil {
actualSearchResultsViewModel?.searchResults?.value == searchResults
}
assert(actualSearchResultsViewModel?.searchResults?.value == searchResults)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,25 @@ fun ContentView(
hideNavBar = { navBarVisible = false },
bottomBar = {
if (navBarVisible) {
BottomNavBar(navController = navController)
BottomNavBar(
currentDestination = navController.currentBackStackEntry?.destination,
navigateToNearby = { navController.navigate(Routes.NearbyTransit) },
navigateToMore = { navController.navigate(Routes.More) }
)
}
}
)
}
composable<Routes.More> {
MorePage(bottomBar = { BottomNavBar(navController = navController) })
MorePage(
bottomBar = {
BottomNavBar(
currentDestination = navController.currentBackStackEntry?.destination,
navigateToNearby = { navController.navigate(Routes.NearbyTransit) },
navigateToMore = { navController.navigate(Routes.More) }
)
}
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package com.mbta.tid.mbta_app.android

import kotlinx.serialization.Serializable

object Routes {
@Serializable object NearbyTransit
sealed class Routes {
@Serializable object NearbyTransit : Routes()

@Serializable object More
@Serializable object More : Routes()
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.NavDestination
import com.mbta.tid.mbta_app.android.R
import com.mbta.tid.mbta_app.android.Routes

@Composable
fun BottomNavBar(navController: NavHostController) {

val currentDestination = navController.currentBackStackEntry?.destination

fun BottomNavBar(
currentDestination: NavDestination?,
navigateToNearby: () -> Unit,
navigateToMore: () -> Unit
) {
BottomAppBar(
modifier = Modifier.height(83.dp),
containerColor = MaterialTheme.colorScheme.surfaceVariant,
actions = {
BottomNavIconButton(
modifier = Modifier.fillMaxSize().weight(1f),
onClick = { navController.navigate(Routes.NearbyTransit) },
onClick = navigateToNearby,
icon = R.drawable.map_pin,
label = stringResource(R.string.nearby_transit_link),
// currentDestination?.hiearchy?.any { it.hasRoute(Routes.NearbyTransit::class)
Expand All @@ -34,7 +34,7 @@ fun BottomNavBar(navController: NavHostController) {

BottomNavIconButton(
modifier = Modifier.fillMaxSize().weight(1f),
onClick = { navController.navigate(Routes.More) },
onClick = navigateToMore,
icon = R.drawable.more,
label = stringResource(R.string.more_link),
active = currentDestination?.route?.contains("More") ?: true
Expand Down
Loading
Loading