From b7d5de3b6d95c8152db576efee37b453c9251eb4 Mon Sep 17 00:00:00 2001 From: Brian Yencho Date: Mon, 11 Dec 2023 09:29:10 -0600 Subject: [PATCH] Add account switcher test helpers (#360) --- .../auth/feature/landing/LandingScreenTest.kt | 38 +++++----- .../ui/auth/feature/login/LoginScreenTest.kt | 38 +++++----- .../vaultunlock/VaultUnlockScreenTest.kt | 48 ++++++++----- .../BitwardenAccountSwitcherTestHelpers.kt | 72 +++++++++++++++++++ .../ui/vault/feature/vault/VaultScreenTest.kt | 41 +++++++---- 5 files changed, 165 insertions(+), 72 deletions(-) create mode 100644 app/src/test/java/com/x8bit/bitwarden/ui/util/BitwardenAccountSwitcherTestHelpers.kt diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingScreenTest.kt index 7f95adbfbc..8f08c61868 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingScreenTest.kt @@ -22,6 +22,10 @@ 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.model.AccountSummary +import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed +import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed +import com.x8bit.bitwarden.ui.util.performAccountIconClick +import com.x8bit.bitwarden.ui.util.performAccountClick import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -77,43 +81,37 @@ class LandingScreenTest : BaseComposeTest() { @Test fun `account menu icon click should show the account switcher`() { + val accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY) mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) + it.copy(accountSummaries = accountSummaries) } - composeTestRule.onNodeWithContentDescription("Account").performClick() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() + composeTestRule.assertSwitcherIsDisplayed( + accountSummaries = accountSummaries, + isAddAccountButtonVisible = false, + ) } @Suppress("MaxLineLength") @Test fun `account click in the account switcher should send SwitchAccountClick and close switcher`() { // Show the account switcher + val accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY) mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) + it.copy(accountSummaries = accountSummaries) } - composeTestRule.onNodeWithContentDescription("Account").performClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").performClick() + composeTestRule.performAccountClick(accountSummary = ACTIVE_ACCOUNT_SUMMARY) verify { viewModel.trySendAction(LandingAction.SwitchAccountClick(ACTIVE_ACCOUNT_SUMMARY)) } - composeTestRule.onNodeWithText("active@bitwarden.com").assertDoesNotExist() - } - - @Test - fun `add account button in the account switcher does not exist`() { - // Show the account switcher - mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) - } - composeTestRule.onNodeWithContentDescription("Account").performClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() - - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = accountSummaries, + ) } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginScreenTest.kt index 5660cb6953..53c1089e56 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginScreenTest.kt @@ -18,6 +18,10 @@ import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler import com.x8bit.bitwarden.ui.platform.components.BasicDialogState import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary +import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed +import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed +import com.x8bit.bitwarden.ui.util.performAccountIconClick +import com.x8bit.bitwarden.ui.util.performAccountClick import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -66,43 +70,37 @@ class LoginScreenTest : BaseComposeTest() { @Test fun `account menu icon click should show the account switcher`() { + val accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY) mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) + it.copy(accountSummaries = accountSummaries) } - composeTestRule.onNodeWithContentDescription("Account").performClick() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() + composeTestRule.assertSwitcherIsDisplayed( + accountSummaries = accountSummaries, + isAddAccountButtonVisible = false, + ) } @Suppress("MaxLineLength") @Test fun `account click in the account switcher should send SwitchAccountClick and close switcher`() { // Show the account switcher + val accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY) mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) + it.copy(accountSummaries = accountSummaries) } - composeTestRule.onNodeWithContentDescription("Account").performClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").performClick() + composeTestRule.performAccountClick(accountSummary = ACTIVE_ACCOUNT_SUMMARY) verify { viewModel.trySendAction(LoginAction.SwitchAccountClick(ACTIVE_ACCOUNT_SUMMARY)) } - composeTestRule.onNodeWithText("active@bitwarden.com").assertDoesNotExist() - } - - @Test - fun `add account button in the account switcher does not exist`() { - // Show the account switcher - mutableStateFlow.update { - it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY)) - } - composeTestRule.onNodeWithContentDescription("Account").performClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() - - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = accountSummaries, + ) } @Test diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockScreenTest.kt index be1caa87bd..23e63161c5 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockScreenTest.kt @@ -15,10 +15,14 @@ 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.components.model.AccountSummary +import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed +import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed +import com.x8bit.bitwarden.ui.util.performAccountClick +import com.x8bit.bitwarden.ui.util.performAccountIconClick +import com.x8bit.bitwarden.ui.util.performAddAccountClick import io.mockk.every import io.mockk.mockk import io.mockk.verify -import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update @@ -47,39 +51,45 @@ class VaultUnlockScreenTest : BaseComposeTest() { @Test fun `account icon click should show the account switcher`() { - composeTestRule.onNodeWithText("active@bitwarden.com").assertDoesNotExist() - composeTestRule.onNodeWithText("locked@bitwarden.com").assertDoesNotExist() - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = ACCOUNT_SUMMARIES, + ) - composeTestRule.onNodeWithText("AU").performClick() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() - composeTestRule.onNodeWithText("locked@bitwarden.com").assertIsDisplayed() - composeTestRule.onNodeWithText("Add account").assertIsDisplayed() + composeTestRule.assertSwitcherIsDisplayed( + accountSummaries = ACCOUNT_SUMMARIES, + ) } @Suppress("MaxLineLength") @Test fun `account click in the account switcher should send AccountSwitchClick and close switcher`() { // Open the Account Switcher - composeTestRule.onNodeWithText("AU").performClick() + composeTestRule.performAccountIconClick() + + composeTestRule.performAccountClick(accountSummary = LOCKED_ACCOUNT_SUMMARY) - composeTestRule.onNodeWithText("locked@bitwarden.com").performClick() verify { viewModel.trySendAction(VaultUnlockAction.SwitchAccountClick(LOCKED_ACCOUNT_SUMMARY)) } - composeTestRule.onNodeWithText("locked@bitwarden.com").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = ACCOUNT_SUMMARIES, + ) } @Suppress("MaxLineLength") @Test fun `add account click in the account switcher should send AddAccountClick and close switcher`() { // Open the Account Switcher - composeTestRule.onNodeWithText("AU").performClick() + composeTestRule.performAccountIconClick() + + composeTestRule.performAddAccountClick() - composeTestRule.onNodeWithText("Add account").performClick() verify { viewModel.trySendAction(VaultUnlockAction.AddAccountClick) } - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = ACCOUNT_SUMMARIES, + ) } @Test @@ -208,11 +218,13 @@ private val LOCKED_ACCOUNT_SUMMARY = AccountSummary( status = AccountSummary.Status.LOCKED, ) +private val ACCOUNT_SUMMARIES = listOf( + ACTIVE_ACCOUNT_SUMMARY, + LOCKED_ACCOUNT_SUMMARY, +) + private val DEFAULT_STATE: VaultUnlockState = VaultUnlockState( - accountSummaries = persistentListOf( - ACTIVE_ACCOUNT_SUMMARY, - LOCKED_ACCOUNT_SUMMARY, - ), + accountSummaries = ACCOUNT_SUMMARIES, avatarColorString = "0000FF", dialog = null, email = "bit@bitwarden.com", diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/util/BitwardenAccountSwitcherTestHelpers.kt b/app/src/test/java/com/x8bit/bitwarden/ui/util/BitwardenAccountSwitcherTestHelpers.kt new file mode 100644 index 0000000000..03bd9462c8 --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/ui/util/BitwardenAccountSwitcherTestHelpers.kt @@ -0,0 +1,72 @@ +package com.x8bit.bitwarden.ui.util + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary + +private const val ACCOUNT = "Account" +private const val ADD_ACCOUNT = "Add account" + +/** + * Asserts that the account switcher is visible and displaying information for the given + * [accountSummaries]. The existence of the "Add account" button can be asserted with + * [isAddAccountButtonVisible]. + */ +fun ComposeContentTestRule.assertSwitcherIsDisplayed( + accountSummaries: List, + isAddAccountButtonVisible: Boolean = true, +) { + accountSummaries.forEach { accountSummary -> + this.onNodeWithText(accountSummary.email).assertIsDisplayed() + } + + if (isAddAccountButtonVisible) { + this.onNodeWithText(ADD_ACCOUNT).assertIsDisplayed() + } else { + this.onNodeWithText(ADD_ACCOUNT).assertDoesNotExist() + } +} + +/** + * Asserts that the account switcher is not visible by looking for information from the given + * [accountSummaries] and by checking for the "Add account" item. + */ +fun ComposeContentTestRule.assertSwitcherIsNotDisplayed( + accountSummaries: List, +) { + accountSummaries.forEach { accountSummary -> + this.onNodeWithText(accountSummary.email).assertDoesNotExist() + } + this.onNodeWithText(ADD_ACCOUNT).assertDoesNotExist() +} + +/** + * Clicks on the given [accountSummary] in the account switcher. + */ +fun ComposeContentTestRule.performAccountClick( + accountSummary: AccountSummary, +) { + this.onNodeWithText(accountSummary.email).performClick() +} + +/** + * Opens the account switcher. + * + * This is controlled by clicking on an element with the given [targetContentDescription]. + */ +fun ComposeContentTestRule.performAccountIconClick( + targetContentDescription: String = ACCOUNT, +) { + this.onNodeWithContentDescription(targetContentDescription).performClick() +} + +/** + * Clicks on the "Add account" item. Note that this assumes the Account Switcher is currently + * visible. + */ +fun ComposeContentTestRule.performAddAccountClick() { + this.onNodeWithText(ADD_ACCOUNT).performClick() +} diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt index 3d85348baf..610696ca64 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultScreenTest.kt @@ -1,6 +1,5 @@ package com.x8bit.bitwarden.ui.vault.feature.vault -import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertTextEquals import androidx.compose.ui.test.filterToOne import androidx.compose.ui.test.hasClickAction @@ -13,6 +12,11 @@ import androidx.compose.ui.test.performScrollToNode import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary +import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed +import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed +import com.x8bit.bitwarden.ui.util.performAccountClick +import com.x8bit.bitwarden.ui.util.performAccountIconClick +import com.x8bit.bitwarden.ui.util.performAddAccountClick import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType import io.mockk.every import io.mockk.mockk @@ -61,16 +65,17 @@ class VaultScreenTest : BaseComposeTest() { @Suppress("MaxLineLength") @Test fun `account icon click should show the account switcher and trigger the nav bar dim request`() { - composeTestRule.onNodeWithText("active@bitwarden.com").assertDoesNotExist() - composeTestRule.onNodeWithText("locked@bitwarden.com").assertDoesNotExist() - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + val accountSummaries = DEFAULT_STATE.accountSummaries + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = accountSummaries, + ) assertFalse(onDimBottomNavBarRequestCalled) - composeTestRule.onNodeWithText("AU").performClick() + composeTestRule.performAccountIconClick() - composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed() - composeTestRule.onNodeWithText("locked@bitwarden.com").assertIsDisplayed() - composeTestRule.onNodeWithText("Add account").assertIsDisplayed() + composeTestRule.assertSwitcherIsDisplayed( + accountSummaries = accountSummaries, + ) assertTrue(onDimBottomNavBarRequestCalled) } @@ -78,22 +83,30 @@ class VaultScreenTest : BaseComposeTest() { @Test fun `account click in the account switcher should send AccountSwitchClick and close switcher`() { // Open the Account Switcher - composeTestRule.onNodeWithText("AU").performClick() + val accountSummaries = DEFAULT_STATE.accountSummaries + composeTestRule.performAccountIconClick() + + composeTestRule.performAccountClick(accountSummary = LOCKED_ACCOUNT_SUMMARY) - composeTestRule.onNodeWithText("locked@bitwarden.com").performClick() verify { viewModel.trySendAction(VaultAction.AccountSwitchClick(LOCKED_ACCOUNT_SUMMARY)) } - composeTestRule.onNodeWithText("locked@bitwarden.com").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = accountSummaries, + ) } @Suppress("MaxLineLength") @Test fun `Add Account click in the account switcher should send AddAccountClick and close switcher`() { // Open the Account Switcher - composeTestRule.onNodeWithText("AU").performClick() + val accountSummaries = DEFAULT_STATE.accountSummaries + composeTestRule.performAccountIconClick() + + composeTestRule.performAddAccountClick() - composeTestRule.onNodeWithText("Add account").performClick() verify { viewModel.trySendAction(VaultAction.AddAccountClick) } - composeTestRule.onNodeWithText("Add account").assertDoesNotExist() + composeTestRule.assertSwitcherIsNotDisplayed( + accountSummaries = accountSummaries, + ) } @Test