BIT-2078: Add element IDs for search screen (#1145)

This commit is contained in:
David Perez 2024-03-14 14:52:53 -05:00 committed by Álison Fernandes
parent 1a41fcb5c8
commit 888e079f09
17 changed files with 160 additions and 13 deletions

View File

@ -51,8 +51,10 @@ import kotlinx.collections.immutable.persistentListOf
* dialog. * dialog.
* @param modifier An optional [Modifier] for this Composable, defaulting to an empty Modifier. * @param modifier An optional [Modifier] for this Composable, defaulting to an empty Modifier.
* This allows the caller to specify things like padding, size, etc. * This allows the caller to specify things like padding, size, etc.
* @param labelTestTag The optional test tag for the [label].
* @param optionsTestTag The optional test tag for the options button. * @param optionsTestTag The optional test tag for the options button.
* @param supportingLabel An optional secondary text label to display beneath the label. * @param supportingLabel An optional secondary text label to display beneath the label.
* @param supportingLabelTestTag The optional test tag for the [supportingLabel].
* @param trailingLabelIcons An optional list of small icons to be displayed after the [label]. * @param trailingLabelIcons An optional list of small icons to be displayed after the [label].
*/ */
@Suppress("LongMethod") @Suppress("LongMethod")
@ -63,8 +65,10 @@ fun BitwardenListItem(
onClick: () -> Unit, onClick: () -> Unit,
selectionDataList: ImmutableList<SelectionItemData>, selectionDataList: ImmutableList<SelectionItemData>,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
labelTestTag: String? = null,
optionsTestTag: String? = null, optionsTestTag: String? = null,
supportingLabel: String? = null, supportingLabel: String? = null,
supportingLabelTestTag: String? = null,
trailingLabelIcons: ImmutableList<IconResource> = persistentListOf(), trailingLabelIcons: ImmutableList<IconResource> = persistentListOf(),
) { ) {
var shouldShowDialog by rememberSaveable { mutableStateOf(false) } var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
@ -98,25 +102,30 @@ fun BitwardenListItem(
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(weight = 1f, fill = false), modifier = Modifier
.semantics { labelTestTag?.let { testTag = it } }
.weight(weight = 1f, fill = false),
) )
trailingLabelIcons.forEach { trailingLabelIcons.forEach { iconResource ->
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Icon( Icon(
painter = it.iconPainter, painter = iconResource.iconPainter,
contentDescription = it.contentDescription, contentDescription = iconResource.contentDescription,
tint = MaterialTheme.colorScheme.secondary, tint = MaterialTheme.colorScheme.secondary,
modifier = Modifier.size(16.dp), modifier = Modifier
.semantics { iconResource.testTag?.let { testTag = it } }
.size(16.dp),
) )
} }
} }
supportingLabel?.let { supportingLabel?.let { supportLabel ->
Text( Text(
text = it, text = supportLabel,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.semantics { supportingLabelTestTag?.let { testTag = it } },
) )
} }
} }

View File

@ -13,10 +13,12 @@ import kotlinx.parcelize.Parcelize
* *
* @property iconPainter Painter for the icon. * @property iconPainter Painter for the icon.
* @property contentDescription String for the icon's content description. * @property contentDescription String for the icon's content description.
* @property testTag The optional test tag to associate with this icon.
*/ */
data class IconResource( data class IconResource(
val iconPainter: Painter, val iconPainter: Painter,
val contentDescription: String, val contentDescription: String,
val testTag: String? = null,
) )
/** /**
@ -24,12 +26,14 @@ data class IconResource(
* *
* @property iconRes Resource for the icon. * @property iconRes Resource for the icon.
* @property contentDescription The icon's content description. * @property contentDescription The icon's content description.
* @property testTag The optional test tag to associate with this icon.
*/ */
@Parcelize @Parcelize
data class IconRes( data class IconRes(
@DrawableRes @DrawableRes
val iconRes: Int, val iconRes: Int,
val contentDescription: Text, val contentDescription: Text,
val testTag: String? = null,
) : Parcelable ) : Parcelable
/** /**
@ -46,4 +50,5 @@ fun IconRes.toIconResource(): IconResource =
IconResource( IconResource(
iconPainter = painterResource(id = iconRes), iconPainter = painterResource(id = iconRes),
contentDescription = contentDescription(), contentDescription = contentDescription(),
testTag = testTag,
) )

View File

@ -112,7 +112,10 @@ fun SearchContent(
BitwardenListItem( BitwardenListItem(
startIcon = it.iconData, startIcon = it.iconData,
label = it.title, label = it.title,
labelTestTag = it.titleTestTag,
supportingLabel = it.subtitle, supportingLabel = it.subtitle,
supportingLabelTestTag = it.subtitleTestTag,
optionsTestTag = it.overflowTestTag,
onClick = { onClick = {
if (it.autofillSelectionOptions.isNotEmpty()) { if (it.autofillSelectionOptions.isNotEmpty()) {
autofillSelectionOptionsItem = it autofillSelectionOptionsItem = it

View File

@ -770,11 +770,14 @@ data class SearchState(
data class DisplayItem( data class DisplayItem(
val id: String, val id: String,
val title: String, val title: String,
val titleTestTag: String,
val subtitle: String?, val subtitle: String?,
val subtitleTestTag: String,
val totpCode: String?, val totpCode: String?,
val iconData: IconData, val iconData: IconData,
val extraIconList: List<IconRes>, val extraIconList: List<IconRes>,
val overflowOptions: List<ListingItemOverflowAction>, val overflowOptions: List<ListingItemOverflowAction>,
val overflowTestTag: String?,
val autofillSelectionOptions: List<AutofillSelectionOption>, val autofillSelectionOptions: List<AutofillSelectionOption>,
val shouldDisplayMasterPasswordReprompt: Boolean, val shouldDisplayMasterPasswordReprompt: Boolean,
) : Parcelable ) : Parcelable

View File

@ -183,13 +183,16 @@ private fun CipherView.toDisplayItem(
SearchState.DisplayItem( SearchState.DisplayItem(
id = id.orEmpty(), id = id.orEmpty(),
title = name, title = name,
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = this.toIconData( iconData = this.toIconData(
baseIconUrl = baseIconUrl, baseIconUrl = baseIconUrl,
isIconLoadingDisabled = isIconLoadingDisabled, isIconLoadingDisabled = isIconLoadingDisabled,
), ),
extraIconList = toLabelIcons(), extraIconList = toLabelIcons(),
overflowOptions = toOverflowActions(), overflowOptions = toOverflowActions(),
overflowTestTag = "CipherOptionsButton",
totpCode = login?.totp, totpCode = login?.totp,
autofillSelectionOptions = AutofillSelectionOption autofillSelectionOptions = AutofillSelectionOption
.entries .entries
@ -322,7 +325,9 @@ private fun SendView.toDisplayItem(
SearchState.DisplayItem( SearchState.DisplayItem(
id = id.orEmpty(), id = id.orEmpty(),
title = name, title = name,
titleTestTag = "SendNameLabel",
subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock), subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock),
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local( iconData = IconData.Local(
iconRes = when (type) { iconRes = when (type) {
SendType.TEXT -> R.drawable.ic_send_text SendType.TEXT -> R.drawable.ic_send_text
@ -331,6 +336,7 @@ private fun SendView.toDisplayItem(
), ),
extraIconList = toLabelIcons(clock = clock), extraIconList = toLabelIcons(clock = clock),
overflowOptions = toOverflowActions(baseWebSendUrl = baseWebSendUrl), overflowOptions = toOverflowActions(baseWebSendUrl = baseWebSendUrl),
overflowTestTag = "SendOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,

View File

@ -11,25 +11,31 @@ import com.x8bit.bitwarden.ui.platform.base.util.asText
enum class SendStatusIcon( enum class SendStatusIcon(
@DrawableRes val iconRes: Int, @DrawableRes val iconRes: Int,
val contentDescription: Text, val contentDescription: Text,
val testTag: String,
) { ) {
DISABLED( DISABLED(
iconRes = R.drawable.ic_send_disabled, iconRes = R.drawable.ic_send_disabled,
contentDescription = R.string.disabled.asText(), contentDescription = R.string.disabled.asText(),
testTag = "DisabledSendIcon",
), ),
PASSWORD( PASSWORD(
iconRes = R.drawable.ic_send_password, iconRes = R.drawable.ic_send_password,
contentDescription = R.string.password.asText(), contentDescription = R.string.password.asText(),
testTag = "PasswordProtectedSendIcon",
), ),
EXPIRED( EXPIRED(
iconRes = R.drawable.ic_send_expired, iconRes = R.drawable.ic_send_expired,
contentDescription = R.string.expired.asText(), contentDescription = R.string.expired.asText(),
testTag = "ExpiredSendIcon",
), ),
MAX_ACCESS_COUNT_REACHED( MAX_ACCESS_COUNT_REACHED(
iconRes = R.drawable.ic_send_max_access_count_reached, iconRes = R.drawable.ic_send_max_access_count_reached,
contentDescription = R.string.maximum_access_count_reached.asText(), contentDescription = R.string.maximum_access_count_reached.asText(),
testTag = "MaxAccessSendIcon",
), ),
PENDING_DELETE( PENDING_DELETE(
iconRes = R.drawable.ic_send_pending_delete, iconRes = R.drawable.ic_send_pending_delete,
contentDescription = R.string.pending_delete.asText(), contentDescription = R.string.pending_delete.asText(),
testTag = "PendingDeletionSendIcon",
), ),
} }

View File

@ -19,7 +19,13 @@ fun SendView.toLabelIcons(clock: Clock = Clock.systemDefaultZone()): List<IconRe
SendStatusIcon.EXPIRED.takeIf { expirationDate?.isBefore(clock.instant()) == true }, SendStatusIcon.EXPIRED.takeIf { expirationDate?.isBefore(clock.instant()) == true },
SendStatusIcon.PENDING_DELETE.takeIf { deletionDate.isBefore(clock.instant()) }, SendStatusIcon.PENDING_DELETE.takeIf { deletionDate.isBefore(clock.instant()) },
) )
.map { IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) } .map {
IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
}
/** /**
* Creates the list of overflow actions to be displayed for a [SendView]. * Creates the list of overflow actions to be displayed for a [SendView].

View File

@ -196,7 +196,10 @@ fun VaultItemListingContent(
BitwardenListItem( BitwardenListItem(
startIcon = it.iconData, startIcon = it.iconData,
label = it.title, label = it.title,
labelTestTag = it.titleTestTag,
supportingLabel = it.subtitle, supportingLabel = it.subtitle,
supportingLabelTestTag = it.subtitleTestTag,
optionsTestTag = it.optionsTestTag,
onClick = { onClick = {
if (it.isAutofill && it.shouldShowMasterPasswordReprompt) { if (it.isAutofill && it.shouldShowMasterPasswordReprompt) {
masterPasswordRepromptData = masterPasswordRepromptData =

View File

@ -875,9 +875,12 @@ data class VaultItemListingState(
* *
* @property id the id of the item. * @property id the id of the item.
* @property title title of the item. * @property title title of the item.
* @property titleTestTag The test tag associated with the [title].
* @property subtitle subtitle of the item (nullable). * @property subtitle subtitle of the item (nullable).
* @property subtitleTestTag The test tag associated with the [subtitle].
* @property iconData data for the icon to be displayed (nullable). * @property iconData data for the icon to be displayed (nullable).
* @property overflowOptions list of options for the item's overflow menu. * @property overflowOptions list of options for the item's overflow menu.
* @property optionsTestTag The test tag associated with the [overflowOptions].
* @property isAutofill whether or not this screen is part of an autofill flow. * @property isAutofill whether or not this screen is part of an autofill flow.
* @property shouldShowMasterPasswordReprompt whether or not a master password reprompt is * @property shouldShowMasterPasswordReprompt whether or not a master password reprompt is
* required for various secure actions. * required for various secure actions.
@ -885,10 +888,13 @@ data class VaultItemListingState(
data class DisplayItem( data class DisplayItem(
val id: String, val id: String,
val title: String, val title: String,
val titleTestTag: String,
val subtitle: String?, val subtitle: String?,
val subtitleTestTag: String,
val iconData: IconData, val iconData: IconData,
val extraIconList: List<IconRes>, val extraIconList: List<IconRes>,
val overflowOptions: List<ListingItemOverflowAction>, val overflowOptions: List<ListingItemOverflowAction>,
val optionsTestTag: String,
val isAutofill: Boolean, val isAutofill: Boolean,
val shouldShowMasterPasswordReprompt: Boolean, val shouldShowMasterPasswordReprompt: Boolean,
) )

View File

@ -272,13 +272,16 @@ private fun CipherView.toDisplayItem(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = id.orEmpty(), id = id.orEmpty(),
title = name, title = name,
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = this.toIconData( iconData = this.toIconData(
baseIconUrl = baseIconUrl, baseIconUrl = baseIconUrl,
isIconLoadingDisabled = isIconLoadingDisabled, isIconLoadingDisabled = isIconLoadingDisabled,
), ),
extraIconList = toLabelIcons(), extraIconList = toLabelIcons(),
overflowOptions = toOverflowActions(), overflowOptions = toOverflowActions(),
optionsTestTag = "CipherOptionsButton",
isAutofill = isAutofill, isAutofill = isAutofill,
shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD, shouldShowMasterPasswordReprompt = reprompt == CipherRepromptType.PASSWORD,
) )
@ -308,7 +311,9 @@ private fun SendView.toDisplayItem(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = id.orEmpty(), id = id.orEmpty(),
title = name, title = name,
titleTestTag = "SendNameLabel",
subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock), subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock),
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local( iconData = IconData.Local(
iconRes = when (type) { iconRes = when (type) {
SendType.TEXT -> R.drawable.ic_send_text SendType.TEXT -> R.drawable.ic_send_text
@ -317,6 +322,7 @@ private fun SendView.toDisplayItem(
), ),
extraIconList = toLabelIcons(clock = clock), extraIconList = toLabelIcons(clock = clock),
overflowOptions = toOverflowActions(baseWebSendUrl = baseWebSendUrl), overflowOptions = toOverflowActions(baseWebSendUrl = baseWebSendUrl),
optionsTestTag = "SendOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )

View File

@ -53,6 +53,10 @@ fun CipherView.toLabelIcons(): List<IconRes> {
VaultTrailingIcon.ATTACHMENT.takeIf { this.attachments?.isNotEmpty() == true }, VaultTrailingIcon.ATTACHMENT.takeIf { this.attachments?.isNotEmpty() == true },
) )
.map { .map {
IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
} }
} }

View File

@ -11,13 +11,16 @@ import com.x8bit.bitwarden.ui.platform.base.util.asText
enum class VaultTrailingIcon( enum class VaultTrailingIcon(
@DrawableRes val iconRes: Int, @DrawableRes val iconRes: Int,
val contentDescription: Text, val contentDescription: Text,
val testTag: String,
) { ) {
COLLECTION( COLLECTION(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
ATTACHMENT( ATTACHMENT(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
} }

View File

@ -21,7 +21,9 @@ fun createMockDisplayItemForCipher(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = "mockUsername-$number", subtitle = "mockUsername-$number",
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Network( iconData = IconData.Network(
uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png", uri = "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_login_item, fallbackIconRes = R.drawable.ic_login_item,
@ -30,10 +32,12 @@ fun createMockDisplayItemForCipher(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -52,6 +56,7 @@ fun createMockDisplayItemForCipher(
url = "www.mockuri$number.com", url = "www.mockuri$number.com",
), ),
), ),
overflowTestTag = "CipherOptionsButton",
totpCode = "mockTotp-$number", totpCode = "mockTotp-$number",
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,
@ -62,16 +67,20 @@ fun createMockDisplayItemForCipher(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = null, subtitle = null,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_secure_note_item), iconData = IconData.Local(R.drawable.ic_secure_note_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -81,6 +90,7 @@ fun createMockDisplayItemForCipher(
notes = "mockNotes-$number", notes = "mockNotes-$number",
), ),
), ),
overflowTestTag = "CipherOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,
@ -91,16 +101,20 @@ fun createMockDisplayItemForCipher(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = "mockBrand-$number, *er-$number", subtitle = "mockBrand-$number, *er-$number",
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_card_item), iconData = IconData.Local(R.drawable.ic_card_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -113,6 +127,7 @@ fun createMockDisplayItemForCipher(
securityCode = "mockCode-$number", securityCode = "mockCode-$number",
), ),
), ),
overflowTestTag = "CipherOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,
@ -123,22 +138,27 @@ fun createMockDisplayItemForCipher(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = "mockFirstName-${number}mockLastName-$number", subtitle = "mockFirstName-${number}mockLastName-$number",
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_identity_item), iconData = IconData.Local(R.drawable.ic_identity_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"), ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"), ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
), ),
overflowTestTag = "CipherOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,
@ -159,16 +179,20 @@ fun createMockDisplayItemForSend(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "SendNameLabel",
subtitle = "Oct 27, 2023, 12:00 PM", subtitle = "Oct 27, 2023, 12:00 PM",
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local(R.drawable.ic_send_file), iconData = IconData.Local(R.drawable.ic_send_file),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_send_password, iconRes = R.drawable.ic_send_password,
contentDescription = R.string.password.asText(), contentDescription = R.string.password.asText(),
testTag = "PasswordProtectedSendIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_send_max_access_count_reached, iconRes = R.drawable.ic_send_max_access_count_reached,
contentDescription = R.string.maximum_access_count_reached.asText(), contentDescription = R.string.maximum_access_count_reached.asText(),
testTag = "MaxAccessSendIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -182,6 +206,7 @@ fun createMockDisplayItemForSend(
ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"),
ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"),
), ),
overflowTestTag = "SendOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,
@ -192,16 +217,20 @@ fun createMockDisplayItemForSend(
SearchState.DisplayItem( SearchState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "SendNameLabel",
subtitle = "Oct 27, 2023, 12:00 PM", subtitle = "Oct 27, 2023, 12:00 PM",
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local(R.drawable.ic_send_text), iconData = IconData.Local(R.drawable.ic_send_text),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_send_password, iconRes = R.drawable.ic_send_password,
contentDescription = R.string.password.asText(), contentDescription = R.string.password.asText(),
testTag = "PasswordProtectedSendIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_send_max_access_count_reached, iconRes = R.drawable.ic_send_max_access_count_reached,
contentDescription = R.string.maximum_access_count_reached.asText(), contentDescription = R.string.maximum_access_count_reached.asText(),
testTag = "MaxAccessSendIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -215,6 +244,7 @@ fun createMockDisplayItemForSend(
ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"),
ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"),
), ),
overflowTestTag = "SendOptionsButton",
totpCode = null, totpCode = null,
autofillSelectionOptions = emptyList(), autofillSelectionOptions = emptyList(),
shouldDisplayMasterPasswordReprompt = false, shouldDisplayMasterPasswordReprompt = false,

View File

@ -118,22 +118,27 @@ private val ALL_SEND_STATUS_ICONS: List<IconRes> = listOf(
IconRes( IconRes(
iconRes = SendStatusIcon.DISABLED.iconRes, iconRes = SendStatusIcon.DISABLED.iconRes,
contentDescription = SendStatusIcon.DISABLED.contentDescription, contentDescription = SendStatusIcon.DISABLED.contentDescription,
testTag = SendStatusIcon.DISABLED.testTag,
), ),
IconRes( IconRes(
iconRes = SendStatusIcon.PASSWORD.iconRes, iconRes = SendStatusIcon.PASSWORD.iconRes,
contentDescription = SendStatusIcon.PASSWORD.contentDescription, contentDescription = SendStatusIcon.PASSWORD.contentDescription,
testTag = SendStatusIcon.PASSWORD.testTag,
), ),
IconRes( IconRes(
iconRes = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.iconRes, iconRes = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.iconRes,
contentDescription = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.contentDescription, contentDescription = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.contentDescription,
testTag = SendStatusIcon.MAX_ACCESS_COUNT_REACHED.testTag,
), ),
IconRes( IconRes(
iconRes = SendStatusIcon.EXPIRED.iconRes, iconRes = SendStatusIcon.EXPIRED.iconRes,
contentDescription = SendStatusIcon.EXPIRED.contentDescription, contentDescription = SendStatusIcon.EXPIRED.contentDescription,
testTag = SendStatusIcon.EXPIRED.testTag,
), ),
IconRes( IconRes(
iconRes = SendStatusIcon.PENDING_DELETE.iconRes, iconRes = SendStatusIcon.PENDING_DELETE.iconRes,
contentDescription = SendStatusIcon.PENDING_DELETE.contentDescription, contentDescription = SendStatusIcon.PENDING_DELETE.contentDescription,
testTag = SendStatusIcon.PENDING_DELETE.testTag,
), ),
) )

View File

@ -1469,7 +1469,9 @@ private fun createDisplayItem(number: Int): VaultItemListingState.DisplayItem =
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockTitle-$number", title = "mockTitle-$number",
titleTestTag = "SendNameLabel",
subtitle = "mockSubtitle-$number", subtitle = "mockSubtitle-$number",
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local(R.drawable.ic_card_item), iconData = IconData.Local(R.drawable.ic_card_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
@ -1500,6 +1502,7 @@ private fun createDisplayItem(number: Int): VaultItemListingState.DisplayItem =
ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"),
ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"),
), ),
optionsTestTag = "SendOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -1508,12 +1511,15 @@ private fun createCipherDisplayItem(number: Int): VaultItemListingState.DisplayI
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockTitle-$number", title = "mockTitle-$number",
titleTestTag = "CipherNameLabel",
subtitle = "mockSubtitle-$number", subtitle = "mockSubtitle-$number",
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_vault), iconData = IconData.Local(R.drawable.ic_vault),
extraIconList = emptyList(), extraIconList = emptyList(),
overflowOptions = listOf( overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"), ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
), ),
optionsTestTag = "CipherOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )

View File

@ -22,7 +22,9 @@ fun createMockDisplayItemForCipher(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Network( iconData = IconData.Network(
"https://vault.bitwarden.com/icons/www.mockuri.com/icon.png", "https://vault.bitwarden.com/icons/www.mockuri.com/icon.png",
fallbackIconRes = R.drawable.ic_login_item, fallbackIconRes = R.drawable.ic_login_item,
@ -31,10 +33,12 @@ fun createMockDisplayItemForCipher(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -53,6 +57,7 @@ fun createMockDisplayItemForCipher(
url = "www.mockuri$number.com", url = "www.mockuri$number.com",
), ),
), ),
optionsTestTag = "CipherOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -62,16 +67,20 @@ fun createMockDisplayItemForCipher(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_secure_note_item), iconData = IconData.Local(R.drawable.ic_secure_note_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -81,6 +90,7 @@ fun createMockDisplayItemForCipher(
notes = "mockNotes-$number", notes = "mockNotes-$number",
), ),
), ),
optionsTestTag = "CipherOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -90,16 +100,20 @@ fun createMockDisplayItemForCipher(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_card_item), iconData = IconData.Local(R.drawable.ic_card_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -112,6 +126,7 @@ fun createMockDisplayItemForCipher(
securityCode = "mockCode-$number", securityCode = "mockCode-$number",
), ),
), ),
optionsTestTag = "CipherOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -121,22 +136,27 @@ fun createMockDisplayItemForCipher(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "CipherNameLabel",
subtitle = subtitle, subtitle = subtitle,
subtitleTestTag = "CipherSubTitleLabel",
iconData = IconData.Local(R.drawable.ic_identity_item), iconData = IconData.Local(R.drawable.ic_identity_item),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_collection, iconRes = R.drawable.ic_collection,
contentDescription = R.string.collections.asText(), contentDescription = R.string.collections.asText(),
testTag = "CipherInCollectionIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_attachment, iconRes = R.drawable.ic_attachment,
contentDescription = R.string.attachments.asText(), contentDescription = R.string.attachments.asText(),
testTag = "CipherWithAttachmentsIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"), ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"), ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
), ),
optionsTestTag = "CipherOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -156,16 +176,20 @@ fun createMockDisplayItemForSend(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "SendNameLabel",
subtitle = "Oct 27, 2023, 12:00 PM", subtitle = "Oct 27, 2023, 12:00 PM",
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local(R.drawable.ic_send_file), iconData = IconData.Local(R.drawable.ic_send_file),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_send_password, iconRes = R.drawable.ic_send_password,
contentDescription = R.string.password.asText(), contentDescription = R.string.password.asText(),
testTag = "PasswordProtectedSendIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_send_max_access_count_reached, iconRes = R.drawable.ic_send_max_access_count_reached,
contentDescription = R.string.maximum_access_count_reached.asText(), contentDescription = R.string.maximum_access_count_reached.asText(),
testTag = "MaxAccessSendIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -179,6 +203,7 @@ fun createMockDisplayItemForSend(
ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"),
ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"),
), ),
optionsTestTag = "SendOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )
@ -188,16 +213,20 @@ fun createMockDisplayItemForSend(
VaultItemListingState.DisplayItem( VaultItemListingState.DisplayItem(
id = "mockId-$number", id = "mockId-$number",
title = "mockName-$number", title = "mockName-$number",
titleTestTag = "SendNameLabel",
subtitle = "Oct 27, 2023, 12:00 PM", subtitle = "Oct 27, 2023, 12:00 PM",
subtitleTestTag = "SendDateLabel",
iconData = IconData.Local(R.drawable.ic_send_text), iconData = IconData.Local(R.drawable.ic_send_text),
extraIconList = listOf( extraIconList = listOf(
IconRes( IconRes(
iconRes = R.drawable.ic_send_password, iconRes = R.drawable.ic_send_password,
contentDescription = R.string.password.asText(), contentDescription = R.string.password.asText(),
testTag = "PasswordProtectedSendIcon",
), ),
IconRes( IconRes(
iconRes = R.drawable.ic_send_max_access_count_reached, iconRes = R.drawable.ic_send_max_access_count_reached,
contentDescription = R.string.maximum_access_count_reached.asText(), contentDescription = R.string.maximum_access_count_reached.asText(),
testTag = "MaxAccessSendIcon",
), ),
), ),
overflowOptions = listOf( overflowOptions = listOf(
@ -211,6 +240,7 @@ fun createMockDisplayItemForSend(
ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.RemovePasswordClick(sendId = "mockId-$number"),
ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"), ListingItemOverflowAction.SendAction.DeleteClick(sendId = "mockId-$number"),
), ),
optionsTestTag = "SendOptionsButton",
isAutofill = false, isAutofill = false,
shouldShowMasterPasswordReprompt = false, shouldShowMasterPasswordReprompt = false,
) )

View File

@ -247,7 +247,11 @@ class CipherViewExtensionsTest {
) )
val expected = listOf(VaultTrailingIcon.COLLECTION).map { val expected = listOf(VaultTrailingIcon.COLLECTION).map {
IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
} }
val result = cipher.toLabelIcons() val result = cipher.toLabelIcons()
@ -263,7 +267,11 @@ class CipherViewExtensionsTest {
) )
val expected = listOf(VaultTrailingIcon.COLLECTION).map { val expected = listOf(VaultTrailingIcon.COLLECTION).map {
IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
} }
val result = cipher.toLabelIcons() val result = cipher.toLabelIcons()
@ -279,7 +287,11 @@ class CipherViewExtensionsTest {
) )
val expected = listOf(VaultTrailingIcon.ATTACHMENT).map { val expected = listOf(VaultTrailingIcon.ATTACHMENT).map {
IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
} }
val result = cipher.toLabelIcons() val result = cipher.toLabelIcons()
@ -295,7 +307,11 @@ class CipherViewExtensionsTest {
VaultTrailingIcon.COLLECTION, VaultTrailingIcon.COLLECTION,
VaultTrailingIcon.ATTACHMENT, VaultTrailingIcon.ATTACHMENT,
).map { ).map {
IconRes(iconRes = it.iconRes, contentDescription = it.contentDescription) IconRes(
iconRes = it.iconRes,
contentDescription = it.contentDescription,
testTag = it.testTag,
)
} }
val result = cipher.toLabelIcons() val result = cipher.toLabelIcons()