[PM-37294] fix: Announce external-link affordance on premium upgrade CTAs (#6951)

This commit is contained in:
Patrick Honkonen authored and GitHub committed 2026-05-20 15:15:20 +00:00
1 parent 304c32e1a4
commit 8002794c59
12 files changed
+91

No files matched your search

@@ -403,6 +403,7 @@ private fun PremiumContent(
label = stringResource(id = BitwardenString.manage_plan),
onClick = handlers.onManagePlanClick,
icon = rememberVectorPainter(id = BitwardenDrawable.ic_external_link),
isExternalLink = true,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth()
@@ -415,6 +416,7 @@ private fun PremiumContent(
label = stringResource(id = BitwardenString.cancel_premium),
onClick = handlers.onCancelPremiumClick,
icon = rememberVectorPainter(id = BitwardenDrawable.ic_external_link),
isExternalLink = true,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth()
@@ -108,6 +108,7 @@ fun SettingsScreen(
id = BitwardenString.you_now_have_access_to_all_advanced_security_features,
),
actionText = stringResource(id = BitwardenString.learn_more),
isExternalLink = true,
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_star),
@@ -398,6 +398,7 @@ private fun CoachMarkScope<ExploreGeneratorCoachMark>.ScrollContent(
id = BitwardenString.you_now_have_access_to_all_advanced_security_features,
),
actionText = stringResource(id = BitwardenString.learn_more),
isExternalLink = true,
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_star),
@@ -55,6 +55,7 @@ fun SendContent(
id = BitwardenString.you_now_have_access_to_all_advanced_security_features,
),
actionText = stringResource(id = BitwardenString.learn_more),
isExternalLink = true,
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_star),
@@ -576,6 +576,7 @@ private fun ActionCard(
id = BitwardenString.you_now_have_access_to_all_advanced_security_features,
),
actionText = stringResource(id = BitwardenString.learn_more),
isExternalLink = true,
leadingContent = {
Icon(
painter = rememberVectorPainter(id = BitwardenDrawable.ic_star),
@@ -748,6 +748,15 @@ class PlanScreenTest : BitwardenComposeTest() {
verify { viewModel.trySendAction(PlanAction.ManagePlanClick) }
}
@Test
fun `manage plan button should announce external-link affordance`() {
mutableStateFlow.update { it.copy(viewState = DEFAULT_PREMIUM_VIEW_STATE) }
composeTestRule
.onNodeWithContentDescription(label = "Manage plan, External link")
.performScrollTo()
.assertIsDisplayed()
}
@Test
fun `cancel premium button should render when showCancelButton is true`() {
mutableStateFlow.update {
@@ -760,6 +769,19 @@ class PlanScreenTest : BitwardenComposeTest() {
.assertExists()
}
@Test
fun `cancel premium button should announce external-link affordance`() {
mutableStateFlow.update {
it.copy(
viewState = DEFAULT_PREMIUM_VIEW_STATE.copy(showCancelButton = true),
)
}
composeTestRule
.onNodeWithContentDescription(label = "Cancel Premium, External link")
.performScrollTo()
.assertIsDisplayed()
}
@Test
fun `cancel premium button should not render when showCancelButton is false`() {
mutableStateFlow.update {
@@ -254,6 +254,9 @@ class SettingsScreenTest : BitwardenComposeTest() {
composeTestRule
.onNodeWithText(text = "Learn more")
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(label = "Learn more, External link")
.assertIsDisplayed()
}
@Test
@@ -1848,6 +1848,9 @@ class GeneratorScreenTest : BitwardenComposeTest() {
composeTestRule
.onNodeWithText(text = "Learn more")
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(label = "Learn more, External link")
.assertIsDisplayed()
}
@Test
@@ -960,6 +960,9 @@ class SendScreenTest : BitwardenComposeTest() {
composeTestRule
.onNodeWithText(text = "Learn more")
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(label = "Learn more, External link")
.assertIsDisplayed()
}
@Test
@@ -1706,6 +1706,9 @@ class VaultScreenTest : BitwardenComposeTest() {
composeTestRule
.onNodeWithText(text = "Learn more")
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(label = "Learn more, External link")
.assertIsDisplayed()
}
@Test
@@ -50,6 +50,8 @@ import com.bitwarden.ui.util.asText
* @param cardSubtitle The subtitle of the card.
* @param secondaryButton The optional data for a secondary button.
* @param leadingContent Optional content to display on the leading side of the [cardTitle] [Text].
* @param isExternalLink Whether the CTA launches an external link, which announces the
* external-link affordance to screen readers via the shared `external_link_format` string.
*/
@Suppress("LongMethod")
@Composable
@@ -62,6 +64,7 @@ fun BitwardenActionCard(
cardSubtitle: String? = null,
secondaryButton: BitwardenButtonData? = null,
leadingContent: @Composable (() -> Unit)? = null,
isExternalLink: Boolean = false,
) {
Card(
modifier = modifier,
@@ -133,6 +136,7 @@ fun BitwardenActionCard(
BitwardenFilledButton(
label = actionText,
onClick = onActionClick,
isExternalLink = isExternalLink,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
@@ -0,0 +1,47 @@
package com.bitwarden.ui.platform.components.card
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import com.bitwarden.ui.platform.base.BaseComposeTest
import com.bitwarden.ui.platform.theme.BitwardenTheme
import org.junit.Test
class BitwardenActionCardTest : BaseComposeTest() {
@Test
fun `action button content description defaults to actionText`() {
setTestContent {
BitwardenTheme {
BitwardenActionCard(
cardTitle = "Title",
actionText = "Learn more",
onActionClick = {},
)
}
}
composeTestRule
.onNodeWithContentDescription(label = "Learn more")
.assertIsDisplayed()
}
@Test
fun `action button announces external-link affordance when isExternalLink is true`() {
setTestContent {
BitwardenTheme {
BitwardenActionCard(
cardTitle = "Title",
actionText = "Learn more",
isExternalLink = true,
onActionClick = {},
)
}
}
composeTestRule
.onNodeWithContentDescription(label = "Learn more, External link")
.assertIsDisplayed()
composeTestRule
.onNodeWithText(text = "Learn more")
.assertIsDisplayed()
}
}