diff --git a/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityTest.kt index d56ee51917b..dd257e50471 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AdministratorControlsActivityTest.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.view.View import android.view.ViewParent import android.widget.FrameLayout +import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.core.widget.NestedScrollView import androidx.drawerlayout.widget.DrawerLayout @@ -34,13 +35,11 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.util.HumanReadables import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.rule.ActivityTestRule import dagger.Component import org.hamcrest.Matchers import org.hamcrest.Matchers.not import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.oppia.android.R @@ -103,13 +102,6 @@ import javax.inject.Singleton ) class AdministratorControlsActivityTest { - @get:Rule - var activityTestRule: ActivityTestRule = ActivityTestRule( - AdministratorControlsActivity::class.java, /* initialTouchMode= */ - true, /* launchActivity= */ - false - ) - @Inject lateinit var profileTestHelper: ProfileTestHelper @@ -145,51 +137,24 @@ class AdministratorControlsActivityTest { ) ).use { testCoroutineDispatchers.runCurrent() - onView( - atPositionOnView( - R.id.administrator_controls_list, - 0, R.id.general_text_view - ) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 0, + targetView = R.id.general_text_view ) - .check(matches(isDisplayed())) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 0, R.id.edit_account_text_view - ) + verifyTextOnAdministratorListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.edit_account_text_view, + stringIdToMatch = R.string.administrator_controls_edit_account ) - .check( - matches( - withText( - context.resources.getString( - R.string.administrator_controls_edit_account - ) - ) - ) - ) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 1, - R.id.profile_management_text_view - ) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 1, + targetView = R.id.profile_management_text_view ) - .check(matches(isDisplayed())) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 1, R.id.edit_profiles_text_view - ) + verifyTextOnAdministratorListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.edit_profiles_text_view, + stringIdToMatch = R.string.administrator_controls_edit_profiles ) - .check( - matches( - withText( - context.resources.getString( - R.string.administrator_controls_edit_profiles - ) - ) - ) - ) } } @@ -201,43 +166,20 @@ class AdministratorControlsActivityTest { ) ).use { testCoroutineDispatchers.runCurrent() - onView( - atPositionOnView( - R.id.administrator_controls_list, - 2, - R.id.download_permissions_text_view - ) - ) - .check( - matches( - withText( - context.resources.getString( - R.string.administrator_controls_download_permissions_label - ) - ) - ) - ) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 2, - R.id.topic_update_on_wifi_constraint_layout - ) + verifyTextOnAdministratorListItemAtPosition( + itemPosition = 2, + targetViewId = R.id.download_permissions_text_view, + stringIdToMatch = R.string.administrator_controls_download_permissions_label ) - .check(matches(isDisplayed())) - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 2 - ) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 2, + targetView = R.id.topic_update_on_wifi_constraint_layout ) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 2, - R.id.auto_update_topic_constraint_layout - ) + scrollToPosition(position = 2) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 2, + targetView = R.id.auto_update_topic_constraint_layout ) - .check(matches(isDisplayed())) } } @@ -249,55 +191,25 @@ class AdministratorControlsActivityTest { ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 3 - ) - ) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 3, R.id.app_information_text_view - ) + scrollToPosition(position = 3) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 3, + targetView = R.id.app_information_text_view ) - .check(matches(isDisplayed())) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 3, R.id.app_version_text_view - ) + verifyTextOnAdministratorListItemAtPosition( + itemPosition = 3, + targetViewId = R.id.app_version_text_view, + stringIdToMatch = R.string.administrator_controls_app_version ) - .check( - matches( - withText( - context.resources.getString( - R.string.administrator_controls_app_version - ) - ) - ) - ) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 4, R.id.account_actions_text_view - ) + verifyItemDisplayedOnAdministratorControlListItem( + itemPosition = 4, + targetView = R.id.account_actions_text_view ) - .check(matches(isDisplayed())) - onView( - atPositionOnView( - R.id.administrator_controls_list, - 4, R.id.log_out_text_view - ) + verifyTextOnAdministratorListItemAtPosition( + itemPosition = 4, + targetViewId = R.id.log_out_text_view, + stringIdToMatch = R.string.administrator_controls_log_out ) - .check( - matches( - withText( - context.resources.getString( - R.string.administrator_controls_log_out - ) - ) - ) - ) } } @@ -315,20 +227,15 @@ class AdministratorControlsActivityTest { 2, R.id.topic_update_on_wifi_switch ) - ) - .check(matches(not(isChecked()))) - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 2 - ) - ) + ).check(matches(not(isChecked()))) + scrollToPosition(position = 2) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.auto_update_topic_switch + 2, + R.id.auto_update_topic_switch ) - ) - .check(matches(not(isChecked()))) + ).check(matches(not(isChecked()))) } } @@ -340,72 +247,60 @@ class AdministratorControlsActivityTest { ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 2 - ) - ) + scrollToPosition(position = 2) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.topic_update_on_wifi_switch + 2, + R.id.topic_update_on_wifi_switch ) - ) - .check(matches(not(isChecked()))) + ).check(matches(not(isChecked()))) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.auto_update_topic_switch + 2, + R.id.auto_update_topic_switch ) - ) - .check(matches(not(isChecked()))) + ).check(matches(not(isChecked()))) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.topic_update_on_wifi_switch + 2, + R.id.topic_update_on_wifi_switch ) - ) - .perform(click()) + ).perform(click()) onView(isRoot()).perform(orientationLandscape()) - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 2 - ) - ) + scrollToPosition(position = 2) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.topic_update_on_wifi_switch + 2, + R.id.topic_update_on_wifi_switch ) - ) - .check(matches(isChecked())) + ).check(matches(isChecked())) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.auto_update_topic_switch + 2, + R.id.auto_update_topic_switch ) - ) - .check(matches(not(isChecked()))) + ).check(matches(not(isChecked()))) onView(isRoot()).perform(orientationPortrait()) - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 2 - ) - ) + scrollToPosition(position = 2) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.topic_update_on_wifi_switch + 2, + R.id.topic_update_on_wifi_switch ) - ) - .check(matches(isChecked())) + ).check(matches(isChecked())) onView( atPositionOnView( R.id.administrator_controls_list, - 2, R.id.auto_update_topic_switch + 2, + R.id.auto_update_topic_switch ) - ) - .check(matches(not(isChecked()))) + ).check(matches(not(isChecked()))) } } @@ -413,7 +308,7 @@ class AdministratorControlsActivityTest { fun testAdministratorControlsFragment_clickEditProfile_opensProfileListActivity() { launch( createAdministratorControlsActivityIntent( - 0 + profileId = 0 ) ).use { testCoroutineDispatchers.runCurrent() @@ -423,54 +318,36 @@ class AdministratorControlsActivityTest { } @Test - fun testAdministratorControlsFragment_clickLogoutButton_displaysLogoutDialog() { + fun testAdministratorControlsFragment_clickLogoutButton_logoutDialogIsDisplayed() { launch( createAdministratorControlsActivityIntent( profileId = 0 ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 4 - ) - ) + scrollToPosition(position = 4) onView(withId(R.id.log_out_text_view)).perform(click()) - onView(withText(R.string.log_out_dialog_message)).inRoot(isDialog()) - .check(matches(isDisplayed())) - onView(withText(R.string.log_out_dialog_okay_button)).inRoot(isDialog()) - .check(matches(isDisplayed())) - onView(withText(R.string.log_out_dialog_cancel_button)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_message) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_okay_button) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_cancel_button) } } @Test - fun testAdministratorControlsFragment_changeConfiguration_clickLogout_displaysLogoutDialog() { + fun testAdministratorControlsFragment_configChange_clickLogout_logoutDialogIsDisplayed() { launch( createAdministratorControlsActivityIntent( profileId = 0 ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 4 - ) - ) + scrollToPosition(position = 4) onView(isRoot()).perform(orientationLandscape()) - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 4 - ) - ) + scrollToPosition(position = 4) onView(withId(R.id.log_out_text_view)).perform(click()) - onView(withText(R.string.log_out_dialog_message)).inRoot(isDialog()) - .check(matches(isDisplayed())) - onView(withText(R.string.log_out_dialog_okay_button)).inRoot(isDialog()) - .check(matches(isDisplayed())) - onView(withText(R.string.log_out_dialog_cancel_button)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_message) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_okay_button) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_cancel_button) } } @@ -483,35 +360,25 @@ class AdministratorControlsActivityTest { ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 4 - ) - ) + scrollToPosition(position = 4) onView(withId(R.id.log_out_text_view)).perform(click()) - onView(withText(R.string.log_out_dialog_message)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_message) onView(withText(R.string.log_out_dialog_okay_button)).perform(click()) intended(hasComponent(ProfileChooserActivity::class.java.name)) } } @Test - fun testAdministratorControlsFragment_clickCancelButtonInLogoutDialog_dialogDismissed() { + fun testAdministratorControlsFragment_clickCancelButtonInLogoutDialog_dialogIsDismissed() { launch( createAdministratorControlsActivityIntent( profileId = 0 ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 4 - ) - ) + scrollToPosition(position = 4) onView(withId(R.id.log_out_text_view)).perform(click()) - onView(withText(R.string.log_out_dialog_message)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(textInDialogId = R.string.log_out_dialog_message) onView(withText(R.string.log_out_dialog_cancel_button)).perform(click()) onView(withId(R.id.log_out_text_view)).check(matches(isDisplayed())) } @@ -521,22 +388,18 @@ class AdministratorControlsActivityTest { fun testAdministratorControlsFragment_clickAppVersion_opensAppVersionActivity() { launch( createAdministratorControlsActivityIntent( - 0 + profileId = 0 ) ).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.administrator_controls_list)).perform( - scrollToPosition( - 3 - ) - ) + scrollToPosition(position = 3) onView(withId(R.id.app_version_text_view)).perform(click()) intended(hasComponent(AppVersionActivity::class.java.name)) } } @Test - fun testAdministratorControls_selectAdminNavItem_displaysAdminControls() { + fun testAdministratorControls_selectAdminNavItem_adminControlsIsDisplayed() { launch( createAdministratorControlsActivityIntent( 0 @@ -638,6 +501,47 @@ class AdministratorControlsActivityTest { return view.getParent() } + private fun verifyItemDisplayedOnAdministratorControlListItem( + itemPosition: Int, + targetView: Int + ) { + onView( + atPositionOnView( + R.id.administrator_controls_list, + itemPosition, + targetView + ) + ).check(matches(isDisplayed())) + } + + private fun verifyTextOnAdministratorListItemAtPosition( + itemPosition: Int, + targetViewId: Int, + @StringRes stringIdToMatch: Int + ) { + onView( + atPositionOnView( + R.id.administrator_controls_list, + itemPosition, + targetViewId + ) + ).check(matches(withText(context.getString(stringIdToMatch)))) + } + + private fun scrollToPosition(position: Int) { + onView(withId(R.id.administrator_controls_list)).perform( + scrollToPosition( + position + ) + ) + } + + private fun verifyTextInDialog(@StringRes textInDialogId: Int) { + onView(withText(context.getString(textInDialogId))) + .inRoot(isDialog()) + .check(matches(isDisplayed())) + } + // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. // TODO(#1675): Add NetworkModule once data module is migrated off of Moshi. @Singleton diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt index 606d8c9d898..6e691da1555 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt @@ -114,7 +114,8 @@ class HomeActivityTest { @Inject lateinit var testCoroutineDispatchers: TestCoroutineDispatchers - private val internalProfileId: Int = 1 + private val internalProfileId: Int = 0 + private val internalProfileId1: Int = 1 private lateinit var oppiaClock: OppiaClock @Before @@ -144,143 +145,113 @@ class HomeActivityTest { } @Test - fun testHomeActivity_withAdminProfile_profileNameDisplayedSuccessfully() { - launch(createHomeActivityIntent(0)).use { + fun testHomeActivity_withAdminProfile_displayProfileName_profileNameIsDisplayed() { + launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(0) + scrollToPosition(position = 0) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.profile_name_textview, + stringToMatch = "Admin!" ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 0, - R.id.profile_name_textview - ) - ).check(matches(withText("Admin!"))) } } @Test - fun testHomeActivity_withAdminProfile_configChange_profileNameDisplayedSuccessfully() { - launch(createHomeActivityIntent(0)).use { + fun testHomeActivity_withAdminProfile_configChange_profileNameIsDisplayed() { + launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(0) + scrollToPosition(position = 0) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.profile_name_textview, + stringToMatch = "Admin!" ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 0, - R.id.profile_name_textview - ) - ).check(matches(withText("Admin!"))) } } @Test - fun testHomeActivity_recyclerViewIndex0_displayGreetingMessageBasedOnTime_goodMorningMessageDisplayedSuccessful() { // ktlint-disable max-line-length + fun testHomeActivity_displayGreetingMessageBasedOnTime_goodMorningMessageIsDisplayed() { getApplicationDependencies() oppiaClock.setCurrentTimeMs(MORNING_TIMESTAMP) - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(0) + scrollToPosition(position = 0) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.welcome_text_view, + stringToMatch = "Good morning," ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 0, - R.id.welcome_text_view - ) - ).check(matches(withText("Good morning,"))) } } @Test - fun testHomeActivity_recyclerViewIndex0_displayGreetingMessageBasedOnTime_goodAfternoonMessageDisplayedSuccessful() { // ktlint-disable max-line-length + fun testHomeActivity_displayGreetingMessageBasedOnTime_goodAfternoonMessageIsDisplayed() { getApplicationDependencies() oppiaClock.setCurrentTimeMs(AFTERNOON_TIMESTAMP) - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(0) + scrollToPosition(position = 0) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.welcome_text_view, + stringToMatch = "Good afternoon," ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 0, - R.id.welcome_text_view - ) - ).check(matches(withText("Good afternoon,"))) } } @Test - fun testHomeActivity_recyclerViewIndex0_displayGreetingMessageBasedOnTime_goodEveningMessageDisplayedSuccessful() { // ktlint-disable max-line-length + fun testHomeActivity_displayGreetingMessageBasedOnTime_goodEveningMessageIsDisplayed() { getApplicationDependencies() oppiaClock.setCurrentTimeMs(EVENING_TIMESTAMP) - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(0) + scrollToPosition(position = 0) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 0, + targetViewId = R.id.welcome_text_view, + stringToMatch = "Good evening," ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 0, - R.id.welcome_text_view - ) - ).check(matches(withText("Good evening,"))) } } @Test - fun testHomeActivity_recyclerViewIndex1_displaysRecentlyPlayedStoriesText() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_recentlyPlayedStoriesTextIsDisplayed() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 1, - R.id.recently_played_stories_text_view - ) - ).check( - matches( - withText(R.string.recently_played_stories) - ) + scrollToPosition(position = 1) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.recently_played_stories_text_view, + stringToMatch = context.getString(R.string.recently_played_stories) ) } } @Test - fun testHomeActivity_recyclerViewIndex1_displaysViewAllText() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_userProfile_viewAllTextIsDisplayed() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.view_all_text_view)).check( - matches( - withText(R.string.view_all) - ) + scrollToPosition(position = 1) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.view_all_text_view, + stringToMatch = context.getString(R.string.view_all) ) } } @Test - fun testHomeActivity_recyclerViewIndex1_clickViewAll_opensRecentlyPlayedActivity() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_clickViewAll_opensRecentlyPlayedActivity() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) + scrollToPosition(position = 1) onView( atPositionOnView( - R.id.home_recycler_view, 1, R.id.view_all_text_view + R.id.home_recycler_view, + 1, + R.id.view_all_text_view ) ).perform(click()) intended(hasComponent(RecentlyPlayedActivity::class.java.name)) @@ -288,8 +259,8 @@ class HomeActivityTest { } @Test - fun testHomeActivity_recyclerViewIndex1_promotedCard_chapterNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_promotedCard_chapterNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() onView( allOf( @@ -303,43 +274,37 @@ class HomeActivityTest { } @Test - fun testHomeActivity_recyclerViewIndex1_promotedCard_storyNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_promotedCard_storyNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( - matches( - withText(containsString("First Story")) - ) + scrollToPosition(position = 1) + verifyTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.story_name_text_view, + stringToMatch = "First Story" ) } } @Test - fun testHomeActivity_recyclerViewIndex1_configurationChange_promotedCard_storyNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_configChange_promotedCard_storyNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) + scrollToPosition(position = 1) onView(isRoot()).perform(orientationLandscape()) - onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( - matches( - withText(containsString("First Story")) - ) + verifyTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.story_name_text_view, + stringToMatch = "First Story" ) } } @Test - fun testHomeActivity_recyclerViewIndex1_clickPromotedStory_opensTopicActivity() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_clickPromotedStory_opensTopicActivity() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) + scrollToPosition(position = 1) onView( allOf( withId(R.id.promoted_story_list_recycler_view), @@ -349,125 +314,96 @@ class HomeActivityTest { ) ).perform(click()) intended(hasComponent(TopicActivity::class.java.name)) - intended(hasExtra(TopicActivity.getProfileIdKey(), internalProfileId)) + intended(hasExtra(TopicActivity.getProfileIdKey(), internalProfileId1)) intended(hasExtra(TopicActivity.getTopicIdKey(), TEST_TOPIC_ID_0)) intended(hasExtra(TopicActivity.getStoryIdKey(), TEST_STORY_ID_0)) } } @Test - fun testHomeActivity_recyclerViewIndex1_promotedCard_topicNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_promotedCard_topicNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.topic_name_text_view)).check( - matches( - withText(containsString("FIRST TEST TOPIC")) - ) + scrollToPosition(position = 1) + verifyTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.topic_name_text_view, + stringToMatch = "FIRST TEST TOPIC" ) } } @Test - fun testHomeActivity_recyclerViewIndex3_topicSummary_topicNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_topicSummaryCard_topicNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(3) - ) - onView(atPositionOnView(R.id.home_recycler_view, 3, R.id.topic_name_text_view)).check( - matches( - withText(containsString("First Test Topic")) - ) + scrollToPosition(position = 3) + verifyTextOnHomeListItemAtPosition( + itemPosition = 3, + targetViewId = R.id.topic_name_text_view, + stringToMatch = "First Test Topic" ) } } @Test - fun testHomeActivity_recyclerViewIndex3_topicSummary_lessonCountIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_topicSummaryCard_lessonCountIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(3) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 3, R.id.lesson_count_text_view - ) - ).check( - matches( - withText(containsString("5 Lessons")) - ) + scrollToPosition(position = 3) + verifyTextOnHomeListItemAtPosition( + itemPosition = 3, + targetViewId = R.id.lesson_count_text_view, + stringToMatch = "5 Lessons" ) } } @Test - fun testHomeActivity_recyclerViewIndex4_topicSummary_topicNameIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_topicSummarySecondCard_topicNameIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(4) - ) - onView(atPositionOnView(R.id.home_recycler_view, 4, R.id.topic_name_text_view)).check( - matches( - withText(containsString("Second Test Topic")) - ) + scrollToPosition(position = 4) + verifyTextOnHomeListItemAtPosition( + itemPosition = 4, + targetViewId = R.id.topic_name_text_view, + stringToMatch = "Second Test Topic" ) } } @Test - fun testHomeActivity_recyclerViewIndex4_topicSummary_lessonCountIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_topicSummarySecondCard_lessonCountIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(4) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 4, R.id.lesson_count_text_view - ) - ).check( - matches( - withText(containsString("1 Lesson")) - ) + scrollToPosition(position = 4) + verifyTextOnHomeListItemAtPosition( + itemPosition = 4, + targetViewId = R.id.lesson_count_text_view, + stringToMatch = "1 Lesson" ) } } @Test - fun testHomeActivity_recyclerViewIndex4_topicSummary_configurationChange_lessonCountIsCorrect() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_topicSummary_configChange_lessonCountIsCorrect() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(4) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 4, R.id.lesson_count_text_view - ) - ).check( - matches( - withText(containsString("1 Lesson")) - ) + scrollToPosition(position = 4) + verifyTextOnHomeListItemAtPosition( + itemPosition = 4, + targetViewId = R.id.lesson_count_text_view, + stringToMatch = "1 Lesson" ) } } @Test - fun testHomeActivity_recyclerViewIndex3_clickTopicSummary_opensTopicActivity() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_clickTopicSummary_opensTopicActivity() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(3) - ) + scrollToPosition(position = 3) onView(atPosition(R.id.home_recycler_view, 3)).perform(click()) intended(hasComponent(TopicActivity::class.java.name)) intended(hasExtra(TopicActivity.getTopicIdKey(), TEST_TOPIC_ID_0)) @@ -476,7 +412,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_showsExitToProfileChooserDialog() { - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() pressBack() onView(withText(R.string.home_activity_back_dialog_message)) @@ -487,7 +423,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_orientationChange_showsExitToProfileChooserDialog() { - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() pressBack() onView(isRoot()).perform(orientationLandscape()) @@ -499,7 +435,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_clickExit_checkOpensProfileActivity() { - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() pressBack() onView(withText(R.string.home_activity_back_dialog_exit)) @@ -511,7 +447,7 @@ class HomeActivityTest { @Test fun testHomeActivity_checkSpanForItem0_spanSizeIsTwoOrThree() { - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() if (context.resources.getBoolean(R.bool.isTablet)) { onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(3, 0)) @@ -523,15 +459,15 @@ class HomeActivityTest { @Test fun testHomeActivity_checkSpanForItem4_spanSizeIsOne() { - launch(createHomeActivityIntent(internalProfileId)).use { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(1, 4)) } } @Test - fun testHomeActivity_configurationChange_checkSpanForItem4_spanSizeIsOne() { - launch(createHomeActivityIntent(internalProfileId)).use { + fun testHomeActivity_configChange_checkSpanForItem4_spanSizeIsOne() { + launch(createHomeActivityIntent(internalProfileId1)).use { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(1, 4)) @@ -539,7 +475,43 @@ class HomeActivityTest { } private fun createHomeActivityIntent(profileId: Int): Intent { - return HomeActivity.createHomeActivity(ApplicationProvider.getApplicationContext(), profileId) + return HomeActivity.createHomeActivity(context, profileId) + } + + private fun scrollToPosition(position: Int) { + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition( + position + ) + ) + } + + private fun verifyTextOnHomeListItemAtPosition( + itemPosition: Int, + targetViewId: Int, + stringToMatch: String + ) { + onView( + atPositionOnView( + R.id.home_recycler_view, + itemPosition, + targetViewId + ) + ).check(matches(withText(containsString(stringToMatch)))) + } + + private fun verifyExactTextOnHomeListItemAtPosition( + itemPosition: Int, + targetViewId: Int, + stringToMatch: String + ) { + onView( + atPositionOnView( + R.id.home_recycler_view, + itemPosition, + targetViewId + ) + ).check(matches(withText(stringToMatch))) } // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. diff --git a/app/src/sharedTest/java/org/oppia/android/app/profileprogress/ProfileProgressFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/profileprogress/ProfileProgressFragmentTest.kt index 7d95f701c90..daa4be77e92 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/profileprogress/ProfileProgressFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/profileprogress/ProfileProgressFragmentTest.kt @@ -9,16 +9,11 @@ import android.content.Intent import android.content.res.Resources import android.net.Uri import android.provider.MediaStore -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.RecyclerView import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.PerformException -import androidx.test.espresso.UiController -import androidx.test.espresso.ViewAction -import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition @@ -35,14 +30,11 @@ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText -import androidx.test.espresso.util.HumanReadables -import androidx.test.espresso.util.TreeIterables import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.Component import dagger.Module import dagger.Provides import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.not import org.hamcrest.Matcher import org.junit.After @@ -104,7 +96,6 @@ import org.oppia.android.util.parser.HtmlParserEntityTypeModule import org.oppia.android.util.parser.ImageParsingModule import org.robolectric.annotation.Config import org.robolectric.annotation.LooperMode -import java.util.concurrent.TimeoutException import javax.inject.Inject import javax.inject.Singleton @@ -148,6 +139,10 @@ class ProfileProgressFragmentTest { Intents.release() } + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + private fun createProfileProgressActivityIntent(profileId: Int): Intent { return ProfileProgressActivity.createProfileProgressActivityIntent( ApplicationProvider.getApplicationContext(), @@ -159,11 +154,10 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragment_checkProfileName_profileNameIsCorrect() { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.profile_name_text_view) - ).check( - matches(withText("Admin")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.profile_name_text_view, + stringToMatch = "Admin" ) } } @@ -173,11 +167,10 @@ class ProfileProgressFragmentTest { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) - waitForTheView(withText("Admin")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.profile_name_text_view) - ).check( - matches(withText("Admin")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.profile_name_text_view, + stringToMatch = "Admin" ) } } @@ -186,17 +179,9 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragment_openProfilePictureEditDialog() { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.profile_edit_image - ) - ).perform(click()) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.profile_edit_image) testCoroutineDispatchers.runCurrent() - onView(withText(R.string.profile_progress_edit_dialog_title)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(context.getString(R.string.profile_progress_edit_dialog_title)) } } @@ -204,17 +189,8 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragment_openProfilePictureEditDialog_configurationChange_dialogIsStillOpen() { // ktlint-disable max-line-length launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.profile_edit_image - ) - ).perform(click()) - testCoroutineDispatchers.runCurrent() - onView(withText(R.string.profile_progress_edit_dialog_title)).inRoot(isDialog()) - .check(matches(isDisplayed())) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.profile_edit_image) + verifyTextInDialog(context.getString(R.string.profile_progress_edit_dialog_title)) onView(isRoot()).perform(orientationLandscape()) onView(withText(R.string.profile_progress_edit_dialog_title)).check(matches(isDisplayed())) } @@ -230,17 +206,8 @@ class ProfileProgressFragmentTest { intending(expectedIntent).respondWith(activityResult) launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.profile_edit_image - ) - ).perform(click()) - testCoroutineDispatchers.runCurrent() - onView(withText(R.string.profile_progress_edit_dialog_title)).inRoot(isDialog()) - .check(matches(isDisplayed())) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.profile_edit_image) + verifyTextInDialog(context.getString(R.string.profile_progress_edit_dialog_title)) onView(withText(R.string.profile_picture_edit_alert_dialog_choose_from_library)) .perform(click()) intended(expectedIntent) @@ -257,17 +224,8 @@ class ProfileProgressFragmentTest { intending(expectedIntent).respondWith(activityResult) launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.profile_edit_image - ) - ).perform(click()) - testCoroutineDispatchers.runCurrent() - onView(withText(R.string.profile_progress_edit_dialog_title)).inRoot(isDialog()) - .check(matches(isDisplayed())) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.profile_edit_image) + verifyTextInDialog(context.getString(R.string.profile_progress_edit_dialog_title)) onView(withText(R.string.profile_picture_edit_alert_dialog_choose_from_library)) .perform(click()) testCoroutineDispatchers.runCurrent() @@ -275,17 +233,9 @@ class ProfileProgressFragmentTest { onView(isRoot()).perform(orientationLandscape()) testCoroutineDispatchers.runCurrent() intended(expectedIntent) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.profile_edit_image - ) - ).perform(click()) - testCoroutineDispatchers.runCurrent() + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.profile_edit_image) // The dialog should still be open after a configuration change. - onView(withText(R.string.profile_progress_edit_dialog_title)).inRoot(isDialog()) - .check(matches(isDisplayed())) + verifyTextInDialog(context.getString(R.string.profile_progress_edit_dialog_title)) } } @@ -293,11 +243,10 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragmentNoProgress_recyclerViewItem0_checkOngoingTopicsCount_countIsZero() { // ktlint-disable max-line-length launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("0")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.ongoing_topics_count) - ).check( - matches(withText("0")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_count, + stringToMatch = "0" ) } } @@ -315,11 +264,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("2")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.ongoing_topics_count) - ).check( - matches(withText("2")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_count, + stringToMatch = "2" ) } } @@ -339,11 +287,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) testCoroutineDispatchers.runCurrent() - waitForTheView(withText("2")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.ongoing_topics_count) - ).check( - matches(withText("2")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_count, + stringToMatch = "2" ) } } @@ -352,14 +299,10 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragmentNoProgress_recyclerViewItem0_checkOngoingTopicsString_descriptionIsCorrect() { // ktlint-disable max-line-length launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.topics_in_progress)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, R.id.ongoing_topics_description_text_view - ) - ).check( - matches(withText(R.string.topics_in_progress)) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_description_text_view, + stringToMatch = context.getString(R.string.topics_in_progress) ) } } @@ -377,14 +320,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.topics_in_progress)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, R.id.ongoing_topics_description_text_view - ) - ).check( - matches(withText(R.string.topics_in_progress)) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_description_text_view, + stringToMatch = context.getString(R.string.topics_in_progress) ) } } @@ -404,14 +343,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.topics_in_progress)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, R.id.ongoing_topics_description_text_view - ) - ).check( - matches(withText(R.string.topics_in_progress)) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.ongoing_topics_description_text_view, + stringToMatch = context.getString(R.string.topics_in_progress) ) } } @@ -420,11 +355,10 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragmentNoProgress_recyclerViewItem0_checkCompletedStoriesCount_countIsZero() { // ktlint-disable max-line-length launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("0")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.completed_stories_count) - ).check( - matches(withText("0")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.completed_stories_count, + stringToMatch = "0" ) } } @@ -442,11 +376,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("2")) - onView( - atPositionOnView(R.id.profile_progress_list, 0, R.id.completed_stories_count) - ).check( - matches(withText("2")) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.completed_stories_count, + stringToMatch = "2" ) } } @@ -455,15 +388,10 @@ class ProfileProgressFragmentTest { fun testProfileProgressFragmentNoProgress_recyclerViewItem0_checkCompletedStoriesString_descriptionIsCorrect() { // ktlint-disable max-line-length launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.stories_completed)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.completed_stories_description_text_view - ) - ).check( - matches(withText(R.string.stories_completed)) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.completed_stories_description_text_view, + stringToMatch = context.getString(R.string.stories_completed) ) } } @@ -481,15 +409,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.stories_completed)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.completed_stories_description_text_view - ) - ).check( - matches(withText(R.string.stories_completed)) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.completed_stories_description_text_view, + stringToMatch = context.getString(R.string.stories_completed) ) } } @@ -502,11 +425,10 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() onView(withId(R.id.profile_progress_list)) .perform(scrollToPosition(1)) - waitForTheView(withText("First Story")) - onView( - atPositionOnView(R.id.profile_progress_list, 1, R.id.story_name_text_view) - ).check( - matches(withText(containsString("First Story"))) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 1, + targetViewId = R.id.story_name_text_view, + stringToMatch = "First Story" ) } } @@ -520,14 +442,10 @@ class ProfileProgressFragmentTest { 1 ) ) - waitForTheView(withText("First Story")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 1, R.id.story_name_text_view - ) - ).check( - matches(withText(containsString("First Story"))) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 1, + targetViewId = R.id.story_name_text_view, + stringToMatch = "First Story" ) } } @@ -541,14 +459,10 @@ class ProfileProgressFragmentTest { 1 ) ) - waitForTheView(withText("FIRST TEST TOPIC")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 1, R.id.topic_name_text_view - ) - ).check( - matches(withText(containsString("FIRST TEST TOPIC"))) + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 1, + targetViewId = R.id.topic_name_text_view, + stringToMatch = "FIRST TEST TOPIC" ) } } @@ -562,14 +476,8 @@ class ProfileProgressFragmentTest { 1 ) ) - waitForTheView(withText("FIRST TEST TOPIC")) - onView( - atPositionOnView( - R.id.profile_progress_list, - 1, R.id.topic_name_text_view - ) - ).perform(click()) testCoroutineDispatchers.runCurrent() + clickProfileProgressItem(itemPosition = 1, targetViewId = R.id.topic_name_text_view) intended(hasComponent(TopicActivity::class.java.name)) intended(hasExtra(TopicActivity.getProfileIdKey(), internalProfileId)) intended(hasExtra(TopicActivity.getTopicIdKey(), TEST_TOPIC_ID_0)) @@ -581,13 +489,12 @@ class ProfileProgressFragmentTest { fun testProfileProgressActivity_recyclerViewIndex0_clickViewAll_opensRecentlyPlayedActivity() { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText("Admin")) - onView(atPositionOnView(R.id.profile_progress_list, 0, R.id.view_all_text_view)) - .check( - matches(withText("View All")) - ) - .perform(click()) - testCoroutineDispatchers.runCurrent() + verifyItemDisplayedOnProfileProgressListItem( + itemPosition = 0, + targetViewId = R.id.view_all_text_view, + stringToMatch = "View All" + ) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.view_all_text_view) intended(hasComponent(RecentlyPlayedActivity::class.java.name)) intended( hasExtra( @@ -602,15 +509,13 @@ class ProfileProgressFragmentTest { fun testProfileProgressActivityNoProgress_recyclerViewIndex0_clickTopicCount_isNotClickable() { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.topics_in_progress)) onView( atPositionOnView( R.id.profile_progress_list, - 0, R.id.ongoing_topics_container + 0, + R.id.ongoing_topics_container ) - ).check( - matches(not(isClickable())) - ) + ).check(matches(not(isClickable()))) } } @@ -618,15 +523,13 @@ class ProfileProgressFragmentTest { fun testProfileProgressActivityNoProgress_recyclerViewIndex0_clickStoryCount_isNotClickable() { launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.stories_completed)) onView( atPositionOnView( R.id.profile_progress_list, - 0, R.id.completed_stories_container + 0, + R.id.completed_stories_container ) - ).check( - matches(not(isClickable())) - ) + ).check(matches(not(isClickable()))) } } @@ -636,39 +539,30 @@ class ProfileProgressFragmentTest { testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.stories_completed)) onView( atPositionOnView( R.id.profile_progress_list, - 0, R.id.completed_stories_container + 0, + R.id.completed_stories_container ) - ).check( - matches(not(isClickable())) - ) + ).check(matches(not(isClickable()))) } } @Test fun testProfileProgressActivityWithProgress_recyclerViewIndex0_clickTopicCount_opensOngoingTopicListActivity() { // ktlint-disable max-line-length storyProgressTestHelper.markPartialTopicProgressForFractions( - profileId, + profileId = profileId, timestampOlderThanAWeek = false ) storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - profileId, + profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.topics_in_progress)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.ongoing_topics_container - ) - ).perform(click()) + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.ongoing_topics_container) testCoroutineDispatchers.runCurrent() intended(hasComponent(OngoingTopicListActivity::class.java.name)) intended( @@ -683,25 +577,17 @@ class ProfileProgressFragmentTest { @Test fun testProfileProgressActivityWithProgress_recyclerViewIndex0_clickStoryCount_opensCompletedStoryListActivity() { // ktlint-disable max-line-length storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, + profileId = profileId, timestampOlderThanAWeek = false ) storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, + profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() launch(createProfileProgressActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - waitForTheView(withText(R.string.stories_completed)) - onView( - atPositionOnView( - R.id.profile_progress_list, - 0, - R.id.completed_stories_container - ) - ).perform(click()) - testCoroutineDispatchers.runCurrent() + clickProfileProgressItem(itemPosition = 0, targetViewId = R.id.completed_stories_container) intended(hasComponent(CompletedStoryListActivity::class.java.name)) intended( hasExtra( @@ -725,51 +611,35 @@ class ProfileProgressFragmentTest { return Instrumentation.ActivityResult(RESULT_OK, resultIntent) } - private fun waitForTheView(viewMatcher: Matcher): ViewInteraction { - return onView(isRoot()).perform(waitForMatch(viewMatcher, 30000)) - } - - // TODO(#59): Remove these waits once we can ensure that the production executors are not depended on in tests. - // Sleeping is really bad practice in Espresso tests, and can lead to test flakiness. It shouldn't be necessary if we - // use a test executor service with a counting idle resource, but right now Gradle mixes dependencies such that both - // the test and production blocking executors are being used. The latter cannot be updated to notify Espresso of any - // active coroutines, so the test attempts to assert state before it's ready. This artificial delay in the Espresso - // thread helps to counter that. - /** - * Perform action of waiting for a specific matcher to finish. Adapted from: - * https://stackoverflow.com/a/22563297/3689782. - */ - private fun waitForMatch(viewMatcher: Matcher, millis: Long): ViewAction { - return object : ViewAction { - override fun getDescription(): String { - return "wait for a specific view with matcher <$viewMatcher> during $millis millis." - } - - override fun getConstraints(): Matcher { - return isRoot() - } - - override fun perform(uiController: UiController?, view: View?) { - checkNotNull(uiController) - uiController.loopMainThreadUntilIdle() - val startTime = System.currentTimeMillis() - val endTime = startTime + millis - - do { - if (TreeIterables.breadthFirstViewTraversal(view).any { viewMatcher.matches(it) }) { - return - } - uiController.loopMainThreadForAtLeast(50) - } while (System.currentTimeMillis() < endTime) - - // Couldn't match in time. - throw PerformException.Builder() - .withActionDescription(description) - .withViewDescription(HumanReadables.describe(view)) - .withCause(TimeoutException()) - .build() - } - } + private fun verifyItemDisplayedOnProfileProgressListItem( + itemPosition: Int, + targetViewId: Int, + stringToMatch: String + ) { + onView( + atPositionOnView( + R.id.profile_progress_list, + itemPosition, + targetViewId + ) + ).check(matches(withText(stringToMatch))) + } + + private fun clickProfileProgressItem(itemPosition: Int, targetViewId: Int) { + onView( + atPositionOnView( + R.id.profile_progress_list, + itemPosition, + targetViewId + ) + ).perform(click()) + testCoroutineDispatchers.runCurrent() + } + + private fun verifyTextInDialog(textInDialog: String) { + onView(withText(textInDialog)) + .inRoot(isDialog()) + .check(matches(isDisplayed())) } @Module @@ -789,10 +659,6 @@ class ProfileProgressFragmentTest { fun provideGlobalLogLevel(): LogLevel = LogLevel.VERBOSE } - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. // TODO(#1675): Add NetworkModule once data module is migrated off of Moshi. @Singleton diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 1fd3509e293..6bc4a850d37 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -11,7 +11,6 @@ import dagger.Component import dagger.Module import dagger.Provides import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -117,25 +116,13 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_providesListOfMultipleTopics() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() assertThat(topicList.topicSummaryCount).isGreaterThan(1) } @Test fun testRetrieveTopicList_firstTopic_hasCorrectTopicInfo() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val firstTopic = topicList.getTopicSummary(0) assertThat(firstTopic.topicId).isEqualTo(TEST_TOPIC_ID_0) assertThat(firstTopic.name).isEqualTo("First Test Topic") @@ -143,13 +130,7 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_firstTopic_hasCorrectThumbnail() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val firstTopic = topicList.getTopicSummary(0) assertThat(firstTopic.topicThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.ADDING_AND_SUBTRACTING_FRACTIONS) @@ -157,26 +138,14 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_firstTopic_hasCorrectLessonCount() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val firstTopic = topicList.getTopicSummary(0) assertThat(firstTopic.totalChapterCount).isEqualTo(5) } @Test fun testRetrieveTopicList_secondTopic_hasCorrectTopicInfo() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val secondTopic = topicList.getTopicSummary(1) assertThat(secondTopic.topicId).isEqualTo(TEST_TOPIC_ID_1) assertThat(secondTopic.name).isEqualTo("Second Test Topic") @@ -184,13 +153,7 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_secondTopic_hasCorrectThumbnail() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val secondTopic = topicList.getTopicSummary(1) assertThat(secondTopic.topicThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.BAKER) @@ -198,26 +161,14 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_secondTopic_hasCorrectLessonCount() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val secondTopic = topicList.getTopicSummary(1) assertThat(secondTopic.totalChapterCount).isEqualTo(1) } @Test fun testRetrieveTopicList_fractionsTopic_hasCorrectTopicInfo() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val fractionsTopic = topicList.getTopicSummary(2) assertThat(fractionsTopic.topicId).isEqualTo(FRACTIONS_TOPIC_ID) assertThat(fractionsTopic.name).isEqualTo("Fractions") @@ -225,13 +176,7 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_fractionsTopic_hasCorrectThumbnail() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val fractionsTopic = topicList.getTopicSummary(2) assertThat(fractionsTopic.topicThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) @@ -239,26 +184,14 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_fractionsTopic_hasCorrectLessonCount() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val fractionsTopic = topicList.getTopicSummary(2) assertThat(fractionsTopic.totalChapterCount).isEqualTo(2) } @Test fun testRetrieveTopicList_ratiosTopic_hasCorrectTopicInfo() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val ratiosTopic = topicList.getTopicSummary(3) assertThat(ratiosTopic.topicId).isEqualTo(RATIOS_TOPIC_ID) assertThat(ratiosTopic.name).isEqualTo("Ratios and Proportional Reasoning") @@ -266,13 +199,7 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_ratiosTopic_hasCorrectThumbnail() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val ratiosTopic = topicList.getTopicSummary(3) assertThat(ratiosTopic.topicThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) @@ -280,13 +207,7 @@ class TopicListControllerTest { @Test fun testRetrieveTopicList_ratiosTopic_hasCorrectLessonCount() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() + val topicList = retrieveTopicList() val ratiosTopic = topicList.getTopicSummary(3) assertThat(ratiosTopic.totalChapterCount).isEqualTo(4) } @@ -317,7 +238,6 @@ class TopicListControllerTest { } @Test - @Ignore("Failing on Circle CI.") fun testRetrieveOngoingStoryList_markRecentlyPlayedFracStory0Exp0_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, @@ -326,15 +246,8 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_0, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recentStoryList[0]) } @@ -348,15 +261,8 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_0, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) } @@ -379,21 +285,13 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_1, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) } @Test - @Ignore("Failing on Circle CI.") fun testRetrieveOngoingStoryList_markAllChaptersCompletedInFractions_ongoingStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, @@ -411,16 +309,9 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_1, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) + val ongoingTopicList = retrieveOngoingStoryList() + assertThat(ongoingTopicList.recentStoryCount).isEqualTo(4) verifyDefaultOngoingStoryListSucceeded() } @@ -442,15 +333,8 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[0]) verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) @@ -474,15 +358,8 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[0]) verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) @@ -515,15 +392,8 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(3) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[1]) @@ -557,15 +427,8 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + val ongoingTopicList = retrieveOngoingStoryList() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) assertThat(ongoingTopicList.olderStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.olderStoryList[0]) @@ -695,6 +558,23 @@ class TopicListControllerTest { return Date().time - NINE_DAYS_IN_MS } + private fun retrieveTopicList(): TopicList { + val topicListLiveData = topicListController.getTopicList().toLiveData() + topicListLiveData.observeForever(mockTopicListObserver) + testCoroutineDispatchers.runCurrent() + verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) + return topicListResultCaptor.value.getOrThrow() + } + + private fun retrieveOngoingStoryList(): OngoingStoryList { + testCoroutineDispatchers.runCurrent() + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + verifyGetOngoingStoryListSucceeded() + return ongoingStoryListResultCaptor.value.getOrThrow() + } + // TODO(#89): Move this to a common test application component. @Module class TestModule {