From a3d31c46e1e90aa012254bc7344952e20df94e4e Mon Sep 17 00:00:00 2001 From: Isabel Martin Date: Wed, 27 Mar 2024 09:28:18 -0700 Subject: [PATCH] MBL-1292: Launch LogIn user when Continue button clicked (#1989) --- .../ui/activities/ProjectPageActivity.kt | 8 +- .../projectpage/CheckoutFlowViewModel.kt | 16 +++- .../usecases/CheckoutFlowViewModelTest.kt | 76 +++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 app/src/test/java/com/kickstarter/viewmodels/usecases/CheckoutFlowViewModelTest.kt diff --git a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt index f080e0c75f..5ef13edf73 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt @@ -512,7 +512,9 @@ class ProjectPageActivity : val checkoutPayment by confirmDetailsViewModel.checkoutPayment.collectAsStateWithLifecycle() LaunchedEffect(checkoutPayment.id) { - if (checkoutPayment.id != 0L) checkoutFlowViewModel.onConfirmDetailsContinueClicked() + if (checkoutPayment.id != 0L) checkoutFlowViewModel.onConfirmDetailsContinueClicked { + startLoginToutActivity() + } } val pagerState = rememberPagerState(initialPage = 0, pageCount = { 4 }) @@ -591,7 +593,9 @@ class ProjectPageActivity : shippingAmount = shippingAmount, onConfirmDetailsContinueClicked = { confirmDetailsViewModel.onContinueClicked { - checkoutFlowViewModel.onConfirmDetailsContinueClicked() + checkoutFlowViewModel.onConfirmDetailsContinueClicked { + startLoginToutActivity() + } } }, onBonusSupportMinusClicked = { confirmDetailsViewModel.decrementBonusSupport() }, diff --git a/app/src/main/java/com/kickstarter/viewmodels/projectpage/CheckoutFlowViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/projectpage/CheckoutFlowViewModel.kt index caec7db671..6cfbada23f 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/projectpage/CheckoutFlowViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/projectpage/CheckoutFlowViewModel.kt @@ -10,7 +10,9 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch +import kotlinx.coroutines.rx2.asFlow data class FlowUIState( val currentPage: Int = 0, @@ -20,6 +22,7 @@ data class FlowUIState( class CheckoutFlowViewModel(val environment: Environment) : ViewModel() { private lateinit var newUserReward: Reward + private val currentUser = requireNotNull(environment.currentUserV2()) private val mutableFlowUIState = MutableStateFlow(FlowUIState()) val flowUIState: StateFlow @@ -83,10 +86,17 @@ class CheckoutFlowViewModel(val environment: Environment) : ViewModel() { } } - fun onConfirmDetailsContinueClicked() { + fun onConfirmDetailsContinueClicked(logInCallback: () -> Unit) { viewModelScope.launch { - // Show pledge page - mutableFlowUIState.emit(FlowUIState(currentPage = 3, expanded = true)) + currentUser.isLoggedIn + .asFlow() + .take(1) + .collect { userLoggedIn -> + // - Show pledge page + if (userLoggedIn) mutableFlowUIState.emit(FlowUIState(currentPage = 3, expanded = true)) + // - Trigger LoginFlow callback + else logInCallback() + } } } diff --git a/app/src/test/java/com/kickstarter/viewmodels/usecases/CheckoutFlowViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/usecases/CheckoutFlowViewModelTest.kt new file mode 100644 index 0000000000..c411cf4fd9 --- /dev/null +++ b/app/src/test/java/com/kickstarter/viewmodels/usecases/CheckoutFlowViewModelTest.kt @@ -0,0 +1,76 @@ +package com.kickstarter.viewmodels.usecases + +import com.kickstarter.KSRobolectricTestCase +import com.kickstarter.libs.Environment +import com.kickstarter.libs.MockCurrentUserV2 +import com.kickstarter.mock.factories.UserFactory +import com.kickstarter.viewmodels.projectpage.CheckoutFlowViewModel +import com.kickstarter.viewmodels.projectpage.FlowUIState +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class CheckoutFlowViewModelTest : KSRobolectricTestCase() { + private lateinit var vm: CheckoutFlowViewModel + + private fun setUpEnvironment(environment: Environment) { + this.vm = CheckoutFlowViewModel.Factory(environment).create(CheckoutFlowViewModel::class.java) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun testLaunchLogInCallBack_whenNoUser_loggedIn() = runTest { + var callbackCalled = 0 + + // - No user present on environment + setUpEnvironment(environment()) + + // - Call onConfirmDetailsContinueClicked with a VM loaded with Environment without user + vm.onConfirmDetailsContinueClicked { callbackCalled++ } + + // - Make sure the callback provided is called when no user present, `onConfirmDetailsContinueClicked` will produce states ONLY if user present + assertTrue(callbackCalled == 1) + + val state = mutableListOf() + backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) { + vm.flowUIState.toList(state) + } + + // - make sure empty FlowUISate has been produced, `onConfirmDetailsContinueClicked` will produce states ONLY if user present + assertEquals(state, listOf(FlowUIState())) + assertNotSame(state, listOf(FlowUIState(currentPage = 3, expanded = true))) + assert(state.size == 1) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun testProduceNextPageState_whenUser_LoggedIn() = runTest { + var callbackCalled = 0 + + // - Environment with user present + val environment = environment() + .toBuilder() + .currentUserV2(MockCurrentUserV2(UserFactory.user())) + .build() + + setUpEnvironment(environment) + + // - Call onConfirmDetailsContinueClicked with a VM loaded with Environment containing an user + vm.onConfirmDetailsContinueClicked { callbackCalled++ } + + // - Make sure the callback is not called + assertTrue(callbackCalled == 0) + + val state = mutableListOf() + backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) { + vm.flowUIState.toList(state) + } + + // - make sure next page FlowUIState has been generated, not just the initial empty state + assertEquals(state, listOf(FlowUIState(), FlowUIState(currentPage = 3, expanded = true))) + assert(state.size == 2) + } +}