mirror of
https://github.com/bitwarden/android.git
synced 2024-11-24 10:25:57 +03:00
BIT-725: Replace "region" concept with Environment (#152)
This commit is contained in:
parent
e4ab70a106
commit
2472648434
10 changed files with 120 additions and 75 deletions
|
@ -27,12 +27,6 @@ interface AuthRepository {
|
|||
*/
|
||||
var rememberedEmailAddress: String?
|
||||
|
||||
/**
|
||||
* The currently selected region label (`null` if not set).
|
||||
*/
|
||||
// TODO replace this with a more robust selected region object BIT-725
|
||||
var selectedRegionLabel: String
|
||||
|
||||
/**
|
||||
* Attempt to login with the given email and password. Updated access token will be reflected
|
||||
* in [authStateFlow].
|
||||
|
|
|
@ -77,9 +77,6 @@ class AuthRepositoryImpl @Inject constructor(
|
|||
authDiskSource.rememberedEmailAddress = value
|
||||
}
|
||||
|
||||
// TODO Handle selected region functionality BIT-725
|
||||
override var selectedRegionLabel: String = "bitwarden.us"
|
||||
|
||||
override suspend fun login(
|
||||
email: String,
|
||||
password: String,
|
||||
|
|
|
@ -40,6 +40,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
||||
|
@ -132,10 +133,10 @@ fun LandingScreen(
|
|||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
RegionSelector(
|
||||
selectedOption = state.selectedRegion,
|
||||
EnvironmentSelector(
|
||||
selectedOption = state.selectedEnvironment.type,
|
||||
onOptionSelected = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.RegionOptionSelect(it)) }
|
||||
{ viewModel.trySendAction(LandingAction.EnvironmentTypeSelect(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.semantics { testTag = "RegionSelectorDropdown" }
|
||||
|
@ -208,19 +209,19 @@ fun LandingScreen(
|
|||
* from a list of options. When an option is selected, it invokes the provided callback
|
||||
* and displays the currently selected region on the UI.
|
||||
*
|
||||
* @param selectedOption The currently selected region option.
|
||||
* @param onOptionSelected A callback that gets invoked when a region option is selected
|
||||
* @param selectedOption The currently selected environment option.
|
||||
* @param onOptionSelected A callback that gets invoked when an environment option is selected
|
||||
* and passes the selected option as an argument.
|
||||
* @param modifier A [Modifier] for the composable.
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
private fun RegionSelector(
|
||||
selectedOption: LandingState.RegionOption,
|
||||
onOptionSelected: (LandingState.RegionOption) -> Unit,
|
||||
private fun EnvironmentSelector(
|
||||
selectedOption: Environment.Type,
|
||||
onOptionSelected: (Environment.Type) -> Unit,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
val options = LandingState.RegionOption.values().toList()
|
||||
val options = Environment.Type.values()
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(modifier = modifier) {
|
||||
|
@ -238,7 +239,7 @@ private fun RegionSelector(
|
|||
modifier = Modifier.padding(end = 12.dp),
|
||||
)
|
||||
Text(
|
||||
text = selectedOption.label,
|
||||
text = selectedOption.label(),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
|
@ -256,7 +257,7 @@ private fun RegionSelector(
|
|||
) {
|
||||
options.forEach { optionString ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = optionString.label) },
|
||||
text = { Text(text = optionString.label()) },
|
||||
onClick = {
|
||||
expanded = false
|
||||
onOptionSelected(optionString)
|
||||
|
|
|
@ -5,6 +5,8 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.isValidEmail
|
||||
|
@ -24,6 +26,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class LandingViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<LandingState, LandingEvent, LandingAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
|
@ -31,15 +34,20 @@ class LandingViewModel @Inject constructor(
|
|||
emailInput = authRepository.rememberedEmailAddress.orEmpty(),
|
||||
isContinueButtonEnabled = authRepository.rememberedEmailAddress != null,
|
||||
isRememberMeEnabled = authRepository.rememberedEmailAddress != null,
|
||||
selectedRegion = LandingState.RegionOption.BITWARDEN_US,
|
||||
selectedEnvironment = environmentRepository.environment,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
) {
|
||||
|
||||
init {
|
||||
// As state updates, write to saved state handle:
|
||||
// As state updates:
|
||||
// - write to saved state handle
|
||||
// - updated selected environment
|
||||
stateFlow
|
||||
.onEach { savedStateHandle[KEY_STATE] = it }
|
||||
.onEach {
|
||||
savedStateHandle[KEY_STATE] = it
|
||||
environmentRepository.environment = it.selectedEnvironment
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
|
@ -50,7 +58,7 @@ class LandingViewModel @Inject constructor(
|
|||
is LandingAction.ErrorDialogDismiss -> handleErrorDialogDismiss()
|
||||
is LandingAction.RememberMeToggle -> handleRememberMeToggled(action)
|
||||
is LandingAction.EmailInputChanged -> handleEmailInputUpdated(action)
|
||||
is LandingAction.RegionOptionSelect -> handleRegionSelect(action)
|
||||
is LandingAction.EnvironmentTypeSelect -> handleEnvironmentTypeSelect(action)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,8 +90,6 @@ class LandingViewModel @Inject constructor(
|
|||
|
||||
// Update the remembered email address
|
||||
authRepository.rememberedEmailAddress = email.takeUnless { !isRememberMeEnabled }
|
||||
// Update the selected region selectedRegionLabel
|
||||
authRepository.selectedRegionLabel = mutableStateFlow.value.selectedRegion.label
|
||||
|
||||
sendEvent(LandingEvent.NavigateToLogin(email))
|
||||
}
|
||||
|
@ -102,10 +108,21 @@ class LandingViewModel @Inject constructor(
|
|||
mutableStateFlow.update { it.copy(isRememberMeEnabled = action.isChecked) }
|
||||
}
|
||||
|
||||
private fun handleRegionSelect(action: LandingAction.RegionOptionSelect) {
|
||||
private fun handleEnvironmentTypeSelect(action: LandingAction.EnvironmentTypeSelect) {
|
||||
val environment = when (action.environmentType) {
|
||||
Environment.Type.US -> Environment.Us
|
||||
Environment.Type.EU -> Environment.Eu
|
||||
Environment.Type.SELF_HOSTED -> {
|
||||
// TODO Show dialog for setting selected environment (BIT-330)
|
||||
Environment.SelfHosted(
|
||||
environmentUrlData = Environment.Us.environmentUrlData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
selectedRegion = action.regionOption,
|
||||
selectedEnvironment = environment,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -119,18 +136,9 @@ data class LandingState(
|
|||
val emailInput: String,
|
||||
val isContinueButtonEnabled: Boolean,
|
||||
val isRememberMeEnabled: Boolean,
|
||||
val selectedRegion: RegionOption,
|
||||
val selectedEnvironment: Environment,
|
||||
val errorDialogState: BasicDialogState,
|
||||
) : Parcelable {
|
||||
/**
|
||||
* Enumerates the possible region options with their corresponding labels.
|
||||
*/
|
||||
enum class RegionOption(val label: String) {
|
||||
BITWARDEN_US("bitwarden.com"),
|
||||
BITWARDEN_EU("bitwarden.eu"),
|
||||
SELF_HOSTED("Self-hosted"),
|
||||
}
|
||||
}
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
* Models events for the landing screen.
|
||||
|
@ -185,7 +193,7 @@ sealed class LandingAction {
|
|||
/**
|
||||
* Indicates that the selection from the region drop down has changed.
|
||||
*/
|
||||
data class RegionOptionSelect(
|
||||
val regionOption: LandingState.RegionOption,
|
||||
data class EnvironmentTypeSelect(
|
||||
val environmentType: Environment.Type,
|
||||
) : LandingAction()
|
||||
}
|
||||
|
|
|
@ -147,12 +147,12 @@ fun LoginScreen(
|
|||
.padding(bottom = 24.dp),
|
||||
isEnabled = state.isLoginButtonEnabled,
|
||||
)
|
||||
// TODO Get the "login target" from a dropdown (BIT-202)
|
||||
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.logging_in_as_x_on_y,
|
||||
state.emailAddress,
|
||||
state.region,
|
||||
state.environmentLabel(),
|
||||
),
|
||||
textAlign = TextAlign.Start,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
|
|
|
@ -11,7 +11,9 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||
|
@ -31,6 +33,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class LoginViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<LoginState, LoginEvent, LoginAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
|
@ -38,7 +41,7 @@ class LoginViewModel @Inject constructor(
|
|||
emailAddress = LoginArgs(savedStateHandle).emailAddress,
|
||||
isLoginButtonEnabled = true,
|
||||
passwordInput = "",
|
||||
region = authRepository.selectedRegionLabel,
|
||||
environmentLabel = environmentRepository.environment.label,
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
captchaToken = LoginArgs(savedStateHandle).captchaToken,
|
||||
|
@ -193,7 +196,7 @@ data class LoginState(
|
|||
val passwordInput: String,
|
||||
val emailAddress: String,
|
||||
val captchaToken: String?,
|
||||
val region: String,
|
||||
val environmentLabel: Text,
|
||||
val isLoginButtonEnabled: Boolean,
|
||||
val loadingDialogState: LoadingDialogState,
|
||||
val errorDialogState: BasicDialogState,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
|
@ -15,6 +16,8 @@ import androidx.compose.ui.test.onNodeWithText
|
|||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
|
@ -29,6 +32,9 @@ import org.junit.Test
|
|||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
class LandingScreenTest : BaseComposeTest() {
|
||||
private val resources
|
||||
get() = ApplicationProvider.getApplicationContext<Application>().resources
|
||||
|
||||
@Test
|
||||
fun `continue button should be enabled or disabled according to the state`() {
|
||||
val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
|
@ -218,8 +224,8 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `selecting region should send RegionOptionSelect action`() {
|
||||
val selectedRegion = LandingState.RegionOption.BITWARDEN_EU
|
||||
fun `selecting environment should send EnvironmentOptionSelect action`() {
|
||||
val selectedEnvironment = Environment.Eu
|
||||
val viewModel = mockk<LandingViewModel>(relaxed = true) {
|
||||
every { eventFlow } returns emptyFlow()
|
||||
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
|
||||
|
@ -234,13 +240,17 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
// Clicking to open dropdown
|
||||
composeTestRule.onNodeWithText(LandingState.RegionOption.BITWARDEN_US.label).performClick()
|
||||
composeTestRule
|
||||
.onNodeWithText(Environment.Us.label.toString(resources))
|
||||
.performClick()
|
||||
|
||||
// Clicking item from the dropdown menu
|
||||
composeTestRule.onNodeWithText(selectedRegion.label).performClick()
|
||||
composeTestRule
|
||||
.onNodeWithText(selectedEnvironment.label.toString(resources))
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
viewModel.trySendAction(LandingAction.RegionOptionSelect(selectedRegion))
|
||||
viewModel.trySendAction(LandingAction.EnvironmentTypeSelect(selectedEnvironment.type))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,7 +329,7 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
emailInput = "",
|
||||
isContinueButtonEnabled = true,
|
||||
isRememberMeEnabled = false,
|
||||
selectedRegion = LandingState.RegionOption.BITWARDEN_US,
|
||||
selectedEnvironment = Environment.Us,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
|
@ -145,14 +146,14 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `RegionOptionSelect should update value of selected region`() = runTest {
|
||||
val inputRegion = LandingState.RegionOption.BITWARDEN_EU
|
||||
fun `EnvironmentTypeSelect should update value of selected region`() = runTest {
|
||||
val inputEnvironment = Environment.Eu
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
awaitItem()
|
||||
viewModel.trySendAction(LandingAction.RegionOptionSelect(inputRegion))
|
||||
viewModel.trySendAction(LandingAction.EnvironmentTypeSelect(inputEnvironment.type))
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(selectedRegion = LandingState.RegionOption.BITWARDEN_EU),
|
||||
DEFAULT_STATE.copy(selectedEnvironment = Environment.Eu),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
|
@ -162,11 +163,15 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
private fun createViewModel(
|
||||
rememberedEmail: String? = null,
|
||||
environment: Environment = Environment.Us,
|
||||
savedStateHandle: SavedStateHandle = SavedStateHandle(),
|
||||
): LandingViewModel = LandingViewModel(
|
||||
authRepository = mockk(relaxed = true) {
|
||||
every { rememberedEmailAddress } returns rememberedEmail
|
||||
},
|
||||
environmentRepository = mockk(relaxed = true) {
|
||||
every { this@mockk.environment } returns environment
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
||||
|
@ -177,7 +182,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
emailInput = "",
|
||||
isContinueButtonEnabled = false,
|
||||
isRememberMeEnabled = false,
|
||||
selectedRegion = LandingState.RegionOption.BITWARDEN_US,
|
||||
selectedEnvironment = Environment.Us,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.ui.test.performScrollTo
|
|||
import androidx.compose.ui.test.performTextInput
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||
import io.mockk.every
|
||||
|
@ -37,7 +38,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -65,7 +66,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -93,7 +94,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -121,7 +122,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -161,7 +162,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -190,7 +191,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
@ -219,7 +220,7 @@ class LoginScreenTest : BaseComposeTest() {
|
|||
captchaToken = null,
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
environmentLabel = "".asText(),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
|
|
|
@ -8,6 +8,8 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.LoginResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
|
@ -29,7 +31,6 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
|
||||
private val savedStateHandle = SavedStateHandle().also {
|
||||
it["email_address"] = "test@gmail.com"
|
||||
it["region_label"] = ""
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
|
@ -47,7 +48,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -72,6 +75,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = handle,
|
||||
)
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -84,7 +90,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -108,10 +116,13 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
} returns LoginResult.Error(errorMessage = "mock_error")
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
}
|
||||
val environmentRepository = mockk<EnvironmentRepository> {
|
||||
every { environment } returns Environment.Us
|
||||
}
|
||||
val viewModel = LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
environmentRepository = environmentRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -148,10 +159,12 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
login("test@gmail.com", "", captchaToken = null)
|
||||
} returns LoginResult.Success
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
}
|
||||
val viewModel = LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -186,10 +199,12 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
coEvery { login("test@gmail.com", "", captchaToken = null) } returns
|
||||
LoginResult.CaptchaRequired(captchaId = "mock_captcha_id")
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
}
|
||||
val viewModel = LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
|
@ -207,7 +222,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -226,7 +243,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -245,7 +264,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -264,7 +285,9 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
val viewModel = LoginViewModel(
|
||||
authRepository = mockk {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
},
|
||||
environmentRepository = mockk {
|
||||
every { environment } returns Environment.Us
|
||||
},
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
@ -283,7 +306,6 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
every { captchaTokenResultFlow } returns flowOf(
|
||||
CaptchaCallbackTokenResult.Success("token"),
|
||||
)
|
||||
every { selectedRegionLabel } returns "bitwarden.us"
|
||||
coEvery {
|
||||
login(
|
||||
"test@gmail.com",
|
||||
|
@ -292,8 +314,12 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
} returns LoginResult.Success
|
||||
}
|
||||
val environmentRepository = mockk<EnvironmentRepository> {
|
||||
every { environment } returns Environment.Us
|
||||
}
|
||||
LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
environmentRepository = environmentRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
coVerify {
|
||||
|
@ -306,7 +332,7 @@ class LoginViewModelTest : BaseViewModelTest() {
|
|||
emailAddress = "test@gmail.com",
|
||||
passwordInput = "",
|
||||
isLoginButtonEnabled = true,
|
||||
region = "bitwarden.us",
|
||||
environmentLabel = Environment.Us.type.label,
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
captchaToken = null,
|
||||
|
|
Loading…
Reference in a new issue