mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
Add additional test coverage for vault screen (#228)
This commit is contained in:
parent
bcffbe6fce
commit
7016c2a1ce
2 changed files with 286 additions and 56 deletions
|
@ -62,7 +62,9 @@ fun VaultContent(
|
|||
label = favoriteItem.name(),
|
||||
supportingLabel = favoriteItem.supportingLabel?.invoke(),
|
||||
onClick = { vaultItemClick(favoriteItem) },
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -70,7 +72,9 @@ fun VaultContent(
|
|||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant,
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +99,9 @@ fun VaultContent(
|
|||
label = stringResource(id = R.string.type_login),
|
||||
supportingLabel = state.loginItemsCount.toString(),
|
||||
onClick = loginGroupClick,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -105,7 +111,9 @@ fun VaultContent(
|
|||
label = stringResource(id = R.string.type_card),
|
||||
supportingLabel = state.cardItemsCount.toString(),
|
||||
onClick = cardGroupClick,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -115,7 +123,9 @@ fun VaultContent(
|
|||
label = stringResource(id = R.string.type_identity),
|
||||
supportingLabel = state.identityItemsCount.toString(),
|
||||
onClick = identityGroupClick,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,7 +135,9 @@ fun VaultContent(
|
|||
label = stringResource(id = R.string.type_secure_note),
|
||||
supportingLabel = state.secureNoteItemsCount.toString(),
|
||||
onClick = secureNoteGroupClick,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -134,7 +146,9 @@ fun VaultContent(
|
|||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant,
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -156,9 +170,11 @@ fun VaultContent(
|
|||
VaultGroupListItem(
|
||||
startIcon = painterResource(id = R.drawable.ic_folder),
|
||||
label = folder.name(),
|
||||
supportingLabel = state.folderItems.count().toString(),
|
||||
supportingLabel = folder.itemCount.toString(),
|
||||
onClick = { folderClick(folder) },
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +184,9 @@ fun VaultContent(
|
|||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant,
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -198,7 +216,9 @@ fun VaultContent(
|
|||
HorizontalDivider(
|
||||
thickness = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant,
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.vault
|
||||
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasClickAction
|
||||
import androidx.compose.ui.test.hasScrollToNodeAction
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
|
@ -66,96 +72,289 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a login item should send LoginGroupClick action`() {
|
||||
fun `clicking a favorite item should send VaultItemClick with the correct item`() {
|
||||
val itemText = "Test Item"
|
||||
val username = "BitWarden"
|
||||
val vaultItem = VaultState.ViewState.VaultItem.Login(
|
||||
id = "12345",
|
||||
name = itemText.asText(),
|
||||
username = username.asText(),
|
||||
)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = VaultState.ViewState.Content(
|
||||
loginItemsCount = 0,
|
||||
cardItemsCount = 0,
|
||||
identityItemsCount = 0,
|
||||
secureNoteItemsCount = 0,
|
||||
favoriteItems = emptyList(),
|
||||
folderItems = emptyList(),
|
||||
noFolderItems = emptyList(),
|
||||
trashItemsCount = 0,
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
favoriteItems = listOf(vaultItem),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Login").performScrollTo().performClick()
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(itemText))
|
||||
// Header
|
||||
composeTestRule
|
||||
.onNodeWithText("Favorites")
|
||||
.assertTextEquals("Favorites", 1.toString())
|
||||
// Item
|
||||
composeTestRule
|
||||
.onNodeWithText(itemText)
|
||||
.assertTextEquals(itemText, username)
|
||||
.performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.VaultItemClick(vaultItem))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a folder item should send FolderClick with the correct item`() {
|
||||
val folderText = "Test Folder"
|
||||
val count = 3
|
||||
val folderItem = VaultState.ViewState.FolderItem(
|
||||
id = "12345",
|
||||
name = folderText.asText(),
|
||||
itemCount = count,
|
||||
)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
folderItems = listOf(folderItem),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(folderText))
|
||||
composeTestRule
|
||||
.onNodeWithText(folderText)
|
||||
.assertTextEquals(folderText, count.toString())
|
||||
.performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.FolderClick(folderItem))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a no folder item should send VaultItemClick with the correct item`() {
|
||||
val itemText = "Test Item"
|
||||
val userName = "BitWarden"
|
||||
val vaultItem = VaultState.ViewState.VaultItem.Login(
|
||||
id = "12345",
|
||||
name = itemText.asText(),
|
||||
username = userName.asText(),
|
||||
)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
noFolderItems = listOf(vaultItem),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(itemText))
|
||||
composeTestRule
|
||||
.onNodeWithText(itemText)
|
||||
.assertTextEquals(itemText, userName)
|
||||
.performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.VaultItemClick(vaultItem))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login item count should update according to state`() {
|
||||
val rowText = "Login"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, 0.toString())
|
||||
|
||||
val count = 45
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
loginItemsCount = count,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, count.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a login item should send LoginGroupClick action`() {
|
||||
val rowText = "Login"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.LoginGroupClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a card item should send CardGroupClick action`() {
|
||||
fun `card item count should update according to state`() {
|
||||
val rowText = "Card"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, 0.toString())
|
||||
|
||||
val count = 3
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = VaultState.ViewState.Content(
|
||||
loginItemsCount = 0,
|
||||
cardItemsCount = 0,
|
||||
identityItemsCount = 0,
|
||||
secureNoteItemsCount = 0,
|
||||
favoriteItems = emptyList(),
|
||||
folderItems = emptyList(),
|
||||
noFolderItems = emptyList(),
|
||||
trashItemsCount = 0,
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
cardItemsCount = count,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Card").performScrollTo().performClick()
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, count.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a card item should send CardGroupClick action`() {
|
||||
val rowText = "Card"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.CardGroupClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking an identity item should send IdentityGroupClick action`() {
|
||||
fun `identity item count should update according to state`() {
|
||||
val rowText = "Identity"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, 0.toString())
|
||||
|
||||
val count = 14
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = VaultState.ViewState.Content(
|
||||
loginItemsCount = 0,
|
||||
cardItemsCount = 0,
|
||||
identityItemsCount = 0,
|
||||
secureNoteItemsCount = 0,
|
||||
favoriteItems = emptyList(),
|
||||
folderItems = emptyList(),
|
||||
noFolderItems = emptyList(),
|
||||
trashItemsCount = 0,
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
identityItemsCount = count,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Identity").performScrollTo().performClick()
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, count.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking an identity item should send IdentityGroupClick action`() {
|
||||
val rowText = "Identity"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.IdentityGroupClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a secure note item should send SecureNoteGroupClick action`() {
|
||||
fun `secure note item count should update according to state`() {
|
||||
val rowText = "Secure note"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, 0.toString())
|
||||
|
||||
val count = 7
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = VaultState.ViewState.Content(
|
||||
loginItemsCount = 0,
|
||||
cardItemsCount = 0,
|
||||
identityItemsCount = 0,
|
||||
secureNoteItemsCount = 0,
|
||||
favoriteItems = emptyList(),
|
||||
folderItems = emptyList(),
|
||||
noFolderItems = emptyList(),
|
||||
trashItemsCount = 0,
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
secureNoteItemsCount = count,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Secure note").performScrollTo().performClick()
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).assertTextEquals(rowText, count.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking a secure note item should send SecureNoteGroupClick action`() {
|
||||
val rowText = "Secure note"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onNodeWithText(rowText).performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.SecureNoteGroupClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `trash count should update according to state`() {
|
||||
val rowText = "Trash"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
// Header
|
||||
composeTestRule
|
||||
.onAllNodes(hasText(rowText))
|
||||
.filterToOne(!hasClickAction())
|
||||
.assertTextEquals(rowText, 0.toString())
|
||||
// Item
|
||||
composeTestRule
|
||||
.onAllNodes(hasText(rowText))
|
||||
.filterToOne(hasClickAction())
|
||||
.assertTextEquals(rowText, 0.toString())
|
||||
|
||||
val trashCount = 5
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
|
||||
trashItemsCount = 5,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
// Header
|
||||
composeTestRule
|
||||
.onAllNodes(hasText(rowText))
|
||||
.filterToOne(!hasClickAction())
|
||||
.assertTextEquals(rowText, trashCount.toString())
|
||||
// Item
|
||||
composeTestRule
|
||||
.onAllNodes(hasText(rowText))
|
||||
.filterToOne(hasClickAction())
|
||||
.assertTextEquals(rowText, trashCount.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking trash item should send TrashClick action`() {
|
||||
val rowText = "Trash"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasScrollToNodeAction()).performScrollToNode(hasText(rowText))
|
||||
composeTestRule.onAllNodes(hasText(rowText)).filterToOne(hasClickAction()).performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(VaultAction.TrashClick)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val DEFAULT_STATE: VaultState = VaultState(
|
||||
|
@ -163,3 +362,14 @@ private val DEFAULT_STATE: VaultState = VaultState(
|
|||
initials = "BW",
|
||||
viewState = VaultState.ViewState.Loading,
|
||||
)
|
||||
|
||||
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(
|
||||
loginItemsCount = 0,
|
||||
cardItemsCount = 0,
|
||||
identityItemsCount = 0,
|
||||
secureNoteItemsCount = 0,
|
||||
favoriteItems = emptyList(),
|
||||
folderItems = emptyList(),
|
||||
noFolderItems = emptyList(),
|
||||
trashItemsCount = 0,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue