diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index 54053a1bb..2b0bc3bf0 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -18,7 +18,8 @@ package com.google.samples.apps.nowinandroid.ui import androidx.compose.ui.semantics.SemanticsActions.ScrollBy import androidx.compose.ui.test.assertCountEquals -import androidx.compose.ui.test.assertIsOn +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText @@ -87,6 +88,8 @@ class NavigationTest { private val forYou by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_title) private val interests by composeTestRule.stringResource(FeatureSearchR.string.feature_search_interests) private val sampleTopic = "Headlines" + private val sampleTopicCheckIconDescription = "Headlines checked" + private val sampleTopicAddIconDescription = "Headlines add" private val appName by composeTestRule.stringResource(R.string.app_name) private val saved by composeTestRule.stringResource(BookmarksR.string.feature_bookmarks_title) private val settings by composeTestRule.stringResource(SettingsR.string.feature_settings_top_app_bar_action_icon_description) @@ -115,13 +118,20 @@ class NavigationTest { fun navigationBar_navigateToPreviouslySelectedTab_restoresContent() { composeTestRule.apply { // GIVEN the user follows a topic - onNodeWithText(sampleTopic).performClick() + onNodeWithContentDescription(sampleTopic).performClick() // WHEN the user navigates to the Interests destination onNodeWithText(interests).performClick() // AND the user navigates to the For You destination onNodeWithText(forYou).performClick() // THEN the state of the For You destination is restored - onNodeWithContentDescription(sampleTopic).assertIsOn() + onNodeWithContentDescription( + sampleTopicCheckIconDescription, + useUnmergedTree = true, + ).assertIsDisplayed() + onNodeWithContentDescription( + sampleTopicAddIconDescription, + useUnmergedTree = true, + ).assertIsNotDisplayed() } } @@ -132,11 +142,18 @@ class NavigationTest { fun navigationBar_reselectTab_keepsState() { composeTestRule.apply { // GIVEN the user follows a topic - onNodeWithText(sampleTopic).performClick() + onNodeWithContentDescription(sampleTopic).performClick() // WHEN the user taps the For You navigation bar item onNodeWithText(forYou).performClick() // THEN the state of the For You destination is restored - onNodeWithContentDescription(sampleTopic).assertIsOn() + onNodeWithContentDescription( + sampleTopicCheckIconDescription, + useUnmergedTree = true, + ).assertIsDisplayed() + onNodeWithContentDescription( + sampleTopicAddIconDescription, + useUnmergedTree = true, + ).assertIsNotDisplayed() } } diff --git a/feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt b/feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt index c3ec5c560..6bb2197c5 100644 --- a/feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt +++ b/feature/foryou/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreenTest.kt @@ -128,7 +128,7 @@ class ForYouScreenTest { testData.forEach { testTopic -> composeTestRule - .onNodeWithText(testTopic.topic.name) + .onNodeWithContentDescription(testTopic.topic.name) .assertExists() .assertHasClickAction() } @@ -175,7 +175,7 @@ class ForYouScreenTest { followableTopicTestData.forEach { testTopic -> composeTestRule - .onNodeWithText(testTopic.topic.name) + .onNodeWithContentDescription(testTopic.topic.name) .assertExists() .assertHasClickAction() } diff --git a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 1a3325996..7190f5cbc 100644 --- a/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -75,6 +75,13 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription +import androidx.compose.ui.semantics.toggleableState +import androidx.compose.ui.state.ToggleableState.Off +import androidx.compose.ui.state.ToggleableState.On import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -268,23 +275,30 @@ private fun LazyStaggeredGridScope.onboarding( is OnboardingUiState.Shown -> { item(span = StaggeredGridItemSpan.FullLine, contentType = "onboarding") { - Column(modifier = interestsItemModifier) { - Text( - text = stringResource(R.string.feature_foryou_onboarding_guidance_title), - textAlign = TextAlign.Center, + Column( + modifier = interestsItemModifier, + ) { + Column( modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - style = MaterialTheme.typography.titleMedium, - ) - Text( - text = stringResource(R.string.feature_foryou_onboarding_guidance_subtitle), - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp, start = 24.dp, end = 24.dp), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.bodyMedium, - ) + .semantics(mergeDescendants = true) { }, + ) { + Text( + text = stringResource(R.string.feature_foryou_onboarding_guidance_title), + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp), + style = MaterialTheme.typography.titleMedium, + ) + Text( + text = stringResource(R.string.feature_foryou_onboarding_guidance_subtitle), + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp, start = 24.dp, end = 24.dp), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyMedium, + ) + } TopicSelection( onboardingUiState, onTopicCheckedChanged, @@ -384,7 +398,21 @@ private fun SingleTopicButton( Surface( modifier = Modifier .width(312.dp) - .heightIn(min = 56.dp), + .heightIn(min = 56.dp) + .semantics(mergeDescendants = true) { + toggleableState = if (isSelected) { + On + } else { + Off + } + stateDescription = if (isSelected) { + "Following" + } else { + "Not Following" + } + + contentDescription = name + }, shape = RoundedCornerShape(corner = CornerSize(8.dp)), color = MaterialTheme.colorScheme.surface, selected = isSelected, @@ -394,7 +422,9 @@ private fun SingleTopicButton( ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(start = 12.dp, end = 8.dp), + modifier = Modifier + .padding(start = 12.dp, end = 8.dp) + .clearAndSetSemantics { }, ) { TopicIcon( imageUrl = imageUrl, @@ -413,13 +443,19 @@ private fun SingleTopicButton( icon = { Icon( imageVector = NiaIcons.Add, - contentDescription = name, + contentDescription = stringResource( + id = R.string.feature_foryou_topic_icon_add, + name, + ), ) }, checkedIcon = { Icon( imageVector = NiaIcons.Check, - contentDescription = name, + contentDescription = stringResource( + id = R.string.feature_foryou_topic_icon_checked, + name, + ), ) }, ) diff --git a/feature/foryou/src/main/res/values/strings.xml b/feature/foryou/src/main/res/values/strings.xml index 166749664..3efa10b0b 100644 --- a/feature/foryou/src/main/res/values/strings.xml +++ b/feature/foryou/src/main/res/values/strings.xml @@ -21,5 +21,7 @@ Navigate up What are you interested in? Updates from topics you follow will appear here. Follow some things to get started. + %s checked + %s add