diff --git a/app/src/commonMain/kotlin/id/gdg/app/AppViewModel.kt b/app/src/commonMain/kotlin/id/gdg/app/AppViewModel.kt index 3b58507..1d2ee7b 100644 --- a/app/src/commonMain/kotlin/id/gdg/app/AppViewModel.kt +++ b/app/src/commonMain/kotlin/id/gdg/app/AppViewModel.kt @@ -59,7 +59,7 @@ class AppViewModel( ChapterUiModel.Default ) - private var _eventDetailUiState = MutableStateFlow(EventDetailUiModel()) + private var _eventDetailUiState = MutableStateFlow(EventDetailUiModel.Empty) val eventDetailUiState get() = _eventDetailUiState.asStateFlow() init { @@ -135,12 +135,17 @@ class AppViewModel( } private fun fetchEventDetail(eventId: Int) { + _eventDetailUiState.update { it.copy(state = UiState.Loading) } + viewModelScope.launch { val result = eventDetailUseCase(eventId) withContext(Dispatchers.Main) { _eventDetailUiState.update { - it.copy(detail = result.getOrNull()) + it.copy( + state = result.asUiState(), + detail = result.getOrNull() + ) } } } diff --git a/app/src/commonMain/kotlin/id/gdg/app/ui/state/EventDetailUiModel.kt b/app/src/commonMain/kotlin/id/gdg/app/ui/state/EventDetailUiModel.kt index 0112798..5afac40 100644 --- a/app/src/commonMain/kotlin/id/gdg/app/ui/state/EventDetailUiModel.kt +++ b/app/src/commonMain/kotlin/id/gdg/app/ui/state/EventDetailUiModel.kt @@ -1,7 +1,17 @@ package id.gdg.app.ui.state +import id.gdg.app.ui.state.common.UiState import id.gdg.event.model.EventDetailModel data class EventDetailUiModel( + val state: UiState, val detail: EventDetailModel? = null -) \ No newline at end of file +) { + + companion object { + val Empty get() = EventDetailUiModel( + state = UiState.Loading, + detail = null + ) + } +} \ No newline at end of file diff --git a/app/src/commonTest/kotlin/id/gdg/app/AppViewModelTest.kt b/app/src/commonTest/kotlin/id/gdg/app/AppViewModelTest.kt index f233bd3..39b1713 100644 --- a/app/src/commonTest/kotlin/id/gdg/app/AppViewModelTest.kt +++ b/app/src/commonTest/kotlin/id/gdg/app/AppViewModelTest.kt @@ -166,4 +166,51 @@ class AppViewModelTest : KoinTest { } } } + + @Test + fun `when EventDetail is invoked then the the event details is returned`() { + val expectedValue = EventDetailModel( + title = "DevFest!" + ) + + robot.eventDetailUseCase.setData(Result.success(expectedValue)) + + viewModel.sendEvent(AppEvent.EventDetail(1)) + + runBlocking { + viewModel.eventDetailUiState.test { + val actualValue = expectMostRecentItem() + assertTrue { actualValue.state is UiState.Success } + assertTrue { actualValue.detail != null } + } + } + } + + @Test + fun `when EventDetail is invoked and invalid event id then an empty event detail is returned`() { + robot.eventDetailUseCase.setData(Result.success(null)) + + viewModel.sendEvent(AppEvent.EventDetail(-1)) + + runBlocking { + viewModel.eventDetailUiState.test { + val actualValue = expectMostRecentItem() + assertTrue { actualValue.state is UiState.Success } + assertTrue { actualValue.detail == null } + } + } + } + + @Test + fun `when EventDetail is invoked and a network error occurs then a Fail state is returned`() { + robot.eventDetailUseCase.setData(Result.failure(Throwable("network error"))) + + viewModel.sendEvent(AppEvent.EventDetail(0)) + + runBlocking { + viewModel.eventDetailUiState.test { + assertTrue { expectMostRecentItem().state is UiState.Fail } + } + } + } } \ No newline at end of file