BIT-2216: Add remove account option from account summary long-press (#1300)

This commit is contained in:
David Perez 2024-04-23 14:00:43 -05:00 committed by Álison Fernandes
parent 7127347028
commit 4326630d10
8 changed files with 316 additions and 20 deletions

View file

@ -49,6 +49,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBackground
import com.x8bit.bitwarden.ui.platform.base.util.toSafeOverlayColor
import com.x8bit.bitwarden.ui.platform.base.util.toUnscaledTextUnit
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLogoutConfirmationDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenRemovalConfirmationDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenSelectionDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.row.BitwardenBasicDialogRow
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
@ -116,6 +117,7 @@ fun BitwardenAccountSwitcher(
var lockOrLogoutAccount by remember { mutableStateOf<AccountSummary?>(null) }
var logoutConfirmationAccount by remember { mutableStateOf<AccountSummary?>(null) }
var removeConfirmationAccount by remember { mutableStateOf<AccountSummary?>(null) }
when {
isVisibleActual -> {
// Can not show dialogs when the switcher itself is visible
@ -133,6 +135,10 @@ fun BitwardenAccountSwitcher(
lockOrLogoutAccount = null
logoutConfirmationAccount = it
},
onRemoveAccountClick = {
lockOrLogoutAccount = null
removeConfirmationAccount = it
},
)
}
@ -146,6 +152,17 @@ fun BitwardenAccountSwitcher(
},
)
}
removeConfirmationAccount != null -> {
BitwardenRemovalConfirmationDialog(
accountSummary = requireNotNull(removeConfirmationAccount),
onDismissRequest = { removeConfirmationAccount = null },
onConfirmClick = {
onLogoutAccountClick(requireNotNull(removeConfirmationAccount))
removeConfirmationAccount = null
},
)
}
}
Box(modifier = modifier) {
@ -337,6 +354,7 @@ private fun LockOrLogoutDialog(
onDismissRequest: () -> Unit,
onLockAccountClick: (AccountSummary) -> Unit,
onLogoutAccountClick: (AccountSummary) -> Unit,
onRemoveAccountClick: (AccountSummary) -> Unit,
) {
BitwardenSelectionDialog(
title = "${accountSummary.email}\n${accountSummary.environmentLabel}",
@ -350,12 +368,21 @@ private fun LockOrLogoutDialog(
},
)
}
BitwardenBasicDialogRow(
text = stringResource(id = R.string.log_out),
onClick = {
onLogoutAccountClick(accountSummary)
},
)
if (accountSummary.isLoggedIn) {
BitwardenBasicDialogRow(
text = stringResource(id = R.string.log_out),
onClick = {
onLogoutAccountClick(accountSummary)
},
)
} else {
BitwardenBasicDialogRow(
text = stringResource(id = R.string.remove_account),
onClick = {
onRemoveAccountClick(accountSummary)
},
)
}
},
)
}

View file

@ -0,0 +1,39 @@
package com.x8bit.bitwarden.ui.platform.components.dialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
/**
* A reusable dialog for confirming whether or not the user wants to remove their account.
*
* @param onDismissRequest A callback for when the dialog is requesting dismissal.
* @param onConfirmClick A callback for when the log out confirmation button is clicked.
* @param accountSummary Optional account information that may be used to provide additional
* information.
*/
@Composable
fun BitwardenRemovalConfirmationDialog(
onDismissRequest: () -> Unit,
onConfirmClick: () -> Unit,
accountSummary: AccountSummary? = null,
) {
BitwardenTwoButtonDialog(
title = stringResource(id = R.string.remove_account),
message = removalConfirmationMessage(accountSummary = accountSummary),
confirmButtonText = stringResource(id = R.string.yes),
onConfirmClick = onConfirmClick,
dismissButtonText = stringResource(id = R.string.cancel),
onDismissClick = onDismissRequest,
onDismissRequest = onDismissRequest,
)
}
@Composable
private fun removalConfirmationMessage(accountSummary: AccountSummary?): String {
val baseConfirmationMessage = stringResource(id = R.string.remove_account_confirmation)
return accountSummary
?.let { "$baseConfirmationMessage\n\n${it.email}\n${it.environmentLabel}" }
?: baseConfirmationMessage
}

View file

@ -24,6 +24,7 @@ import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.assertRemovalConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed
import com.x8bit.bitwarden.ui.util.performAccountClick
@ -31,7 +32,8 @@ import com.x8bit.bitwarden.ui.util.performAccountIconClick
import com.x8bit.bitwarden.ui.util.performAccountLongClick
import com.x8bit.bitwarden.ui.util.performLockAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick
import com.x8bit.bitwarden.ui.util.performRemoveAccountClick
import com.x8bit.bitwarden.ui.util.performYesDialogButtonClick
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@ -182,12 +184,46 @@ class LandingScreenTest : BaseComposeTest() {
composeTestRule.performAccountLongClick(ACTIVE_ACCOUNT_SUMMARY)
composeTestRule.performLogoutAccountClick()
composeTestRule.performLogoutAccountConfirmationClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(LandingAction.LogoutAccountClick(ACTIVE_ACCOUNT_SUMMARY)) }
composeTestRule.assertNoDialogExists()
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the lock-or-logout dialog should show the remove account confirmation dialog and hide the lock-or-logout dialog`() {
// Show the lock-or-logout dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.assertRemovalConfirmationDialogIsDisplayed(activeAccountSummary)
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the remove account confirmation dialog should send LogoutAccountClick action and close the dialog`() {
// Show the remove account confirmation dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(LandingAction.LogoutAccountClick(activeAccountSummary)) }
composeTestRule.assertNoDialogExists()
}
@Test
fun `continue button should be enabled or disabled according to the state`() {
composeTestRule.onNodeWithText("Continue").assertIsEnabled()

View file

@ -21,6 +21,7 @@ import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.assertRemovalConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed
import com.x8bit.bitwarden.ui.util.performAccountClick
@ -29,7 +30,8 @@ import com.x8bit.bitwarden.ui.util.performAccountLongClick
import com.x8bit.bitwarden.ui.util.performAddAccountClick
import com.x8bit.bitwarden.ui.util.performLockAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick
import com.x8bit.bitwarden.ui.util.performRemoveAccountClick
import com.x8bit.bitwarden.ui.util.performYesDialogButtonClick
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
@ -206,12 +208,46 @@ class LoginScreenTest : BaseComposeTest() {
composeTestRule.performAccountLongClick(ACTIVE_ACCOUNT_SUMMARY)
composeTestRule.performLogoutAccountClick()
composeTestRule.performLogoutAccountConfirmationClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(LoginAction.LogoutAccountClick(ACTIVE_ACCOUNT_SUMMARY)) }
composeTestRule.assertNoDialogExists()
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the lock-or-logout dialog should show the remove account confirmation dialog and hide the lock-or-logout dialog`() {
// Show the lock-or-logout dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.assertRemovalConfirmationDialogIsDisplayed(activeAccountSummary)
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the remove account confirmation dialog should send LogoutAccountClick action and close the dialog`() {
// Show the remove account confirmation dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(LoginAction.LogoutAccountClick(activeAccountSummary)) }
composeTestRule.assertNoDialogExists()
}
@Test
fun `log in with device button visibility should update according to state`() {
val buttonText = "Log in with device"

View file

@ -21,6 +21,7 @@ import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager
import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.assertRemovalConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed
import com.x8bit.bitwarden.ui.util.performAccountClick
@ -29,7 +30,8 @@ import com.x8bit.bitwarden.ui.util.performAccountLongClick
import com.x8bit.bitwarden.ui.util.performAddAccountClick
import com.x8bit.bitwarden.ui.util.performLockAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick
import com.x8bit.bitwarden.ui.util.performRemoveAccountClick
import com.x8bit.bitwarden.ui.util.performYesDialogButtonClick
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
@ -244,7 +246,7 @@ class VaultUnlockScreenTest : BaseComposeTest() {
composeTestRule.performAccountLongClick(ACTIVE_ACCOUNT_SUMMARY)
composeTestRule.performLogoutAccountClick()
composeTestRule.performLogoutAccountConfirmationClick()
composeTestRule.performYesDialogButtonClick()
verify {
viewModel.trySendAction(VaultUnlockAction.LogoutAccountClick(ACTIVE_ACCOUNT_SUMMARY))
@ -252,6 +254,42 @@ class VaultUnlockScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists()
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the lock-or-logout dialog should show the remove account confirmation dialog and hide the lock-or-logout dialog`() {
// Show the lock-or-logout dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.assertRemovalConfirmationDialogIsDisplayed(activeAccountSummary)
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the remove account confirmation dialog should send LogoutAccountClick action and close the dialog`() {
// Show the remove account confirmation dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.performYesDialogButtonClick()
verify {
viewModel.trySendAction(VaultUnlockAction.LogoutAccountClick(activeAccountSummary))
}
composeTestRule.assertNoDialogExists()
}
@Test
fun `logout click in the overflow menu should show the logout confirmation dialog`() {
// Confirm neither the popup nor the dialog are showing

View file

@ -89,7 +89,7 @@ fun ComposeContentTestRule.assertLockOrLogoutDialogIsDisplayed(
}
/**
* Asserts the logoung confirmation dialog is currently displayed with information from the given
* Asserts the logout confirmation dialog is currently displayed with information from the given
* [accountSummary].
*/
fun ComposeContentTestRule.assertLogoutConfirmationDialogIsDisplayed(
@ -116,6 +116,34 @@ fun ComposeContentTestRule.assertLogoutConfirmationDialogIsDisplayed(
.assertIsDisplayed()
}
/**
* Asserts the account removal confirmation dialog is currently displayed with information from
* the given [accountSummary].
*/
fun ComposeContentTestRule.assertRemovalConfirmationDialogIsDisplayed(
accountSummary: AccountSummary,
) {
this
.onNode(isDialog())
.assertIsDisplayed()
this
.onAllNodesWithText("Remove account")
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
this
.onAllNodesWithText("Are you sure you want to remove this account?", substring = true)
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
this
.onAllNodesWithText(accountSummary.email, substring = true)
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
this
.onAllNodesWithText(accountSummary.environmentLabel, substring = true)
.filterToOne(hasAnyAncestor(isDialog()))
.assertIsDisplayed()
}
/**
* Clicks on the given [accountSummary] in the account switcher.
*/
@ -147,7 +175,7 @@ fun ComposeContentTestRule.performLockAccountClick() {
}
/**
* Clicks the "Lock" button in the "lock or logout" dialog.
* Clicks the "log out" button in the "lock or logout" dialog.
*/
fun ComposeContentTestRule.performLogoutAccountClick() {
this
@ -157,9 +185,19 @@ fun ComposeContentTestRule.performLogoutAccountClick() {
}
/**
* Clicks the "Yes" button in the logout confirmation dialog to confirm the logout.
* Clicks the "Remove account" button in the "lock or logout" dialog.
*/
fun ComposeContentTestRule.performLogoutAccountConfirmationClick() {
fun ComposeContentTestRule.performRemoveAccountClick() {
this
.onAllNodesWithText("Remove account")
.filterToOne(hasAnyAncestor(isDialog()))
.performClick()
}
/**
* Clicks the "Yes" button in the account confirmation dialog to confirm the action.
*/
fun ComposeContentTestRule.performYesDialogButtonClick() {
this
.onAllNodesWithText("Yes")
.filterToOne(hasAnyAncestor(isDialog()))

View file

@ -33,6 +33,7 @@ import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertMasterPasswordDialogDisplayed
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.assertRemovalConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed
import com.x8bit.bitwarden.ui.util.isProgressBar
@ -42,7 +43,8 @@ import com.x8bit.bitwarden.ui.util.performAccountIconClick
import com.x8bit.bitwarden.ui.util.performAccountLongClick
import com.x8bit.bitwarden.ui.util.performLockAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick
import com.x8bit.bitwarden.ui.util.performRemoveAccountClick
import com.x8bit.bitwarden.ui.util.performYesDialogButtonClick
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
@ -261,7 +263,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
composeTestRule.performAccountLongClick(ACTIVE_ACCOUNT_SUMMARY)
composeTestRule.performLogoutAccountClick()
composeTestRule.performLogoutAccountConfirmationClick()
composeTestRule.performYesDialogButtonClick()
verify {
viewModel.trySendAction(
@ -271,6 +273,50 @@ class VaultItemListingScreenTest : BaseComposeTest() {
composeTestRule.assertNoDialogExists()
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the lock-or-logout dialog should show the remove account confirmation dialog and hide the lock-or-logout dialog`() {
// Show the lock-or-logout dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(
accountSummaries = listOf(activeAccountSummary),
autofillSelectionData = AUTOFILL_SELECTION_DATA,
)
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.assertRemovalConfirmationDialogIsDisplayed(activeAccountSummary)
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the remove account confirmation dialog should send LogoutAccountClick action and close the dialog`() {
// Show the remove account confirmation dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(
accountSummaries = listOf(activeAccountSummary),
autofillSelectionData = AUTOFILL_SELECTION_DATA,
)
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.performYesDialogButtonClick()
verify {
viewModel.trySendAction(
VaultItemListingsAction.LogoutAccountClick(activeAccountSummary),
)
}
composeTestRule.assertNoDialogExists()
}
@Test
fun `NavigateBack event should invoke NavigateBack`() {
mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateBack)

View file

@ -28,6 +28,7 @@ import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.assertRemovalConfirmationDialogIsDisplayed
import com.x8bit.bitwarden.ui.util.assertScrollableNodeDoesNotExist
import com.x8bit.bitwarden.ui.util.assertSwitcherIsDisplayed
import com.x8bit.bitwarden.ui.util.assertSwitcherIsNotDisplayed
@ -38,7 +39,8 @@ import com.x8bit.bitwarden.ui.util.performAccountLongClick
import com.x8bit.bitwarden.ui.util.performAddAccountClick
import com.x8bit.bitwarden.ui.util.performLockAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountClick
import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick
import com.x8bit.bitwarden.ui.util.performRemoveAccountClick
import com.x8bit.bitwarden.ui.util.performYesDialogButtonClick
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
@ -334,12 +336,46 @@ class VaultScreenTest : BaseComposeTest() {
composeTestRule.performAccountLongClick(ACTIVE_ACCOUNT_SUMMARY)
composeTestRule.performLogoutAccountClick()
composeTestRule.performLogoutAccountConfirmationClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(VaultAction.LogoutAccountClick(ACTIVE_ACCOUNT_SUMMARY)) }
composeTestRule.assertNoDialogExists()
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the lock-or-logout dialog should show the remove account confirmation dialog and hide the lock-or-logout dialog`() {
// Show the lock-or-logout dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.assertRemovalConfirmationDialogIsDisplayed(activeAccountSummary)
}
@Suppress("MaxLineLength")
@Test
fun `remove account button click in the remove account confirmation dialog should send LogoutAccountClick action and close the dialog`() {
// Show the remove account confirmation dialog
val activeAccountSummary = ACTIVE_ACCOUNT_SUMMARY.copy(isLoggedIn = false)
mutableStateFlow.update {
it.copy(accountSummaries = listOf(activeAccountSummary))
}
composeTestRule.performAccountIconClick()
composeTestRule.performAccountLongClick(activeAccountSummary)
composeTestRule.performRemoveAccountClick()
composeTestRule.performYesDialogButtonClick()
verify { viewModel.trySendAction(VaultAction.LogoutAccountClick(activeAccountSummary)) }
composeTestRule.assertNoDialogExists()
}
@Test
fun `overflow button click should show the overflow menu`() {
composeTestRule.onNode(isPopup()).assertDoesNotExist()