From f953066f22b3153169b853e52a8c59eccd92949a Mon Sep 17 00:00:00 2001 From: Ramsey Smith <142836716+ramsey-livefront@users.noreply.github.com> Date: Wed, 27 Dec 2023 14:15:12 -0700 Subject: [PATCH] BIT-667: UI for identity creation (Unit Tests) (#435) --- .../feature/additem/VaultAddItemScreenTest.kt | 573 +++++++++++++++++- .../additem/VaultAddItemViewModelTest.kt | 276 +++++++++ 2 files changed, 848 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemScreenTest.kt index 2d4a9382e..105627760 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemScreenTest.kt @@ -426,7 +426,549 @@ class VaultAddItemScreenTest : BaseComposeTest() { } } + @Test + fun `in ItemType_Identity selecting a title should trigger TitleSelected`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + // Opens the menu + composeTestRule + .onNodeWithContentDescriptionAfterScroll(label = "Title, Mr") + .performClick() + + // Choose the option from the menu + composeTestRule + .onAllNodesWithText(text = "Mx") + .onLast() + .performScrollTo() + .performClick() + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.TitleSelected( + title = VaultAddItemState.ViewState.Content.ItemType.Identity.Title.MX, + ), + ) + } + } + + @Test + fun `in ItemType_Identity the Title should display the selected title from the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithContentDescriptionAfterScroll(label = "Title, Mr") + .assertIsDisplayed() + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { + copy( + selectedTitle = VaultAddItemState.ViewState.Content.ItemType.Identity.Title.MX, + ) + } + } + + composeTestRule + .onNodeWithContentDescriptionAfterScroll(label = "Title, Mx") + .assertIsDisplayed() + } + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity changing the first name text field should trigger FirstNameTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "First name") + .performTextInput(text = "TestFirstName") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.FirstNameTextChange( + firstName = "TestFirstName", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the first name text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "First name") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(firstName = "NewFirstName") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "First name") + .assertTextContains("NewFirstName") + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity changing the middle name text field should trigger MiddleNameTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Middle name") + .performTextInput(text = "TestMiddleName") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.MiddleNameTextChange( + middleName = "TestMiddleName", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the middle name text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Middle name") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(middleName = "NewMiddleName") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Middle name") + .assertTextContains("NewMiddleName") + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity changing the last name text field should trigger LastNameTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Last name") + .performTextInput(text = "TestLastName") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.LastNameTextChange( + lastName = "TestLastName", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the last name text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Last name") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(lastName = "NewLastName") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Last name") + .assertTextContains("NewLastName") + } + + @Test + fun `in ItemType_Identity changing username text field should trigger UsernameTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Username") + .performTextInput(text = "TestUsername") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.UsernameTextChange( + username = "TestUsername", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the username text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Username") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(username = "NewUsername") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Username") + .assertTextContains("NewUsername") + } + + @Test + fun `in ItemType_Identity changing company text field should trigger CompanyTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Company") + .performTextInput(text = "TestCompany") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.CompanyTextChange( + company = "TestCompany", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the company text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Company") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(company = "NewCompany") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Company") + .assertTextContains("NewCompany") + } + + @Test + fun `in ItemType_Identity changing SSN text field should trigger CompanyTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Social Security number") + .performTextInput(text = "TestSsn") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.SsnTextChange( + ssn = "TestSsn", + ), + ) + } + } + + @Test + fun `in ItemType_Identity the SSN text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Social Security number") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(ssn = "NewSsn") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Social Security number") + .assertTextContains("NewSsn") + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity changing passport number text field should trigger PassportNumberTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Passport number") + .performTextInput(text = "TestPassportNumber") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.PassportNumberTextChange( + passportNumber = "TestPassportNumber", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the passport number text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Passport number") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(passportNumber = "NewPassportNumber") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Passport number") + .assertTextContains("NewPassportNumber") + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity changing license number text field should trigger LicenseNumberTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "License number") + .performTextInput(text = "TestLicenseNumber") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.LicenseNumberTextChange( + licenseNumber = "TestLicenseNumber", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the license number text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "License number") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(licenseNumber = "NewLicenseNumber") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "License number") + .assertTextContains("NewLicenseNumber") + } + + @Test + fun `in ItemType_Identity changing email text field should trigger EmailTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Email") + .performTextInput(text = "TestEmail") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.EmailTextChange( + email = "TestEmail", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the email text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Email") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(email = "NewEmail") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Email") + .assertTextContains("NewEmail") + } + + @Test + fun `in ItemType_Identity changing address1 text field should trigger Address1TextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 1") + .performTextInput(text = "TestAddress1") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.Address1TextChange( + address1 = "TestAddress1", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the address1 text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 1") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(address1 = "NewAddress1") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 1") + .assertTextContains("NewAddress1") + } + + @Test + fun `in ItemType_Identity changing address2 text field should trigger Address2TextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 2") + .performTextInput(text = "TestAddress2") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.Address2TextChange( + address2 = "TestAddress2", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the address2 text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 2") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(address2 = "NewAddress2") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 2") + .assertTextContains("NewAddress2") + } + + @Test + fun `in ItemType_Identity changing address3 text field should trigger Address3TextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 3") + .performTextInput(text = "TestAddress3") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.Address3TextChange( + address3 = "TestAddress3", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the address3 text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 3") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(address3 = "NewAddress3") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Address 3") + .assertTextContains("NewAddress3") + } + + @Test + fun `in ItemType_Identity changing city text field should trigger CityTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "City / Town") + .performTextInput(text = "TestCity") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.CityTextChange( + city = "TestCity", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the city text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "City / Town") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(city = "NewCity") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "City / Town") + .assertTextContains("NewCity") + } + + @Test + fun `in ItemType_Identity changing zip text field should trigger ZipTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Zip / Postal code") + .performTextInput(text = "TestZip") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.ZipTextChange( + zip = "TestZip", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the zip text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Zip / Postal code") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(zip = "NewZip") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Zip / Postal code") + .assertTextContains("NewZip") + } + + @Test + fun `in ItemType_Identity changing country text field should trigger CountryTextChange`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Country") + .performTextInput(text = "TestCountry") + + verify { + viewModel.trySendAction( + VaultAddItemAction.ItemType.IdentityType.CountryTextChange( + country = "TestCountry", + ), + ) + } + } + + @Suppress("MaxLineLength") + @Test + fun `in ItemType_Identity the country text field should display the text provided by the state`() { + mutableStateFlow.value = DEFAULT_STATE_IDENTITY + composeTestRule + .onNodeWithTextAfterScroll(text = "Country") + .assertTextContains("") + + mutableStateFlow.update { currentState -> + updateIdentityType(currentState) { copy(country = "NewCountry") } + } + + composeTestRule + .onNodeWithTextAfterScroll(text = "Country") + .assertTextContains("NewCountry") + } + @Test fun `clicking New Custom Field button should allow creation of Linked type`() { mutableStateFlow.value = DEFAULT_STATE_LOGIN @@ -923,7 +1465,6 @@ class VaultAddItemScreenTest : BaseComposeTest() { //region Helper functions - @Suppress("MaxLineLength") private fun updateLoginType( currentState: VaultAddItemState, transform: VaultAddItemState.ViewState.Content.ItemType.Login.() -> @@ -945,6 +1486,27 @@ class VaultAddItemScreenTest : BaseComposeTest() { return currentState.copy(viewState = updatedType) } + private fun updateIdentityType( + currentState: VaultAddItemState, + transform: VaultAddItemState.ViewState.Content.ItemType.Identity.() -> + VaultAddItemState.ViewState.Content.ItemType.Identity, + ): VaultAddItemState { + val updatedType = when (val viewState = currentState.viewState) { + is VaultAddItemState.ViewState.Content -> { + when (val type = viewState.type) { + is VaultAddItemState.ViewState.Content.ItemType.Identity -> { + viewState.copy( + type = type.transform(), + ) + } + else -> viewState + } + } + else -> viewState + } + return currentState.copy(viewState = updatedType) + } + @Suppress("MaxLineLength") private fun updateCommonContent( currentState: VaultAddItemState, @@ -980,6 +1542,15 @@ class VaultAddItemScreenTest : BaseComposeTest() { dialog = null, ) + private val DEFAULT_STATE_IDENTITY = VaultAddItemState( + vaultAddEditType = VaultAddEditType.AddItem, + viewState = VaultAddItemState.ViewState.Content( + common = VaultAddItemState.ViewState.Content.Common(), + type = VaultAddItemState.ViewState.Content.ItemType.Identity(), + ), + dialog = null, + ) + @Suppress("MaxLineLength") private val DEFAULT_STATE_SECURE_NOTES_CUSTOM_FIELDS = VaultAddItemState( viewState = VaultAddItemState.ViewState.Content( diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemViewModelTest.kt index 27bd463fe..8897479cc 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/additem/VaultAddItemViewModelTest.kt @@ -535,6 +535,282 @@ class VaultAddItemViewModelTest : BaseViewModelTest() { } } + @Nested + inner class VaultAddIdentityTypeItemActions { + private lateinit var viewModel: VaultAddItemViewModel + private lateinit var vaultAddItemInitialState: VaultAddItemState + private lateinit var identityInitialSavedStateHandle: SavedStateHandle + + @BeforeEach + fun setup() { + vaultAddItemInitialState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity(), + ) + identityInitialSavedStateHandle = createSavedStateHandleWithState( + state = vaultAddItemInitialState, + vaultAddEditType = VaultAddEditType.AddItem, + ) + viewModel = createAddVaultItemViewModel( + savedStateHandle = identityInitialSavedStateHandle, + ) + } + + @Test + fun `FirstNameTextChange should update first name`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.FirstNameTextChange( + firstName = "newFirstName", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + firstName = "newFirstName", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `MiddleNameTextChange should update middle name`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.MiddleNameTextChange( + middleName = "newMiddleName", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + middleName = "newMiddleName", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `LastNameTextChange should update last name`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.LastNameTextChange( + lastName = "newLastName", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + lastName = "newLastName", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `UsernameTextChange should update username`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.UsernameTextChange( + username = "newUsername", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + username = "newUsername", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `CompanyTextChange should update company`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.CompanyTextChange( + company = "newCompany", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + company = "newCompany", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `SsnTextChange should update SSN`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.SsnTextChange( + ssn = "newSsn", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + ssn = "newSsn", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `PassportNumberTextChange should update passport number`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.PassportNumberTextChange( + passportNumber = "newPassportNumber", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + passportNumber = "newPassportNumber", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `LicenseNumberTextChange should update license number`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.LicenseNumberTextChange( + licenseNumber = "newLicenseNumber", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + licenseNumber = "newLicenseNumber", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `EmailTextChange should update email`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.EmailTextChange( + email = "newEmail", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + email = "newEmail", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `PhoneTextChange should update phone`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.PhoneTextChange( + phone = "newPhone", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + phone = "newPhone", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `Address1TextChange should update address1`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.Address1TextChange( + address1 = "newAddress1", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + address1 = "newAddress1", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `Address2TextChange should update address2`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.Address2TextChange( + address2 = "newAddress2", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + address2 = "newAddress2", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `Address3TextChange should update address3`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.Address3TextChange( + address3 = "newAddress3", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + address3 = "newAddress3", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `CityTextChange should update city`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.CityTextChange( + city = "newCity", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + city = "newCity", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `ZipTextChange should update zip`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.ZipTextChange( + zip = "newZip", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + zip = "newZip", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `CountryTextChange should update country`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.CountryTextChange( + country = "newCountry", + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + country = "newCountry", + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + + @Test + fun `TitleSelected should update title`() = runTest { + val action = VaultAddItemAction.ItemType.IdentityType.TitleSelected( + title = VaultAddItemState.ViewState.Content.ItemType.Identity.Title.MX, + ) + val expectedState = createVaultAddItemState( + typeContentViewState = VaultAddItemState.ViewState.Content.ItemType.Identity( + selectedTitle = VaultAddItemState.ViewState.Content.ItemType.Identity.Title.MX, + ), + ) + viewModel.actionChannel.trySend(action) + + assertEquals(expectedState, viewModel.stateFlow.value) + } + } + @Nested inner class VaultAddItemCommonActions { private lateinit var viewModel: VaultAddItemViewModel