mirror of
https://github.com/bitwarden/android.git
synced 2026-10-23 11:33:22 -05:00
BIT-462: Add UI for custom vault timeout (#576)
This commit is contained in:
1 parent
ff9dd81c55
commit
7e0a14d3a0
5 files changed
+252
-18
No files matched your search
+112
-2
@@ -8,6 +8,7 @@ import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.hasClickAction
|
||||
import androidx.compose.ui.test.hasTextExactly
|
||||
import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
@@ -33,6 +34,7 @@ import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
|
||||
private var onNavigateBackCalled = false
|
||||
@@ -134,7 +136,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
.filterToOne(hasClickAction())
|
||||
.performScrollTo()
|
||||
.assertTextEquals("Session timeout", "30 minutes")
|
||||
mutableStateFlow.update { it.copy(vaultTimeoutType = VaultTimeout.Type.FOUR_HOURS) }
|
||||
mutableStateFlow.update { it.copy(vaultTimeout = VaultTimeout.FourHours) }
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Session timeout")
|
||||
.filterToOne(hasClickAction())
|
||||
@@ -345,6 +347,114 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom session timeout should update according to state`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("Custom")
|
||||
.assertDoesNotExist()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 0))
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
// Check for exact text to differentiate from the Custom label on the Vault Timeout
|
||||
// item above.
|
||||
.onNode(hasTextExactly("Custom", "00:00"))
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 123))
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasTextExactly("Custom", "02:03"))
|
||||
.assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 1234))
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasTextExactly("Custom", "20:34"))
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom session timeout click should show a time-picker dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 123))
|
||||
}
|
||||
composeTestRule
|
||||
.onNode(hasTextExactly("Custom", "02:03"))
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Time")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Cancel")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Ok")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom session timeout dialog Cancel click should dismiss the dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 123))
|
||||
}
|
||||
composeTestRule
|
||||
.onNode(hasTextExactly("Custom", "02:03"))
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Cancel")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `custom session timeout dialog Ok click should dismiss the dialog and send CustomVaultTimeoutSelect`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 123))
|
||||
}
|
||||
composeTestRule
|
||||
.onNode(hasTextExactly("Custom", "02:03"))
|
||||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Ok")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.CustomVaultTimeoutSelect(
|
||||
VaultTimeout.Custom(vaultTimeoutInMinutes = 123),
|
||||
),
|
||||
)
|
||||
}
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on session timeout action click should show a selection dialog`() {
|
||||
composeTestRule.assertNoDialogExists()
|
||||
@@ -598,7 +708,7 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
||||
isApproveLoginRequestsEnabled = false,
|
||||
isUnlockWithBiometricsEnabled = false,
|
||||
isUnlockWithPinEnabled = false,
|
||||
vaultTimeoutType = VaultTimeout.Type.THIRTY_MINUTES,
|
||||
vaultTimeout = VaultTimeout.ThirtyMinutes,
|
||||
vaultTimeoutAction = VaultTimeoutAction.LOCK,
|
||||
)
|
||||
}
|
||||
|
||||
+30
-2
@@ -139,13 +139,41 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
vaultTimeoutType = VaultTimeout.Type.FOUR_HOURS,
|
||||
vaultTimeout = VaultTimeout.FourHours,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify { settingsRepository.vaultTimeout = VaultTimeout.FourHours }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CustomVaultTimeoutSelect should update the selection and emit ShowToast()`() = runTest {
|
||||
val settingsRepository = mockk<SettingsRepository>() {
|
||||
every { vaultTimeout = any() } just runs
|
||||
}
|
||||
val viewModel = createViewModel(settingsRepository = settingsRepository)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.CustomVaultTimeoutSelect(
|
||||
customVaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 360),
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
AccountSecurityEvent.ShowToast("Not yet implemented.".asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 360),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify {
|
||||
settingsRepository.vaultTimeout = VaultTimeout.Custom(vaultTimeoutInMinutes = 360)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on VaultTimeoutActionSelect should update vault timeout action`() = runTest {
|
||||
val settingsRepository = mockk<SettingsRepository>() {
|
||||
@@ -263,7 +291,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
||||
isApproveLoginRequestsEnabled = false,
|
||||
isUnlockWithBiometricsEnabled = false,
|
||||
isUnlockWithPinEnabled = false,
|
||||
vaultTimeoutType = VaultTimeout.Type.THIRTY_MINUTES,
|
||||
vaultTimeout = VaultTimeout.ThirtyMinutes,
|
||||
vaultTimeoutAction = VaultTimeoutAction.LOCK,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user