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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,23 @@ import com.mbta.tid.mbta_app.model.response.NearbyResponse
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.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
import com.mbta.tid.mbta_app.repositories.IRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.IVehiclesRepository
import com.mbta.tid.mbta_app.repositories.IVisitHistoryRepository
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.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 @@ -201,6 +206,9 @@ class NearbyTransitPageTest : KoinTest {
val koinApplication = koinApplication {
modules(
module {
single<IGlobalRepository> {
MockGlobalRepository(response = GlobalResponse(builder))
}
single<ISchedulesRepository> { MockScheduleRepository() }
single<IPredictionsRepository> {
object : IPredictionsRepository {
Expand Down Expand Up @@ -257,6 +265,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 @@ -22,11 +22,14 @@ import com.mbta.tid.mbta_app.repositories.IPinnedRoutesRepository
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.IVisitHistoryRepository
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.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 @@ -229,6 +232,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,14 +13,24 @@ 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.IGlobalRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.IVisitHistoryRepository
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 @@ -31,10 +42,21 @@ 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<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 @@ -74,13 +96,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 @@ -89,10 +112,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