add robot for ForYou feature ui tests

pull/402/head
JanFidor 3 years ago
parent 326eb35cf8
commit 3f61d04b49

@ -0,0 +1,123 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasScrollToNodeAction
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performScrollToNode
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import com.google.samples.apps.nowinandroid.feature.foryou.R.string
internal class ForYouRobot(
private val composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<ComponentActivity>, ComponentActivity>
) {
private val doneButtonMatcher by lazy {
hasText(composeTestRule.activity.resources.getString(string.done))
}
fun setContent(
isSyncing: Boolean,
interestsSelectionState: ForYouInterestsSelectionUiState,
feedState: NewsFeedUiState,
) {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = isSyncing,
interestsSelectionState = interestsSelectionState,
feedState = feedState,
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
}
}
}
fun loadingIndicatorExists() {
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(string.for_you_loading)
)
.assertExists()
}
fun clickableAuthorExists(author: FollowableAuthor) {
composeTestRule
.onNodeWithText(author.author.name)
.assertExists()
.assertHasClickAction()
}
fun clickableTopicExists(topic: FollowableTopic) {
composeTestRule
.onNodeWithText(topic.topic.name)
.assertExists()
.assertHasClickAction()
}
fun scrollToDoneButton() {
composeTestRule
.onAllNodes(hasScrollToNodeAction())
.onFirst()
.performScrollToNode(doneButtonMatcher)
}
fun clickableDoneButtonExists(isEnabled: Boolean) {
composeTestRule
.onNode(doneButtonMatcher)
.assertExists()
.assertHasClickAction()
.apply {
if (isEnabled) assertIsEnabled() else assertIsNotEnabled()
}
}
fun clickableNewsResourceExists(newsResource: NewsResource) {
composeTestRule
.onNodeWithText(
newsResource.title,
substring = true
)
.assertExists()
.assertHasClickAction()
}
fun scrollToNewsResource(newsResource: NewsResource) {
composeTestRule.onNode(hasScrollToNodeAction())
.performScrollToNode(
hasText(
newsResource.title,
substring = true
)
)
}
}

@ -17,17 +17,9 @@
package com.google.samples.apps.nowinandroid.feature.foryou
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasScrollToNodeAction
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performScrollToNode
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
@ -42,305 +34,167 @@ class ForYouScreenTest {
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
private val doneButtonMatcher by lazy {
hasText(
composeTestRule.activity.resources.getString(R.string.done)
)
}
@Test
fun circularProgressIndicator_whenScreenIsLoading_exists() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState = OnboardingUiState.Loading,
feedState = NewsFeedUiState.Loading,
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
}
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState = OnboardingUiState.Loading,
feedState = NewsFeedUiState.Loading,
) {
loadingIndicatorExists()
}
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.for_you_loading)
)
.assertExists()
}
@Test
fun circularProgressIndicator_whenScreenIsSyncing_exists() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = true,
onboardingUiState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Success(emptyList()),
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
}
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = true,
onboardingState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Success(emptyList()),
) {
loadingIndicatorExists()
}
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.for_you_loading)
)
.assertExists()
}
@Test
fun topicSelector_whenNoTopicsSelected_showsAuthorAndTopicChipsAndDisabledDoneButton() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
topics = testTopics,
authors = testAuthors
),
feedState = NewsFeedUiState.Success(
feed = emptyList()
),
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState = OnboardingUiState.Shown(
topics = testTopics,
authors = testAuthors
),
feedState = NewsFeedUiState.Success(emptyList()),
) {
testAuthors.forEach { author ->
clickableAuthorExists(author)
}
}
testAuthors.forEach { testAuthor ->
composeTestRule
.onNodeWithText(testAuthor.author.name)
.assertExists()
.assertHasClickAction()
}
testTopics.forEach { topic ->
clickableTopicExists(topic)
}
testTopics.forEach { testTopic ->
composeTestRule
.onNodeWithText(testTopic.topic.name)
.assertExists()
.assertHasClickAction()
scrollToDoneButton()
clickableDoneButtonExists(false)
}
// Scroll until the Done button is visible
composeTestRule
.onAllNodes(hasScrollToNodeAction())
.onFirst()
.performScrollToNode(doneButtonMatcher)
composeTestRule
.onNode(doneButtonMatcher)
.assertExists()
.assertIsNotEnabled()
.assertHasClickAction()
}
@Test
fun topicSelector_whenSomeTopicsSelected_showsAuthorAndTopicChipsAndEnabledDoneButton() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
// Follow one topic
topics = testTopics.mapIndexed { index, testTopic ->
testTopic.copy(isFollowed = index == 1)
},
authors = testAuthors
),
feedState = NewsFeedUiState.Success(
feed = emptyList()
),
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState =
OnboardingUiState.Shown(
// Follow one topic
topics = testTopics.mapIndexed { index, testTopic ->
testTopic.copy(isFollowed = index == 1)
},
authors = testAuthors
),
feedState = NewsFeedUiState.Success(emptyList()),
) {
testAuthors.forEach { author ->
clickableAuthorExists(author)
}
}
testAuthors.forEach { testAuthor ->
composeTestRule
.onNodeWithText(testAuthor.author.name)
.assertExists()
.assertHasClickAction()
}
testTopics.forEach { topic ->
clickableTopicExists(topic)
}
testTopics.forEach { testTopic ->
composeTestRule
.onNodeWithText(testTopic.topic.name)
.assertExists()
.assertHasClickAction()
scrollToDoneButton()
clickableDoneButtonExists(true)
}
// Scroll until the Done button is visible
composeTestRule
.onAllNodes(hasScrollToNodeAction())
.onFirst()
.performScrollToNode(doneButtonMatcher)
composeTestRule
.onNode(doneButtonMatcher)
.assertExists()
.assertIsEnabled()
.assertHasClickAction()
}
@Test
fun topicSelector_whenSomeAuthorsSelected_showsAuthorAndTopicChipsAndEnabledDoneButton() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
// Follow one topic
topics = testTopics,
authors = testAuthors.mapIndexed { index, testAuthor ->
testAuthor.copy(isFollowed = index == 1)
}
),
feedState = NewsFeedUiState.Success(
feed = emptyList()
),
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState = OnboardingUiState.Shown(
// Follow one topic
topics = testTopics,
authors = testAuthors.mapIndexed { index, testAuthor ->
testAuthor.copy(isFollowed = index == 1)
}
),
feedState = NewsFeedUiState.Success(emptyList()),
) {
testAuthors.forEach { author ->
clickableAuthorExists(author)
}
}
testAuthors.forEach { testAuthor ->
composeTestRule
.onNodeWithText(testAuthor.author.name)
.assertExists()
.assertHasClickAction()
}
testTopics.forEach { topic ->
clickableTopicExists(topic)
}
testTopics.forEach { testTopic ->
composeTestRule
.onNodeWithText(testTopic.topic.name)
.assertExists()
.assertHasClickAction()
scrollToDoneButton()
clickableDoneButtonExists(true)
}
// Scroll until the Done button is visible
composeTestRule
.onAllNodes(hasScrollToNodeAction())
.onFirst()
.performScrollToNode(doneButtonMatcher)
composeTestRule
.onNode(doneButtonMatcher)
.assertExists()
.assertIsEnabled()
.assertHasClickAction()
}
@Test
fun feed_whenInterestsSelectedAndLoading_showsLoadingIndicator() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState =
OnboardingUiState.Shown(
topics = testTopics,
authors = testAuthors
),
feedState = NewsFeedUiState.Loading,
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
}
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState =
OnboardingUiState.Shown(
topics = testTopics,
authors = testAuthors
),
feedState = NewsFeedUiState.Loading,
) {
loadingIndicatorExists()
}
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.for_you_loading)
)
.assertExists()
}
@Test
fun feed_whenNoInterestsSelectionAndLoading_showsLoadingIndicator() {
composeTestRule.setContent {
BoxWithConstraints {
ForYouScreen(
isSyncing = false,
onboardingUiState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Loading,
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
}
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Loading,
) {
loadingIndicatorExists()
}
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.for_you_loading)
)
.assertExists()
}
@Test
fun feed_whenNoInterestsSelectionAndLoaded_showsFeed() {
composeTestRule.setContent {
ForYouScreen(
isSyncing = false,
onboardingUiState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Success(
feed = previewNewsResources.map {
SaveableNewsResource(it, false)
}
),
onTopicCheckedChanged = { _, _ -> },
onAuthorCheckedChanged = { _, _ -> },
saveFollowedTopics = {},
onNewsResourcesCheckedChanged = { _, _ -> }
)
launchForYouRobot(
composeTestRule = composeTestRule,
isSyncing = false,
onboardingState = OnboardingUiState.NotShown,
feedState = NewsFeedUiState.Success(
feed = previewNewsResources.map {
SaveableNewsResource(it, false)
}
),
) {
clickableNewsResourceExists(previewNewsResources[0])
scrollToNewsResource(previewNewsResources[1])
clickableNewsResourceExists(previewNewsResources[1])
}
composeTestRule
.onNodeWithText(
previewNewsResources[0].title,
substring = true
)
.assertExists()
.assertHasClickAction()
composeTestRule.onNode(hasScrollToNodeAction())
.performScrollToNode(
hasText(
previewNewsResources[1].title,
substring = true
)
)
composeTestRule
.onNodeWithText(
previewNewsResources[1].title,
substring = true
)
.assertExists()
.assertHasClickAction()
}
}
private fun launchForYouRobot(
composeTestRule: AndroidComposeTestRule<ActivityScenarioRule<ComponentActivity>, ComponentActivity>,
isSyncing: Boolean,
onboardingState: OnboardingUiState,
feedState: NewsFeedUiState,
func: ForYouRobot.() -> Unit
) = ForYouRobot(composeTestRule).apply {
setContent(isSyncing, onboardingState, feedState)
func()
}
private val testTopic = Topic(
id = "",
name = "",

Loading…
Cancel
Save