[PM-10632] Setup complete screen for new onboarding (#3921)

This commit is contained in:
Dave Severns 2024-09-17 09:23:24 -04:00 committed by GitHub
parent 135a48b3c0
commit 39df103f12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 382 additions and 0 deletions

View file

@ -27,6 +27,12 @@ enum class OnboardingStatus {
@SerialName("autofillSetup") @SerialName("autofillSetup")
AUTOFILL_SETUP, AUTOFILL_SETUP,
/**
* The user is completing the final step of the onboarding process.
*/
@SerialName("finalStep")
FINAL_STEP,
/** /**
* The user has completed all onboarding steps. * The user has completed all onboarding steps.
*/ */

View file

@ -0,0 +1,134 @@
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/**
* Top level composable for the setup complete screen.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SetupCompleteScreen(
viewModel: SetupCompleteViewModel = hiltViewModel(),
) {
val setupCompleteAction: () -> Unit = remember(viewModel) {
{
viewModel.trySendAction(SetupCompleteAction.CompleteSetup)
}
}
// Handle system back action to complete the setup.
BackHandler(onBack = setupCompleteAction)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
BitwardenScaffold(
topBar = {
BitwardenTopAppBar(
scrollBehavior = scrollBehavior,
title = stringResource(R.string.account_setup),
navigationIcon = null,
)
},
modifier = Modifier
.fillMaxSize()
.nestedScroll(scrollBehavior.nestedScrollConnection),
) { innerPadding ->
SetupCompleteContent(
modifier = Modifier
.padding(innerPadding)
.verticalScroll(rememberScrollState()),
onContinue = setupCompleteAction,
)
}
}
@Composable
private fun SetupCompleteContent(
modifier: Modifier = Modifier,
onContinue: () -> Unit,
) {
Column(
modifier = modifier,
) {
Spacer(Modifier.height(32.dp))
Image(
painter = rememberVectorPainter(R.drawable.img_setup_complete),
contentDescription = null,
modifier = Modifier
.align(CenterHorizontally)
.standardHorizontalMargin(),
)
Spacer(Modifier.height(24.dp))
Text(
text = stringResource(R.string.youre_all_set),
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
modifier = Modifier
.align(CenterHorizontally)
.standardHorizontalMargin(),
)
Spacer(Modifier.height(8.dp))
Text(
text = stringResource(R.string.what_bitwarden_has_to_offer),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
modifier = Modifier
.align(CenterHorizontally)
.standardHorizontalMargin(),
)
Spacer(Modifier.height(24.dp))
BitwardenFilledButton(
label = stringResource(R.string.continue_text),
onClick = onContinue,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)
}
}
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun SetupCompleteContent_preview() {
BitwardenTheme {
Surface {
SetupCompleteContent(
modifier = Modifier.fillMaxSize(),
onContinue = {},
)
}
}
}

View file

@ -0,0 +1,51 @@
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
/**
* ViewModel for the [SetupCompleteScreen]
*/
@HiltViewModel
class SetupCompleteViewModel @Inject constructor(
private val authRepository: AuthRepository,
) : BaseViewModel<SetupCompleteState, Unit, SetupCompleteAction>(
initialState = run {
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
SetupCompleteState(userId = userId)
},
) {
override fun handleAction(action: SetupCompleteAction) {
when (action) {
is SetupCompleteAction.CompleteSetup -> handleCompleteSetup()
}
}
private fun handleCompleteSetup() {
authRepository.setOnboardingStatus(
userId = state.userId,
status = OnboardingStatus.COMPLETE,
)
}
}
/**
* State for the [SetupCompleteScreen]
*/
data class SetupCompleteState(
val userId: String,
)
/**
* Model user actions for the [SetupCompleteScreen]
*/
sealed class SetupCompleteAction {
/**
* The user has performed an action to confirm that they are done setting up their account.
*/
data object CompleteSetup : SetupCompleteAction()
}

View file

@ -98,6 +98,7 @@ class RootNavViewModel @Inject constructor(
-> RootNavState.OnboardingAccountLockSetup -> RootNavState.OnboardingAccountLockSetup
OnboardingStatus.AUTOFILL_SETUP -> RootNavState.OnboardingAutoFillSetup OnboardingStatus.AUTOFILL_SETUP -> RootNavState.OnboardingAutoFillSetup
OnboardingStatus.COMPLETE -> throw IllegalStateException("Should not have entered here.") OnboardingStatus.COMPLETE -> throw IllegalStateException("Should not have entered here.")
OnboardingStatus.FINAL_STEP -> TODO("PM-12076 complete navigation wiring")
} }
} }

View file

@ -0,0 +1,44 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="200"
android:viewportHeight="200">
<path
android:pathData="M17.73,42.46C17.73,38.55 21.09,35.62 24.93,35.62H172.74C176.59,35.62 179.94,38.56 179.94,42.46V69.02C179.94,72.93 176.57,75.86 172.74,75.86H24.93C21.08,75.86 17.73,72.92 17.73,69.02V42.46ZM24.93,39.62C23.03,39.62 21.73,41.02 21.73,42.46V69.02C21.73,70.46 23.02,71.86 24.93,71.86H172.74C174.64,71.86 175.94,70.45 175.94,69.02V42.46C175.94,41.02 174.65,39.62 172.74,39.62H24.93Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M34.32,55.74C34.32,54.5 35.33,53.5 36.57,53.5H123.96C125.19,53.5 126.2,54.5 126.2,55.74C126.2,56.98 125.19,57.98 123.96,57.98H36.57C35.33,57.98 34.32,56.98 34.32,55.74Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M164.73,48.82C165.61,49.69 165.62,51.11 164.75,52L154.28,62.63C153.86,63.06 153.28,63.3 152.68,63.3C152.08,63.3 151.51,63.06 151.09,62.63L146.67,58.16C145.8,57.27 145.81,55.85 146.69,54.98C147.57,54.11 148.99,54.12 149.86,55.01L152.68,57.86L161.56,48.85C162.43,47.97 163.85,47.96 164.73,48.82Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M2,30.46C2,23.25 7.04,17 13.71,17H186.29C192.96,17 198,23.25 198,30.46V152.54C198,159.75 192.96,166 186.29,166H125.61C124.5,166 123.61,165.06 123.61,163.9C123.61,162.74 124.5,161.8 125.61,161.8H186.29C190.35,161.8 194,157.88 194,152.54V30.46C194,25.13 190.35,21.2 186.29,21.2H13.71C9.65,21.2 6,25.13 6,30.46V152.54C6,157.88 9.65,161.8 13.71,161.8H74.39C75.5,161.8 76.39,162.74 76.39,163.9C76.39,165.06 75.5,166 74.39,166H13.71C7.04,166 2,159.75 2,152.54V30.46Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M17.73,91.42C17.73,87.51 21.09,84.58 24.93,84.58H172.74C176.59,84.58 179.94,87.52 179.94,91.42V117.98C179.94,121.89 176.57,124.82 172.74,124.82H24.93C21.08,124.82 17.73,121.88 17.73,117.98V91.42ZM24.93,88.58C23.03,88.58 21.73,89.99 21.73,91.42V117.98C21.73,119.42 23.02,120.82 24.93,120.82H172.74C174.64,120.82 175.94,119.42 175.94,117.98V91.42C175.94,89.98 174.65,88.58 172.74,88.58H24.93Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M118.7,104.7C118.7,103.03 120.07,101.66 121.74,101.66C123.41,101.66 124.79,103.03 124.79,104.7C124.79,106.39 123.41,107.75 121.74,107.75C120.07,107.75 118.7,106.39 118.7,104.7ZM106.53,104.7C106.53,103.03 107.9,101.66 109.57,101.66C111.26,101.66 112.61,103.03 112.61,104.7C112.61,106.39 111.26,107.75 109.57,107.75C107.9,107.75 106.53,106.39 106.53,104.7ZM94.36,104.7C94.36,103.03 95.72,101.66 97.4,101.66C99.07,101.66 100.44,103.03 100.44,104.7C100.44,106.39 99.07,107.75 97.4,107.75C95.72,107.75 94.36,106.39 94.36,104.7ZM82.19,104.7C82.19,103.03 83.56,101.66 85.23,101.66C86.9,101.66 88.28,103.03 88.28,104.7C88.28,106.39 86.9,107.75 85.23,107.75C83.56,107.75 82.19,106.39 82.19,104.7ZM70.02,104.7C70.02,103.03 71.39,101.66 73.06,101.66C74.75,101.66 76.11,103.03 76.11,104.7C76.11,106.39 74.75,107.75 73.06,107.75C71.39,107.75 70.02,106.39 70.02,104.7ZM57.87,104.7C57.87,103.03 59.22,101.66 60.91,101.66C62.58,101.66 63.95,103.03 63.95,104.7C63.95,106.39 62.58,107.75 60.91,107.75C59.22,107.75 57.87,106.39 57.87,104.7ZM45.7,104.7C45.7,103.03 47.07,101.66 48.74,101.66C50.42,101.66 51.78,103.03 51.78,104.7C51.78,106.39 50.42,107.75 48.74,107.75C47.07,107.75 45.7,106.39 45.7,104.7ZM33.53,104.7C33.53,103.03 34.9,101.66 36.57,101.66C38.25,101.66 39.61,103.03 39.61,104.7C39.61,106.39 38.25,107.75 36.57,107.75C34.9,107.75 33.53,106.39 33.53,104.7Z"
android:fillColor="#6FD9E2"/>
<path
android:pathData="M164.73,97.79C165.61,98.65 165.62,100.07 164.75,100.96L154.28,111.59C153.86,112.02 153.28,112.26 152.68,112.26C152.08,112.26 151.51,112.02 151.09,111.59L146.67,107.12C145.8,106.24 145.81,104.82 146.69,103.95C147.57,103.08 148.99,103.08 149.86,103.97L152.68,106.82L161.56,97.81C162.43,96.93 163.85,96.92 164.73,97.79Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M94.94,142.86C90.61,145.18 89.16,149.77 90.79,152.83L91.84,154.71C92.75,156.36 91.13,158.25 89.36,157.6C88.9,157.43 88.51,157.09 88.28,156.65L87.26,154.72C84.31,149.2 87.31,142.4 93.05,139.33C98.78,136.26 106.1,137.51 109.07,143.05L111.25,147.12C111.77,148.1 111.4,149.31 110.43,149.83C109.45,150.36 108.24,149.99 107.72,149.01L105.54,144.94C103.89,141.86 99.28,140.54 94.94,142.86Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M82,163.53C82,159.11 85.58,155.53 90,155.53H109.03C113.45,155.53 117.03,159.11 117.03,163.53V177.24C117.03,181.66 113.45,185.24 109.03,185.24H90C85.58,185.24 82,181.66 82,177.24V163.53ZM90,159.53C87.79,159.53 86,161.32 86,163.53V177.24C86,179.45 87.79,181.24 90,181.24H109.03C111.24,181.24 113.03,179.45 113.03,177.24V163.53C113.03,161.32 111.24,159.53 109.03,159.53H90Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M98.51,170.13C97.91,169.78 97.51,169.13 97.51,168.39L97.51,168.01C97.51,166.9 98.41,166 99.51,166C100.62,166 101.52,166.9 101.52,168.01L101.52,168.39C101.52,169.13 101.12,169.78 100.52,170.13L100.52,174.11C100.52,174.67 100.07,175.12 99.52,175.12C98.96,175.12 98.51,174.67 98.51,174.11L98.51,170.13Z"
android:fillColor="#6FD9E2"/>
</vector>

View file

@ -0,0 +1,44 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="200"
android:viewportHeight="200">
<path
android:pathData="M17.73,42.46C17.73,38.55 21.09,35.62 24.93,35.62H172.74C176.59,35.62 179.94,38.56 179.94,42.46V69.02C179.94,72.93 176.57,75.86 172.74,75.86H24.93C21.08,75.86 17.73,72.92 17.73,69.02V42.46ZM24.93,39.62C23.03,39.62 21.73,41.02 21.73,42.46V69.02C21.73,70.46 23.02,71.86 24.93,71.86H172.74C174.64,71.86 175.94,70.45 175.94,69.02V42.46C175.94,41.02 174.65,39.62 172.74,39.62H24.93Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M34.32,55.74C34.32,54.5 35.33,53.5 36.57,53.5H123.96C125.19,53.5 126.2,54.5 126.2,55.74C126.2,56.98 125.19,57.98 123.96,57.98H36.57C35.33,57.98 34.32,56.98 34.32,55.74Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M164.73,48.82C165.61,49.69 165.62,51.11 164.75,52L154.28,62.63C153.86,63.06 153.28,63.3 152.68,63.3C152.08,63.3 151.51,63.06 151.09,62.63L146.67,58.16C145.8,57.27 145.81,55.85 146.69,54.98C147.57,54.11 148.99,54.12 149.86,55.01L152.68,57.86L161.56,48.85C162.43,47.97 163.85,47.96 164.73,48.82Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M2,30.46C2,23.25 7.04,17 13.71,17H186.29C192.96,17 198,23.25 198,30.46V152.54C198,159.75 192.96,166 186.29,166H125.61C124.5,166 123.61,165.06 123.61,163.9C123.61,162.74 124.5,161.8 125.61,161.8H186.29C190.35,161.8 194,157.88 194,152.54V30.46C194,25.13 190.35,21.2 186.29,21.2H13.71C9.65,21.2 6,25.13 6,30.46V152.54C6,157.88 9.65,161.8 13.71,161.8H74.39C75.5,161.8 76.39,162.74 76.39,163.9C76.39,165.06 75.5,166 74.39,166H13.71C7.04,166 2,159.75 2,152.54V30.46Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M17.73,91.42C17.73,87.51 21.09,84.58 24.93,84.58H172.74C176.59,84.58 179.94,87.52 179.94,91.42V117.98C179.94,121.89 176.57,124.82 172.74,124.82H24.93C21.08,124.82 17.73,121.88 17.73,117.98V91.42ZM24.93,88.58C23.03,88.58 21.73,89.99 21.73,91.42V117.98C21.73,119.42 23.02,120.82 24.93,120.82H172.74C174.64,120.82 175.94,119.42 175.94,117.98V91.42C175.94,89.98 174.65,88.58 172.74,88.58H24.93Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M118.7,104.7C118.7,103.03 120.07,101.66 121.74,101.66C123.41,101.66 124.79,103.03 124.79,104.7C124.79,106.39 123.41,107.75 121.74,107.75C120.07,107.75 118.7,106.39 118.7,104.7ZM106.53,104.7C106.53,103.03 107.9,101.66 109.57,101.66C111.26,101.66 112.61,103.03 112.61,104.7C112.61,106.39 111.26,107.75 109.57,107.75C107.9,107.75 106.53,106.39 106.53,104.7ZM94.36,104.7C94.36,103.03 95.72,101.66 97.4,101.66C99.07,101.66 100.44,103.03 100.44,104.7C100.44,106.39 99.07,107.75 97.4,107.75C95.72,107.75 94.36,106.39 94.36,104.7ZM82.19,104.7C82.19,103.03 83.56,101.66 85.23,101.66C86.9,101.66 88.28,103.03 88.28,104.7C88.28,106.39 86.9,107.75 85.23,107.75C83.56,107.75 82.19,106.39 82.19,104.7ZM70.02,104.7C70.02,103.03 71.39,101.66 73.06,101.66C74.75,101.66 76.11,103.03 76.11,104.7C76.11,106.39 74.75,107.75 73.06,107.75C71.39,107.75 70.02,106.39 70.02,104.7ZM57.87,104.7C57.87,103.03 59.22,101.66 60.91,101.66C62.58,101.66 63.95,103.03 63.95,104.7C63.95,106.39 62.58,107.75 60.91,107.75C59.22,107.75 57.87,106.39 57.87,104.7ZM45.7,104.7C45.7,103.03 47.07,101.66 48.74,101.66C50.42,101.66 51.78,103.03 51.78,104.7C51.78,106.39 50.42,107.75 48.74,107.75C47.07,107.75 45.7,106.39 45.7,104.7ZM33.53,104.7C33.53,103.03 34.9,101.66 36.57,101.66C38.25,101.66 39.61,103.03 39.61,104.7C39.61,106.39 38.25,107.75 36.57,107.75C34.9,107.75 33.53,106.39 33.53,104.7Z"
android:fillColor="#10949D"/>
<path
android:pathData="M164.73,97.79C165.61,98.65 165.62,100.07 164.75,100.96L154.28,111.59C153.86,112.02 153.28,112.26 152.68,112.26C152.08,112.26 151.51,112.02 151.09,111.59L146.67,107.12C145.8,106.24 145.81,104.82 146.69,103.95C147.57,103.08 148.99,103.08 149.86,103.97L152.68,106.82L161.56,97.81C162.43,96.93 163.85,96.92 164.73,97.79Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M94.94,142.86C90.61,145.18 89.16,149.77 90.79,152.83L91.84,154.71C92.75,156.36 91.13,158.25 89.36,157.6C88.9,157.43 88.51,157.09 88.28,156.65L87.26,154.72C84.31,149.2 87.31,142.4 93.05,139.33C98.78,136.26 106.1,137.51 109.07,143.05L111.25,147.12C111.77,148.1 111.4,149.31 110.43,149.83C109.45,150.36 108.24,149.99 107.72,149.01L105.54,144.94C103.89,141.86 99.28,140.54 94.94,142.86Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M82,163.53C82,159.11 85.58,155.53 90,155.53H109.03C113.45,155.53 117.03,159.11 117.03,163.53V177.24C117.03,181.66 113.45,185.24 109.03,185.24H90C85.58,185.24 82,181.66 82,177.24V163.53ZM90,159.53C87.79,159.53 86,161.32 86,163.53V177.24C86,179.45 87.79,181.24 90,181.24H109.03C111.24,181.24 113.03,179.45 113.03,177.24V163.53C113.03,161.32 111.24,159.53 109.03,159.53H90Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M98.51,170.13C97.91,169.78 97.51,169.13 97.51,168.39L97.51,168.01C97.51,166.9 98.41,166 99.51,166C100.62,166 101.52,166.9 101.52,168.01L101.52,168.39C101.52,169.13 101.12,169.78 100.52,170.13L100.52,174.11C100.52,174.67 100.07,175.12 99.52,175.12C98.96,175.12 98.51,174.67 98.51,174.11L98.51,170.13Z"
android:fillColor="#10949D"/>
</vector>

View file

@ -1002,4 +1002,6 @@ Do you want to switch to this account?</string>
<string name="turn_on_later">Turn on later</string> <string name="turn_on_later">Turn on later</string>
<string name="turn_on_autofill_later">Turn on autofill later?</string> <string name="turn_on_autofill_later">Turn on autofill later?</string>
<string name="return_to_complete_this_step_anytime_in_settings">You can return to complete this step anytime in Settings.</string> <string name="return_to_complete_this_step_anytime_in_settings">You can return to complete this step anytime in Settings.</string>
<string name="what_bitwarden_has_to_offer">You can now use autofill to log into apps and websites using your saved passwords. Now, you can explore everything else Bitwarden has to offer.</string>
<string name="youre_all_set">You\'re all set!</string>
</resources> </resources>

View file

@ -0,0 +1,39 @@
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
import io.mockk.mockk
import io.mockk.verify
import org.junit.Before
import org.junit.Test
class SetupCompleteScreenTest : BaseComposeTest() {
private val viewModel = mockk<SetupCompleteViewModel>(relaxed = true)
@Before
fun setup() {
setContentWithBackDispatcher {
SetupCompleteScreen(viewModel = viewModel)
}
}
@Test
fun `When continue button clicked sends CompleteSetup action`() {
composeTestRule
.onNodeWithText("Continue")
.performScrollTo()
.performClick()
verify { viewModel.trySendAction(SetupCompleteAction.CompleteSetup) }
}
@Test
fun `When system back behavior is triggered sends CompleteSetup action`() {
backDispatcher?.onBackPressed()
verify { viewModel.trySendAction(SetupCompleteAction.CompleteSetup) }
}
}

View file

@ -0,0 +1,61 @@
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
class SetupCompleteViewModelTest : BaseViewModelTest() {
private val mockUserState = mockk<UserState> {
every { activeUserId } returns DEFAULT_USER_ID
}
private val mutableUserStateFlow = MutableStateFlow<UserState?>(mockUserState)
private val authRepository: AuthRepository = mockk(relaxed = true) {
every { userStateFlow } returns mutableUserStateFlow
}
@Test
fun `When user state has no active accounts then throw IllegalStateException`() {
mutableUserStateFlow.value = null
assertThrows<IllegalArgumentException> {
createViewModel()
}
}
@Test
fun `When user state has active account then ViewModel state should contain active user ID`() {
val viewModel = createViewModel()
assertEquals(
SetupCompleteState(userId = DEFAULT_USER_ID),
viewModel.stateFlow.value,
)
}
@Test
fun `When CompleteSetup action is sent user state is updated with onboarding COMPLETE`() {
val viewModel = createViewModel()
assertEquals(
SetupCompleteState(userId = DEFAULT_USER_ID),
viewModel.stateFlow.value,
)
viewModel.trySendAction(SetupCompleteAction.CompleteSetup)
verify {
authRepository.setOnboardingStatus(
DEFAULT_USER_ID,
OnboardingStatus.COMPLETE,
)
}
}
private fun createViewModel() = SetupCompleteViewModel(authRepository = authRepository)
}
private const val DEFAULT_USER_ID = "userId"