Add edit cipher org events (#3352)

This commit is contained in:
David Perez 2024-06-25 09:12:45 -05:00 committed by GitHub
parent 949768ac95
commit d1e8ed63a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 383 additions and 17 deletions

View file

@ -9,6 +9,10 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
@ -70,10 +74,16 @@ fun LazyListScope.vaultAddEditCardItems(
}
item {
Spacer(modifier = Modifier.height(8.dp))
var showNumber by rememberSaveable { mutableStateOf(value = false) }
BitwardenPasswordField(
label = stringResource(id = R.string.number),
value = cardState.number,
onValueChange = cardHandlers.onNumberTextChange,
showPassword = showNumber,
showPasswordChange = {
showNumber = !showNumber
cardHandlers.onNumberVisibilityChange(showNumber)
},
modifier = Modifier
.testTag("CardNumberEntry")
.fillMaxWidth()
@ -140,10 +150,16 @@ fun LazyListScope.vaultAddEditCardItems(
}
item {
Spacer(modifier = Modifier.height(8.dp))
var showSecurityCode by rememberSaveable { mutableStateOf(value = false) }
BitwardenPasswordField(
label = stringResource(id = R.string.security_code),
value = cardState.securityCode,
onValueChange = cardHandlers.onSecurityCodeTextChange,
showPassword = showSecurityCode,
showPasswordChange = {
showSecurityCode = !showSecurityCode
cardHandlers.onSecurityCodeVisibilityChange(showSecurityCode)
},
keyboardType = KeyboardType.NumberPassword,
modifier = Modifier
.testTag("CardSecurityCodeEntry")
@ -259,7 +275,7 @@ fun LazyListScope.vaultAddEditCardItems(
items(commonState.customFieldData) { customItem ->
VaultAddEditCustomField(
customItem,
customField = customItem,
onCustomFieldValueChange = commonHandlers.onCustomFieldValueChange,
onCustomFieldAction = commonHandlers.onCustomFieldActionSelect,
modifier = Modifier
@ -273,6 +289,7 @@ fun LazyListScope.vaultAddEditCardItems(
VaultLinkedFieldType.BRAND,
VaultLinkedFieldType.NUMBER,
),
onHiddenVisibilityChanged = commonHandlers.onHiddenFieldVisibilityChange,
)
}

View file

@ -37,6 +37,7 @@ import kotlinx.collections.immutable.toImmutableList
* @param onCustomFieldAction Invoked when the user chooses an action.
* @param modifier Modifier for the UI elements.
* @param supportedLinkedTypes The supported linked types for the vault item.
* @param onHiddenVisibilityChanged Emits when the visibility of a hidden custom field changes.
*/
@Composable
@Suppress("LongMethod")
@ -46,6 +47,7 @@ fun VaultAddEditCustomField(
onCustomFieldAction: (CustomFieldAction, VaultAddEditState.Custom) -> Unit,
modifier: Modifier = Modifier,
supportedLinkedTypes: ImmutableList<VaultLinkedFieldType> = persistentListOf(),
onHiddenVisibilityChanged: (Boolean) -> Unit,
) {
var shouldShowChooserDialog by remember { mutableStateOf(false) }
var shouldShowEditDialog by remember { mutableStateOf(false) }
@ -91,11 +93,12 @@ fun VaultAddEditCustomField(
is VaultAddEditState.Custom.HiddenField -> {
CustomFieldHiddenField(
customField.name,
customField.value,
label = customField.name,
value = customField.value,
onValueChanged = {
onCustomFieldValueChange(customField.copy(value = it))
},
onVisibilityChanged = onHiddenVisibilityChanged,
onEditValue = { shouldShowChooserDialog = true },
modifier = modifier,
)
@ -175,12 +178,19 @@ private fun CustomFieldHiddenField(
value: String,
onValueChanged: (String) -> Unit,
onEditValue: () -> Unit,
onVisibilityChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
var shouldShowPassword by remember { mutableStateOf(value = false) }
BitwardenPasswordFieldWithActions(
label = label,
value = value,
onValueChange = onValueChanged,
showPassword = shouldShowPassword,
showPasswordChange = {
shouldShowPassword = !shouldShowPassword
onVisibilityChanged(shouldShowPassword)
},
singleLine = true,
modifier = modifier,
actions = {

View file

@ -403,6 +403,7 @@ fun LazyListScope.vaultAddEditIdentityItems(
VaultLinkedFieldType.LAST_NAME,
VaultLinkedFieldType.FULL_NAME,
),
onHiddenVisibilityChanged = commonTypeHandlers.onHiddenFieldVisibilityChange,
)
}

View file

@ -12,6 +12,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
@ -301,7 +302,7 @@ fun LazyListScope.vaultAddEditLoginItems(
items(commonState.customFieldData) { customItem ->
VaultAddEditCustomField(
customItem,
customField = customItem,
onCustomFieldValueChange = commonActionHandler.onCustomFieldValueChange,
onCustomFieldAction = commonActionHandler.onCustomFieldActionSelect,
modifier = Modifier
@ -311,6 +312,7 @@ fun LazyListScope.vaultAddEditLoginItems(
VaultLinkedFieldType.PASSWORD,
VaultLinkedFieldType.USERNAME,
),
onHiddenVisibilityChanged = commonActionHandler.onHiddenFieldVisibilityChange,
)
}
@ -436,10 +438,16 @@ private fun PasswordRow(
var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
if (canViewPassword) {
var shouldShowPassword by remember { mutableStateOf(false) }
BitwardenPasswordFieldWithActions(
label = stringResource(id = R.string.password),
value = password,
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
showPassword = shouldShowPassword,
showPasswordChange = {
shouldShowPassword = !shouldShowPassword
loginItemTypeHandlers.onPasswordVisibilityChange(shouldShowPassword)
},
showPasswordTestTag = "ViewPasswordButton",
passwordFieldTestTag = "LoginPasswordEntry",
modifier = Modifier

View file

@ -154,12 +154,13 @@ fun LazyListScope.vaultAddEditSecureNotesItems(
}
items(commonState.customFieldData) { customItem ->
VaultAddEditCustomField(
customItem,
customField = customItem,
onCustomFieldValueChange = commonTypeHandlers.onCustomFieldValueChange,
onCustomFieldAction = commonTypeHandlers.onCustomFieldActionSelect,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
onHiddenVisibilityChanged = commonTypeHandlers.onHiddenFieldVisibilityChange,
)
}

View file

@ -214,9 +214,9 @@ class VaultAddEditViewModel @Inject constructor(
private fun handleCommonActions(action: VaultAddEditAction.Common) {
when (action) {
is VaultAddEditAction.Common.CustomFieldValueChange -> handleCustomFieldValueChange(
action,
)
is VaultAddEditAction.Common.CustomFieldValueChange -> {
handleCustomFieldValueChange(action)
}
is VaultAddEditAction.Common.FolderChange -> handleFolderTextInputChange(action)
is VaultAddEditAction.Common.NameTextChange -> handleNameTextInputChange(action)
@ -235,19 +235,23 @@ class VaultAddEditViewModel @Inject constructor(
is VaultAddEditAction.Common.DismissDialog -> handleDismissDialog()
is VaultAddEditAction.Common.SaveClick -> handleSaveClick()
is VaultAddEditAction.Common.TypeOptionSelect -> handleTypeOptionSelect(action)
is VaultAddEditAction.Common.AddNewCustomFieldClick -> handleAddNewCustomFieldClick(
action,
)
is VaultAddEditAction.Common.AddNewCustomFieldClick -> {
handleAddNewCustomFieldClick(action)
}
is VaultAddEditAction.Common.TooltipClick -> handleTooltipClick()
is VaultAddEditAction.Common.CustomFieldActionSelect -> handleCustomFieldActionSelected(
action,
)
is VaultAddEditAction.Common.CustomFieldActionSelect -> {
handleCustomFieldActionSelected(action)
}
is VaultAddEditAction.Common.CollectionSelect -> handleCollectionSelect(action)
is VaultAddEditAction.Common.InitialAutofillDialogDismissed -> {
handleInitialAutofillDialogDismissed()
}
is VaultAddEditAction.Common.HiddenFieldVisibilityChange -> {
handleHiddenFieldVisibilityChange(action)
}
}
}
@ -422,6 +426,20 @@ class VaultAddEditViewModel @Inject constructor(
}
}
private fun handleHiddenFieldVisibilityChange(
action: VaultAddEditAction.Common.HiddenFieldVisibilityChange,
) {
onEdit {
if (action.isVisible) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledHiddenFieldVisible(
cipherId = it.vaultItemId,
),
)
}
}
}
private fun handleAddNewCustomFieldClick(
action: VaultAddEditAction.Common.AddNewCustomFieldClick,
) {
@ -636,6 +654,10 @@ class VaultAddEditViewModel @Inject constructor(
is VaultAddEditAction.ItemType.LoginType.ClearTotpKeyClick -> {
handleLoginClearTotpKey()
}
is VaultAddEditAction.ItemType.LoginType.PasswordVisibilityChange -> {
handlePasswordVisibilityChange(action)
}
}
}
@ -736,6 +758,20 @@ class VaultAddEditViewModel @Inject constructor(
}
}
private fun handlePasswordVisibilityChange(
action: VaultAddEditAction.ItemType.LoginType.PasswordVisibilityChange,
) {
onEdit {
if (action.isVisible) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledPasswordVisible(
cipherId = it.vaultItemId,
),
)
}
}
}
private fun handleLoginAddNewUriClick() {
updateLoginContent { loginType ->
loginType.copy(
@ -961,9 +997,17 @@ class VaultAddEditViewModel @Inject constructor(
handleCardNumberTextChange(action)
}
is VaultAddEditAction.ItemType.CardType.NumberVisibilityChange -> {
handleNumberVisibilityChange(action)
}
is VaultAddEditAction.ItemType.CardType.SecurityCodeTextChange -> {
handleCardSecurityCodeTextChange(action)
}
is VaultAddEditAction.ItemType.CardType.SecurityCodeVisibilityChange -> {
handleSecurityCodeVisibilityChange(action)
}
}
}
@ -997,12 +1041,40 @@ class VaultAddEditViewModel @Inject constructor(
updateCardContent { it.copy(number = action.number) }
}
private fun handleNumberVisibilityChange(
action: VaultAddEditAction.ItemType.CardType.NumberVisibilityChange,
) {
onEdit {
if (action.isVisible) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledCardNumberVisible(
cipherId = it.vaultItemId,
),
)
}
}
}
private fun handleCardSecurityCodeTextChange(
action: VaultAddEditAction.ItemType.CardType.SecurityCodeTextChange,
) {
updateCardContent { it.copy(securityCode = action.securityCode) }
}
private fun handleSecurityCodeVisibilityChange(
action: VaultAddEditAction.ItemType.CardType.SecurityCodeVisibilityChange,
) {
onEdit {
if (action.isVisible) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledCardCodeVisible(
cipherId = it.vaultItemId,
),
)
}
}
}
//endregion Card Type Handlers
//region Internal Type Handlers
@ -1024,10 +1096,11 @@ class VaultAddEditViewModel @Inject constructor(
handleGeneratorResultReceive(action)
}
is VaultAddEditAction.Internal.PasswordBreachReceive ->
is VaultAddEditAction.Internal.PasswordBreachReceive -> {
handlePasswordBreachReceive(action)
}
}
}
private fun handleCreateCipherResultReceive(
action: VaultAddEditAction.Internal.CreateCipherResultReceive,
@ -2009,6 +2082,13 @@ sealed class VaultAddEditAction {
data class CollectionSelect(
val collection: VaultCollection,
) : Common()
/**
* The user has changed the visibility state of a hidden field.
*
* @property isVisible the new visibility state of the hidden field.
*/
data class HiddenFieldVisibilityChange(val isVisible: Boolean) : Common()
}
/**
@ -2085,6 +2165,13 @@ sealed class VaultAddEditAction {
* Represents the action to add a new URI field.
*/
data object AddNewUriClick : LoginType()
/**
* Fired when the password's visibility has changed.
*
* @property isVisible The new password visibility state.
*/
data class PasswordVisibilityChange(val isVisible: Boolean) : LoginType()
}
/**
@ -2240,6 +2327,13 @@ sealed class VaultAddEditAction {
*/
data class NumberTextChange(val number: String) : CardType()
/**
* Fired when the number's visibility has changed.
*
* @property isVisible The new number visibility state.
*/
data class NumberVisibilityChange(val isVisible: Boolean) : CardType()
/**
* Fired when the brand input is selected.
*
@ -2272,6 +2366,13 @@ sealed class VaultAddEditAction {
* @property securityCode The new security code text.
*/
data class SecurityCodeTextChange(val securityCode: String) : CardType()
/**
* Fired when the security code's visibility has changed.
*
* @property isVisible The new code visibility state.
*/
data class SecurityCodeVisibilityChange(val isVisible: Boolean) : CardType()
}
}

View file

@ -15,6 +15,9 @@ import com.x8bit.bitwarden.ui.vault.model.VaultCardExpirationMonth
* @property onExpirationMonthSelected Handles the action when an expiration month is selected.
* @property onExpirationYearTextChange Handles the action when the expiration year text is changed.
* @property onSecurityCodeTextChange Handles the action when the expiration year text is changed.
* @property onSecurityCodeVisibilityChange Handles the action when the security code visibility
* changes.
* @property onNumberVisibilityChange Handles the action when the number visibility changes.
*/
@Suppress("MaxLineLength")
data class VaultAddEditCardTypeHandlers(
@ -24,7 +27,8 @@ data class VaultAddEditCardTypeHandlers(
val onExpirationMonthSelected: (VaultCardExpirationMonth) -> Unit,
val onExpirationYearTextChange: (String) -> Unit,
val onSecurityCodeTextChange: (String) -> Unit,
val onSecurityCodeVisibilityChange: (Boolean) -> Unit,
val onNumberVisibilityChange: (Boolean) -> Unit,
) {
companion object {
@ -76,6 +80,18 @@ data class VaultAddEditCardTypeHandlers(
),
)
},
onSecurityCodeVisibilityChange = {
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.SecurityCodeVisibilityChange(
isVisible = it,
),
)
},
onNumberVisibilityChange = {
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.NumberVisibilityChange(isVisible = it),
)
},
)
}
}

View file

@ -37,6 +37,7 @@ data class VaultAddEditCommonHandlers(
val onCustomFieldValueChange: (VaultAddEditState.Custom) -> Unit,
val onCustomFieldActionSelect: (CustomFieldAction, VaultAddEditState.Custom) -> Unit,
val onCollectionSelect: (VaultCollection) -> Unit,
val onHiddenFieldVisibilityChange: (Boolean) -> Unit,
) {
companion object {
@ -116,6 +117,11 @@ data class VaultAddEditCommonHandlers(
),
)
},
onHiddenFieldVisibilityChange = {
viewModel.trySendAction(
VaultAddEditAction.Common.HiddenFieldVisibilityChange(isVisible = it),
)
},
)
}
}

View file

@ -22,6 +22,8 @@ import com.x8bit.bitwarden.ui.vault.feature.addedit.model.UriItem
* @property onCopyTotpKeyClick Handles the action when the copy TOTP text button is clicked.
* @property onClearTotpKeyClick Handles the action when the clear TOTP text button is clicked.
* @property onAddNewUriClick Handles the action when the add new URI button is clicked.
* @property onPasswordVisibilityChange Handles the action when the password visibility button is
* clicked.
*/
@Suppress("LongParameterList")
data class VaultAddEditLoginTypeHandlers(
@ -36,6 +38,7 @@ data class VaultAddEditLoginTypeHandlers(
val onCopyTotpKeyClick: (String) -> Unit,
val onClearTotpKeyClick: () -> Unit,
val onAddNewUriClick: () -> Unit,
val onPasswordVisibilityChange: (Boolean) -> Unit,
) {
companion object {
@ -106,6 +109,11 @@ data class VaultAddEditLoginTypeHandlers(
VaultAddEditAction.ItemType.LoginType.ClearTotpKeyClick,
)
},
onPasswordVisibilityChange = {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.PasswordVisibilityChange(it),
)
},
)
}
}

View file

@ -20,6 +20,7 @@ import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.isPopup
import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onLast
import androidx.compose.ui.test.onNodeWithContentDescription
@ -466,6 +467,24 @@ class VaultAddEditScreenTest : BaseComposeTest() {
.assertDoesNotExist()
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state changing password visibility state should send PasswordVisibilityChange`() {
composeTestRule
.onNodeWithTextAfterScroll(text = "Password")
.assertExists()
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Show")
.assertExists()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.PasswordVisibilityChange(isVisible = true),
)
}
}
@Test
fun `in ItemType_Login state changing Username text field should trigger UsernameTextChange`() {
composeTestRule
@ -1671,6 +1690,30 @@ class VaultAddEditScreenTest : BaseComposeTest() {
}
}
@Test
fun `in ItemType_Card changing number visibility should trigger NumberVisibilityChange`() {
mutableStateFlow.value = DEFAULT_STATE_CARD.copy(
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(number = "12345"),
isIndividualVaultDisabled = false,
),
)
composeTestRule
.onNodeWithTextAfterScroll(text = "Number")
.assertExists()
.onChildren()
.filterToOne(hasContentDescription(value = "Show"))
.assertExists()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.NumberVisibilityChange(isVisible = true),
)
}
}
@Test
fun `in ItemType_Card the number text field should display the text provided by the state`() {
mutableStateFlow.value = DEFAULT_STATE_CARD
@ -1831,6 +1874,30 @@ class VaultAddEditScreenTest : BaseComposeTest() {
}
}
@Test
fun `in ItemType_Card changing code visibility should trigger SecurityCodeVisibilityChange`() {
mutableStateFlow.value = DEFAULT_STATE_CARD.copy(
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(),
type = VaultAddEditState.ViewState.Content.ItemType.Card(number = "12345"),
isIndividualVaultDisabled = false,
),
)
composeTestRule
.onNodeWithTextAfterScroll(text = "Security code")
.assertExists()
.onChildren()
.filterToOne(hasContentDescription(value = "Show"))
.assertExists()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.SecurityCodeVisibilityChange(isVisible = true),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Card the security code text field should display the text provided by the state`() {
@ -2373,6 +2440,40 @@ class VaultAddEditScreenTest : BaseComposeTest() {
}
}
@Test
fun `changing hidden field visibility state should send HiddenFieldVisibilityChange`() {
mutableStateFlow.update {
it.copy(
viewState = VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common(
customFieldData = listOf(
VaultAddEditState.Custom.HiddenField(
itemId = "itemId",
name = "Hidden item",
value = "I am hiding",
),
),
),
type = VaultAddEditState.ViewState.Content.ItemType.Login(),
isIndividualVaultDisabled = false,
),
)
}
composeTestRule
.onNodeWithTextAfterScroll(text = "Hidden item")
.assertExists()
composeTestRule
.onAllNodesWithContentDescriptionAfterScroll(label = "Show")
.onLast()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(
VaultAddEditAction.Common.HiddenFieldVisibilityChange(isVisible = true),
)
}
}
@Test
fun `clicking and changing the custom text field will send a CustomFieldValueChange event`() {
mutableStateFlow.value = DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS

View file

@ -1205,6 +1205,32 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
assertEquals(expectedState, viewModel.stateFlow.value)
}
@Suppress("MaxLineLength")
@Test
fun `PasswordVisibilityChange should log an event when in edit mode and password is visible`() =
runTest {
val vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "vault_item_id")
val viewModel = createAddVaultItemViewModel(
savedStateHandle = loginInitialSavedStateHandle.apply {
set("state", loginInitialState.copy(vaultAddEditType = vaultAddEditType))
set("vault_add_edit_type", vaultAddEditType)
},
)
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.PasswordVisibilityChange(
isVisible = true,
),
)
verify(exactly = 1) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledPasswordVisible(
cipherId = "vault_item_id",
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `OpenUsernameGeneratorClick should emit NavigateToGeneratorModal with username GeneratorMode`() =
@ -1920,6 +1946,53 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `NumberVisibilityChange should log an event when in edit mode and password is visible`() =
runTest {
val vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "vault_item_id")
val viewModel = createAddVaultItemViewModel(
savedStateHandle = loginInitialSavedStateHandle.apply {
set("state", loginInitialState.copy(vaultAddEditType = vaultAddEditType))
set("vault_add_edit_type", vaultAddEditType)
},
)
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.NumberVisibilityChange(isVisible = true),
)
verify(exactly = 1) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledCardNumberVisible(
cipherId = "vault_item_id",
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `SecurityCodeVisibilityChange should log an event when in edit mode and password is visible`() =
runTest {
val vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "vault_item_id")
val viewModel = createAddVaultItemViewModel(
savedStateHandle = loginInitialSavedStateHandle.apply {
set("state", loginInitialState.copy(vaultAddEditType = vaultAddEditType))
set("vault_add_edit_type", vaultAddEditType)
},
)
viewModel.trySendAction(
VaultAddEditAction.ItemType.CardType.SecurityCodeVisibilityChange(isVisible = true),
)
verify(exactly = 1) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledCardCodeVisible(
cipherId = "vault_item_id",
),
)
}
}
@Nested
inner class VaultAddEditCommonActions {
private lateinit var viewModel: VaultAddEditViewModel
@ -2371,6 +2444,30 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
)
}
@Suppress("MaxLineLength")
@Test
fun `HiddenFieldVisibilityChange should log an event when in edit mode and password is visible`() =
runTest {
val vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "vault_item_id")
val viewModel = createAddVaultItemViewModel(
savedStateHandle = loginInitialSavedStateHandle.apply {
set("state", loginInitialState.copy(vaultAddEditType = vaultAddEditType))
set("vault_add_edit_type", vaultAddEditType)
},
)
viewModel.trySendAction(
VaultAddEditAction.Common.HiddenFieldVisibilityChange(isVisible = true),
)
verify(exactly = 1) {
organizationEventManager.trackEvent(
event = OrganizationEvent.CipherClientToggledHiddenFieldVisible(
cipherId = "vault_item_id",
)
)
}
}
@Test
fun `TooltipClick should emit NavigateToToolTipUri`() = runTest {
viewModel.eventFlow.test {