From 7afc3562dc9fdfba3ae7cd8ab4e085235c046f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojtek=20Kalici=C5=84ski?= Date: Wed, 26 Oct 2022 12:32:06 -0700 Subject: [PATCH 1/5] Fix app id name clash in benchmark module Change-Id: I5889ef4b9338a940f43efc7629dca155068588ec --- {benchmark => benchmarks}/build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 0 .../com/google/samples/apps/nowinandroid/Utils.kt | 12 +++++++++--- .../baselineprofile/BaselineProfileGenerator.kt | 0 .../apps/nowinandroid/bookmarks/BookmarksActions.kt | 0 .../apps/nowinandroid/foryou/ForYouActions.kt | 0 .../nowinandroid/foryou/ScrollForYouFeedBenchmark.kt | 0 .../apps/nowinandroid/interests/InterestsActions.kt | 0 .../interests/TopicsScreenRecompositionBenchmark.kt | 0 .../apps/nowinandroid/startup/StartupBenchmark.kt | 0 settings.gradle.kts | 2 +- 11 files changed, 11 insertions(+), 5 deletions(-) rename {benchmark => benchmarks}/build.gradle.kts (97%) rename {benchmark => benchmarks}/src/main/AndroidManifest.xml (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt (68%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt (100%) rename {benchmark => benchmarks}/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt (100%) diff --git a/benchmark/build.gradle.kts b/benchmarks/build.gradle.kts similarity index 97% rename from benchmark/build.gradle.kts rename to benchmarks/build.gradle.kts index 0cbde5bd3..3271250dd 100644 --- a/benchmark/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -21,7 +21,7 @@ plugins { } android { - namespace = "com.google.samples.apps.nowinandroid.benchmark" + namespace = "com.google.samples.apps.nowinandroid.benchmarks" defaultConfig { minSdk = 23 diff --git a/benchmark/src/main/AndroidManifest.xml b/benchmarks/src/main/AndroidManifest.xml similarity index 100% rename from benchmark/src/main/AndroidManifest.xml rename to benchmarks/src/main/AndroidManifest.xml diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt similarity index 68% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt index 41f817c8d..ffb3da23c 100644 --- a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/Utils.kt @@ -16,10 +16,16 @@ package com.google.samples.apps.nowinandroid -import com.google.samples.apps.nowinandroid.benchmark.BuildConfig +import com.google.samples.apps.nowinandroid.benchmarks.BuildConfig /** * Convenience parameter to use proper package name with regards to build type and build flavor. */ -const val PACKAGE_NAME = - "com.google.samples.apps.nowinandroid.${BuildConfig.FLAVOR}.${BuildConfig.BUILD_TYPE}" +val PACKAGE_NAME = StringBuilder("com.google.samples.apps.nowinandroid").apply { + if (BuildConfig.FLAVOR != "prod") { + append(".${BuildConfig.FLAVOR}") + } + if (BuildConfig.BUILD_TYPE != "release") { + append(".${BuildConfig.BUILD_TYPE}") + } +}.toString() diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/baselineprofile/BaselineProfileGenerator.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/bookmarks/BookmarksActions.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ScrollForYouFeedBenchmark.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/InterestsActions.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/interests/TopicsScreenRecompositionBenchmark.kt diff --git a/benchmark/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt similarity index 100% rename from benchmark/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt rename to benchmarks/src/main/java/com/google/samples/apps/nowinandroid/startup/StartupBenchmark.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index d8ff0162c..cfa31a150 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,7 +33,7 @@ dependencyResolutionManagement { rootProject.name = "nowinandroid" include(":app") include(":app-nia-catalog") -include(":benchmark") +include(":benchmarks") include(":core:common") include(":core:data") include(":core:data-test") From f6e6582f7611b9efbc0a5f74b6a9dacc66da645c Mon Sep 17 00:00:00 2001 From: JanFidor Date: Sun, 6 Nov 2022 18:41:44 +0100 Subject: [PATCH 2/5] add robot for settings feature ui tests --- .../feature/settings/SettingsDialogRobot.kt | 60 ++++++++++++ .../feature/settings/SettingsDialogTest.kt | 96 ++++++++----------- 2 files changed, 101 insertions(+), 55 deletions(-) create mode 100644 feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt diff --git a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt new file mode 100644 index 000000000..c94f7b29b --- /dev/null +++ b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt @@ -0,0 +1,60 @@ +/* + * 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.settings + +import androidx.activity.ComponentActivity +import androidx.annotation.StringRes +import androidx.compose.ui.test.assertIsSelected +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.rules.ActivityScenarioRule + +internal class SettingsDialogRobot( + private val composeTestRule: AndroidComposeTestRule, ComponentActivity> +) { + fun setContent(settingsUiState: SettingsUiState) { + composeTestRule.setContent { + SettingsDialog( + settingsUiState = settingsUiState, + onDismiss = { }, + onChangeThemeBrand = {}, + onChangeDarkThemeConfig = {} + ) + } + } + + fun loadingIndicatorExists() { + composeTestRule + .onNodeWithText(getString(R.string.loading)) + .assertExists() + } + + fun settingExists(name: String) { + composeTestRule + .onNodeWithText(name) + .assertExists() + } + + fun settingIsSelected(name: String) { + composeTestRule + .onNodeWithText(name) + .assertIsSelected() + } + + fun getString(@StringRes stringId: Int) = + composeTestRule.activity.resources.getString(stringId) +} \ No newline at end of file diff --git a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt index 07b6b272c..bf1af77dc 100644 --- a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt +++ b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt @@ -17,9 +17,9 @@ package com.google.samples.apps.nowinandroid.feature.settings import androidx.activity.ComponentActivity -import androidx.compose.ui.test.assertIsSelected +import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.rules.ActivityScenarioRule import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading @@ -32,74 +32,60 @@ class SettingsDialogTest { @get:Rule val composeTestRule = createAndroidComposeRule() - private fun getString(id: Int) = composeTestRule.activity.resources.getString(id) - @Test fun whenLoading_showsLoadingText() { - - composeTestRule.setContent { - SettingsDialog( - settingsUiState = Loading, - onDismiss = { }, - onChangeThemeBrand = {}, - onChangeDarkThemeConfig = {} - ) + launchSettingsDialogRobot(composeTestRule, Loading) { + loadingIndicatorExists() } - - composeTestRule - .onNodeWithText(getString(R.string.loading)) - .assertExists() } @Test fun whenStateIsSuccess_allSettingsAreDisplayed() { - composeTestRule.setContent { - SettingsDialog( - settingsUiState = Success( - UserEditableSettings( - brand = ANDROID, - darkThemeConfig = DARK - ) - ), - onDismiss = { }, - onChangeThemeBrand = {}, - onChangeDarkThemeConfig = {} + launchSettingsDialogRobot( + composeTestRule, + Success( + UserEditableSettings( + brand = ANDROID, + darkThemeConfig = DARK + ) ) - } + ) { + settingExists(getString(R.string.brand_default)) + settingExists(getString(R.string.brand_android)) + settingExists(getString(R.string.dark_mode_config_system_default)) - // Check that all the possible settings are displayed. - composeTestRule.onNodeWithText(getString(R.string.brand_default)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.brand_android)).assertExists() - composeTestRule.onNodeWithText( - getString(R.string.dark_mode_config_system_default) - ).assertExists() - composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_light)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_dark)).assertExists() + settingExists(getString(R.string.dark_mode_config_light)) + settingExists(getString(R.string.dark_mode_config_dark)) - // Check that the correct settings are selected. - composeTestRule.onNodeWithText(getString(R.string.brand_android)).assertIsSelected() - composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_dark)).assertIsSelected() + settingIsSelected(getString(R.string.brand_android)) + settingIsSelected(getString(R.string.dark_mode_config_dark)) + } } @Test fun whenStateIsSuccess_allLinksAreDisplayed() { - composeTestRule.setContent { - SettingsDialog( - settingsUiState = Success( - UserEditableSettings( - brand = ANDROID, - darkThemeConfig = DARK - ) - ), - onDismiss = { }, - onChangeThemeBrand = {}, - onChangeDarkThemeConfig = {} + launchSettingsDialogRobot( + composeTestRule, + Success( + UserEditableSettings( + brand = ANDROID, + darkThemeConfig = DARK + ) ) + ) { + settingExists(getString(R.string.privacy_policy)) + settingExists(getString(R.string.licenses)) + settingExists(getString(R.string.brand_guidelines)) + settingExists(getString(R.string.feedback)) } - - composeTestRule.onNodeWithText(getString(R.string.privacy_policy)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.licenses)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.brand_guidelines)).assertExists() - composeTestRule.onNodeWithText(getString(R.string.feedback)).assertExists() } } + +private fun launchSettingsDialogRobot( + composeTestRule: AndroidComposeTestRule, ComponentActivity>, + settingsUiState: SettingsUiState, + func: SettingsDialogRobot.() -> Unit +) = SettingsDialogRobot(composeTestRule).apply { + setContent(settingsUiState) + func() +} From fdd3b6718733e08777bf123007c22e5fae2dbde0 Mon Sep 17 00:00:00 2001 From: JanFidor Date: Sun, 6 Nov 2022 18:42:04 +0100 Subject: [PATCH 3/5] add robot for topic feature ui tests --- .../nowinandroid/feature/topic/TopicRobot.kt | 70 +++++++++ .../feature/topic/TopicScreenTest.kt | 135 +++++++----------- 2 files changed, 120 insertions(+), 85 deletions(-) create mode 100644 feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt diff --git a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt new file mode 100644 index 000000000..06fc4d43b --- /dev/null +++ b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt @@ -0,0 +1,70 @@ +/* + * 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.topic + +import androidx.activity.ComponentActivity +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.FollowableTopic +import com.google.samples.apps.nowinandroid.core.model.data.NewsResource + +internal class TopicRobot( + private val composeTestRule: AndroidComposeTestRule, ComponentActivity> +) { + private val topicLoading = composeTestRule.activity.resources.getString(R.string.topic_loading) + + fun setContent(topicUiState: TopicUiState, newsUiState: NewsUiState) { + composeTestRule.setContent { + TopicScreen( + topicUiState = topicUiState, + newsUiState = newsUiState, + onBackClick = { }, + onFollowClick = { }, + onBookmarkChanged = { _, _ -> }, + ) + } + } + + fun loadingIndicatorExists() { + composeTestRule + .onNodeWithContentDescription(topicLoading) + .assertExists() + } + + fun topicExists(topic: FollowableTopic) { + composeTestRule + .onNodeWithText(topic.topic.name) + .assertExists() + + composeTestRule + .onNodeWithText(topic.topic.longDescription) + .assertExists() + } + + fun scrollToNewsResource(newsResource: NewsResource) { + composeTestRule + .onAllNodes(hasScrollToNodeAction()) + .onFirst() + .performScrollToNode(hasText(newsResource.title)) + } +} \ No newline at end of file diff --git a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt index 0f20a5e5e..1df807635 100644 --- a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt +++ b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt @@ -17,20 +17,15 @@ package com.google.samples.apps.nowinandroid.feature.topic import androidx.activity.ComponentActivity -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.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.Topic import kotlinx.datetime.Instant -import org.junit.Before import org.junit.Rule import org.junit.Test @@ -44,109 +39,79 @@ class TopicScreenTest { @get:Rule val composeTestRule = createAndroidComposeRule() - private lateinit var topicLoading: String - - @Before - fun setup() { - composeTestRule.activity.apply { - topicLoading = getString(R.string.topic_loading) - } - } - @Test fun niaLoadingWheel_whenScreenIsLoading_showLoading() { - composeTestRule.setContent { - TopicScreen( - topicUiState = TopicUiState.Loading, - newsUiState = NewsUiState.Loading, - onBackClick = { }, - onFollowClick = { }, - onBookmarkChanged = { _, _ -> }, - ) + launchTopicRobot( + composeTestRule, + TopicUiState.Loading, + NewsUiState.Loading + ) { + loadingIndicatorExists() } - - composeTestRule - .onNodeWithContentDescription(topicLoading) - .assertExists() } @Test fun topicTitle_whenTopicIsSuccess_isShown() { val testTopic = testTopics.first() - composeTestRule.setContent { - TopicScreen( - topicUiState = TopicUiState.Success(testTopic), - newsUiState = NewsUiState.Loading, - onBackClick = { }, - onFollowClick = { }, - onBookmarkChanged = { _, _ -> }, - ) - } - - // Name is shown - composeTestRule - .onNodeWithText(testTopic.topic.name) - .assertExists() - // Description is shown - composeTestRule - .onNodeWithText(testTopic.topic.longDescription) - .assertExists() + launchTopicRobot( + composeTestRule, + TopicUiState.Success(testTopic), + NewsUiState.Loading + ) { + topicExists(testTopic) + } } @Test fun news_whenTopicIsLoading_isNotShown() { - composeTestRule.setContent { - TopicScreen( - topicUiState = TopicUiState.Loading, - newsUiState = NewsUiState.Success( - sampleNewsResources.mapIndexed { index, newsResource -> - SaveableNewsResource( - newsResource = newsResource, - isSaved = index % 2 == 0, - ) - } - ), - onBackClick = { }, - onFollowClick = { }, - onBookmarkChanged = { _, _ -> }, + launchTopicRobot( + composeTestRule, + TopicUiState.Loading, + NewsUiState.Success( + sampleNewsResources.mapIndexed { index, newsResource -> + SaveableNewsResource( + newsResource = newsResource, + isSaved = index % 2 == 0, + ) + } ) + ) { + loadingIndicatorExists() } - - // Loading indicator shown - composeTestRule - .onNodeWithContentDescription(topicLoading) - .assertExists() } @Test fun news_whenSuccessAndTopicIsSuccess_isShown() { val testTopic = testTopics.first() - composeTestRule.setContent { - TopicScreen( - topicUiState = TopicUiState.Success(testTopic), - newsUiState = NewsUiState.Success( - sampleNewsResources.mapIndexed { index, newsResource -> - SaveableNewsResource( - newsResource = newsResource, - isSaved = index % 2 == 0, - ) - } - ), - onBackClick = { }, - onFollowClick = { }, - onBookmarkChanged = { _, _ -> }, + launchTopicRobot( + composeTestRule, + TopicUiState.Success(testTopic), + NewsUiState.Success( + sampleNewsResources.mapIndexed { index, newsResource -> + SaveableNewsResource( + newsResource = newsResource, + isSaved = index % 2 == 0, + ) + } ) + ) { + // Scroll to first news title if available + scrollToNewsResource(sampleNewsResources.first()) } - - // Scroll to first news title if available - composeTestRule - .onAllNodes(hasScrollToNodeAction()) - .onFirst() - .performScrollToNode(hasText(sampleNewsResources.first().title)) } } +private fun launchTopicRobot( + composeTestRule: AndroidComposeTestRule, ComponentActivity>, + topicUiState: TopicUiState, + newsUiState: NewsUiState, + func: TopicRobot.() -> Unit +) = TopicRobot(composeTestRule).apply { + setContent(topicUiState, newsUiState) + func() +} + private const val TOPIC_1_NAME = "Headlines" private const val TOPIC_2_NAME = "UI" private const val TOPIC_3_NAME = "Tools" From 9962b9d7a81bf0a05f94baa89e415e99d7e3edb6 Mon Sep 17 00:00:00 2001 From: JanFidor Date: Tue, 15 Nov 2022 16:11:47 +0100 Subject: [PATCH 4/5] Revert "add robot for topic feature ui tests" This reverts commit 9dde120cc5d6fdfe2bae6d69891171bc045652e9. --- .../nowinandroid/feature/topic/TopicRobot.kt | 70 --------- .../feature/topic/TopicScreenTest.kt | 135 +++++++++++------- 2 files changed, 85 insertions(+), 120 deletions(-) delete mode 100644 feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt diff --git a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt deleted file mode 100644 index 06fc4d43b..000000000 --- a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicRobot.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.topic - -import androidx.activity.ComponentActivity -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.FollowableTopic -import com.google.samples.apps.nowinandroid.core.model.data.NewsResource - -internal class TopicRobot( - private val composeTestRule: AndroidComposeTestRule, ComponentActivity> -) { - private val topicLoading = composeTestRule.activity.resources.getString(R.string.topic_loading) - - fun setContent(topicUiState: TopicUiState, newsUiState: NewsUiState) { - composeTestRule.setContent { - TopicScreen( - topicUiState = topicUiState, - newsUiState = newsUiState, - onBackClick = { }, - onFollowClick = { }, - onBookmarkChanged = { _, _ -> }, - ) - } - } - - fun loadingIndicatorExists() { - composeTestRule - .onNodeWithContentDescription(topicLoading) - .assertExists() - } - - fun topicExists(topic: FollowableTopic) { - composeTestRule - .onNodeWithText(topic.topic.name) - .assertExists() - - composeTestRule - .onNodeWithText(topic.topic.longDescription) - .assertExists() - } - - fun scrollToNewsResource(newsResource: NewsResource) { - composeTestRule - .onAllNodes(hasScrollToNodeAction()) - .onFirst() - .performScrollToNode(hasText(newsResource.title)) - } -} \ No newline at end of file diff --git a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt index 1df807635..0f20a5e5e 100644 --- a/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt +++ b/feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt @@ -17,15 +17,20 @@ package com.google.samples.apps.nowinandroid.feature.topic import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.hasScrollToNodeAction +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.test.ext.junit.rules.ActivityScenarioRule +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 com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.Topic import kotlinx.datetime.Instant +import org.junit.Before import org.junit.Rule import org.junit.Test @@ -39,77 +44,107 @@ class TopicScreenTest { @get:Rule val composeTestRule = createAndroidComposeRule() + private lateinit var topicLoading: String + + @Before + fun setup() { + composeTestRule.activity.apply { + topicLoading = getString(R.string.topic_loading) + } + } + @Test fun niaLoadingWheel_whenScreenIsLoading_showLoading() { - launchTopicRobot( - composeTestRule, - TopicUiState.Loading, - NewsUiState.Loading - ) { - loadingIndicatorExists() + composeTestRule.setContent { + TopicScreen( + topicUiState = TopicUiState.Loading, + newsUiState = NewsUiState.Loading, + onBackClick = { }, + onFollowClick = { }, + onBookmarkChanged = { _, _ -> }, + ) } + + composeTestRule + .onNodeWithContentDescription(topicLoading) + .assertExists() } @Test fun topicTitle_whenTopicIsSuccess_isShown() { val testTopic = testTopics.first() - - launchTopicRobot( - composeTestRule, - TopicUiState.Success(testTopic), - NewsUiState.Loading - ) { - topicExists(testTopic) + composeTestRule.setContent { + TopicScreen( + topicUiState = TopicUiState.Success(testTopic), + newsUiState = NewsUiState.Loading, + onBackClick = { }, + onFollowClick = { }, + onBookmarkChanged = { _, _ -> }, + ) } + + // Name is shown + composeTestRule + .onNodeWithText(testTopic.topic.name) + .assertExists() + + // Description is shown + composeTestRule + .onNodeWithText(testTopic.topic.longDescription) + .assertExists() } @Test fun news_whenTopicIsLoading_isNotShown() { - launchTopicRobot( - composeTestRule, - TopicUiState.Loading, - NewsUiState.Success( - sampleNewsResources.mapIndexed { index, newsResource -> - SaveableNewsResource( - newsResource = newsResource, - isSaved = index % 2 == 0, - ) - } + composeTestRule.setContent { + TopicScreen( + topicUiState = TopicUiState.Loading, + newsUiState = NewsUiState.Success( + sampleNewsResources.mapIndexed { index, newsResource -> + SaveableNewsResource( + newsResource = newsResource, + isSaved = index % 2 == 0, + ) + } + ), + onBackClick = { }, + onFollowClick = { }, + onBookmarkChanged = { _, _ -> }, ) - ) { - loadingIndicatorExists() } + + // Loading indicator shown + composeTestRule + .onNodeWithContentDescription(topicLoading) + .assertExists() } @Test fun news_whenSuccessAndTopicIsSuccess_isShown() { val testTopic = testTopics.first() - launchTopicRobot( - composeTestRule, - TopicUiState.Success(testTopic), - NewsUiState.Success( - sampleNewsResources.mapIndexed { index, newsResource -> - SaveableNewsResource( - newsResource = newsResource, - isSaved = index % 2 == 0, - ) - } + composeTestRule.setContent { + TopicScreen( + topicUiState = TopicUiState.Success(testTopic), + newsUiState = NewsUiState.Success( + sampleNewsResources.mapIndexed { index, newsResource -> + SaveableNewsResource( + newsResource = newsResource, + isSaved = index % 2 == 0, + ) + } + ), + onBackClick = { }, + onFollowClick = { }, + onBookmarkChanged = { _, _ -> }, ) - ) { - // Scroll to first news title if available - scrollToNewsResource(sampleNewsResources.first()) } - } -} -private fun launchTopicRobot( - composeTestRule: AndroidComposeTestRule, ComponentActivity>, - topicUiState: TopicUiState, - newsUiState: NewsUiState, - func: TopicRobot.() -> Unit -) = TopicRobot(composeTestRule).apply { - setContent(topicUiState, newsUiState) - func() + // Scroll to first news title if available + composeTestRule + .onAllNodes(hasScrollToNodeAction()) + .onFirst() + .performScrollToNode(hasText(sampleNewsResources.first().title)) + } } private const val TOPIC_1_NAME = "Headlines" From bf243b066f5207f3c1866dd6cced9a08f4fb9e0d Mon Sep 17 00:00:00 2001 From: JanFidor Date: Tue, 15 Nov 2022 16:11:51 +0100 Subject: [PATCH 5/5] Revert "add robot for settings feature ui tests" This reverts commit 642c080563cc28ed5c00130ccdc0d032ba3f0edb. --- .../feature/settings/SettingsDialogRobot.kt | 60 ------------ .../feature/settings/SettingsDialogTest.kt | 96 +++++++++++-------- 2 files changed, 55 insertions(+), 101 deletions(-) delete mode 100644 feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt diff --git a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt deleted file mode 100644 index c94f7b29b..000000000 --- a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogRobot.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.settings - -import androidx.activity.ComponentActivity -import androidx.annotation.StringRes -import androidx.compose.ui.test.assertIsSelected -import androidx.compose.ui.test.junit4.AndroidComposeTestRule -import androidx.compose.ui.test.onNodeWithText -import androidx.test.ext.junit.rules.ActivityScenarioRule - -internal class SettingsDialogRobot( - private val composeTestRule: AndroidComposeTestRule, ComponentActivity> -) { - fun setContent(settingsUiState: SettingsUiState) { - composeTestRule.setContent { - SettingsDialog( - settingsUiState = settingsUiState, - onDismiss = { }, - onChangeThemeBrand = {}, - onChangeDarkThemeConfig = {} - ) - } - } - - fun loadingIndicatorExists() { - composeTestRule - .onNodeWithText(getString(R.string.loading)) - .assertExists() - } - - fun settingExists(name: String) { - composeTestRule - .onNodeWithText(name) - .assertExists() - } - - fun settingIsSelected(name: String) { - composeTestRule - .onNodeWithText(name) - .assertIsSelected() - } - - fun getString(@StringRes stringId: Int) = - composeTestRule.activity.resources.getString(stringId) -} \ No newline at end of file diff --git a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt index bf1af77dc..07b6b272c 100644 --- a/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt +++ b/feature/settings/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsDialogTest.kt @@ -17,9 +17,9 @@ package com.google.samples.apps.nowinandroid.feature.settings import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.compose.ui.test.onNodeWithText import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading @@ -32,60 +32,74 @@ class SettingsDialogTest { @get:Rule val composeTestRule = createAndroidComposeRule() + private fun getString(id: Int) = composeTestRule.activity.resources.getString(id) + @Test fun whenLoading_showsLoadingText() { - launchSettingsDialogRobot(composeTestRule, Loading) { - loadingIndicatorExists() + + composeTestRule.setContent { + SettingsDialog( + settingsUiState = Loading, + onDismiss = { }, + onChangeThemeBrand = {}, + onChangeDarkThemeConfig = {} + ) } + + composeTestRule + .onNodeWithText(getString(R.string.loading)) + .assertExists() } @Test fun whenStateIsSuccess_allSettingsAreDisplayed() { - launchSettingsDialogRobot( - composeTestRule, - Success( - UserEditableSettings( - brand = ANDROID, - darkThemeConfig = DARK - ) + composeTestRule.setContent { + SettingsDialog( + settingsUiState = Success( + UserEditableSettings( + brand = ANDROID, + darkThemeConfig = DARK + ) + ), + onDismiss = { }, + onChangeThemeBrand = {}, + onChangeDarkThemeConfig = {} ) - ) { - settingExists(getString(R.string.brand_default)) - settingExists(getString(R.string.brand_android)) - settingExists(getString(R.string.dark_mode_config_system_default)) + } - settingExists(getString(R.string.dark_mode_config_light)) - settingExists(getString(R.string.dark_mode_config_dark)) + // Check that all the possible settings are displayed. + composeTestRule.onNodeWithText(getString(R.string.brand_default)).assertExists() + composeTestRule.onNodeWithText(getString(R.string.brand_android)).assertExists() + composeTestRule.onNodeWithText( + getString(R.string.dark_mode_config_system_default) + ).assertExists() + composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_light)).assertExists() + composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_dark)).assertExists() - settingIsSelected(getString(R.string.brand_android)) - settingIsSelected(getString(R.string.dark_mode_config_dark)) - } + // Check that the correct settings are selected. + composeTestRule.onNodeWithText(getString(R.string.brand_android)).assertIsSelected() + composeTestRule.onNodeWithText(getString(R.string.dark_mode_config_dark)).assertIsSelected() } @Test fun whenStateIsSuccess_allLinksAreDisplayed() { - launchSettingsDialogRobot( - composeTestRule, - Success( - UserEditableSettings( - brand = ANDROID, - darkThemeConfig = DARK - ) + composeTestRule.setContent { + SettingsDialog( + settingsUiState = Success( + UserEditableSettings( + brand = ANDROID, + darkThemeConfig = DARK + ) + ), + onDismiss = { }, + onChangeThemeBrand = {}, + onChangeDarkThemeConfig = {} ) - ) { - settingExists(getString(R.string.privacy_policy)) - settingExists(getString(R.string.licenses)) - settingExists(getString(R.string.brand_guidelines)) - settingExists(getString(R.string.feedback)) } - } -} -private fun launchSettingsDialogRobot( - composeTestRule: AndroidComposeTestRule, ComponentActivity>, - settingsUiState: SettingsUiState, - func: SettingsDialogRobot.() -> Unit -) = SettingsDialogRobot(composeTestRule).apply { - setContent(settingsUiState) - func() + composeTestRule.onNodeWithText(getString(R.string.privacy_policy)).assertExists() + composeTestRule.onNodeWithText(getString(R.string.licenses)).assertExists() + composeTestRule.onNodeWithText(getString(R.string.brand_guidelines)).assertExists() + composeTestRule.onNodeWithText(getString(R.string.feedback)).assertExists() + } }