From 3d05363c311582f88c1129f9042f0403de75024e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 12 Jul 2018 12:00:08 +0200 Subject: [PATCH] enable Espresso tests with some basic UI tasks --- app/build.gradle | 15 +- app/proguard-rules.pro | 3 + .../fdroid/MainActivityEspressoTest.java | 169 ++++++++++++++++++ config/checkstyle/checkstyle.xml | 2 +- 4 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java diff --git a/app/build.gradle b/app/build.gradle index 6cea670ce..4ad92e551 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,7 +27,15 @@ android { defaultConfig { versionCode 1003051 versionName getVersionName() + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + /* + The Android Testing Support Library collects analytics to continuously improve the testing + experience. More specifically, it uploads a hash of the package name of the application + under test for each invocation. If you do not wish to upload this data, you can opt-out by + passing the following argument to the test runner: disableAnalytics "true". + */ + testInstrumentationRunnerArguments disableAnalytics: 'true' } buildTypes { @@ -165,9 +173,10 @@ dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.7.22' - androidTestImplementation 'com.android.support:support-annotations:25.3.1' - androidTestImplementation 'com.android.support.test:runner:0.5' - androidTestImplementation 'com.android.support.test:rules:0.5' + androidTestImplementation 'com.android.support:support-annotations:27.1.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' } tasks.whenTaskAdded { task -> diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index af1d1faec..4e8e47767 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -13,6 +13,9 @@ -dontnote android.support.** -dontnote **ILicensingService +# Needed for espresso https://stackoverflow.com/a/21706087 +-dontwarn org.xmlpull.v1.** + # StrongHttpsClient and its support classes are totally unused, so the # ch.boye.httpclientandroidlib.** classes are also unneeded -dontwarn info.guardianproject.netcipher.client.** diff --git a/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java new file mode 100644 index 000000000..53e12895f --- /dev/null +++ b/app/src/androidTest/java/org/fdroid/fdroid/MainActivityEspressoTest.java @@ -0,0 +1,169 @@ +package org.fdroid.fdroid; + +import android.support.test.espresso.IdlingPolicies; +import android.support.test.espresso.ViewInteraction; +import android.support.test.filters.LargeTest; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.util.Log; +import android.view.View; +import org.fdroid.fdroid.views.BannerUpdatingRepos; +import org.fdroid.fdroid.views.main.MainActivity; +import org.hamcrest.Matchers; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.TimeUnit; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.swipeDown; +import static android.support.test.espresso.action.ViewActions.swipeLeft; +import static android.support.test.espresso.action.ViewActions.swipeRight; +import static android.support.test.espresso.action.ViewActions.swipeUp; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertTrue; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class MainActivityEspressoTest { + public static final String TAG = "MainActivityEspressoTest"; + + static { + IdlingPolicies.setIdlingResourceTimeout(10, TimeUnit.MINUTES); + } + + @Rule + public ActivityTestRule activityTestRule = + new ActivityTestRule<>(MainActivity.class); + + @Test + public void bottomNavFlavorCheck() { + onView(withText(R.string.updates)).check(matches(isDisplayed())); + onView(withText(R.string.menu_settings)).check(matches(isDisplayed())); + onView(withText("THIS SHOULD NOT SHOW UP ANYWHERE!!!")).check(doesNotExist()); + + assertTrue(BuildConfig.FLAVOR.startsWith("full") || BuildConfig.FLAVOR.startsWith("basic")); + + if (BuildConfig.FLAVOR.startsWith("basic")) { + onView(withText(R.string.main_menu__latest_apps)).check(matches(isDisplayed())); + onView(withText(R.string.main_menu__categories)).check(doesNotExist()); + onView(withText(R.string.main_menu__swap_nearby)).check(doesNotExist()); + } + + if (BuildConfig.FLAVOR.startsWith("full")) { + onView(withText(R.string.main_menu__latest_apps)).check(matches(isDisplayed())); + onView(withText(R.string.main_menu__categories)).check(matches(isDisplayed())); + onView(withText(R.string.main_menu__swap_nearby)).check(matches(isDisplayed())); + } + } + + @Test + public void showSettings() { + ViewInteraction settingsBottonNavButton = onView( + allOf(withText(R.string.menu_settings), isDisplayed())); + settingsBottonNavButton.perform(click()); + onView(withText(R.string.preference_manage_installed_apps)).check(matches(isDisplayed())); + if (BuildConfig.FLAVOR.startsWith("basic") && BuildConfig.APPLICATION_ID.endsWith(".debug")) { + // TODO fix me by sorting out the flavor applicationId for debug builds in app/build.gradle + Log.i(TAG, "Skipping the remainder of showSettings test because it just crashes on basic .debug builds"); + return; + } + ViewInteraction manageInstalledAppsButton = onView( + allOf(withText(R.string.preference_manage_installed_apps), isDisplayed())); + manageInstalledAppsButton.perform(click()); + onView(withText(R.string.installed_apps__activity_title)).check(matches(isDisplayed())); + } + + @Test + public void showUpdates() { + ViewInteraction updatesBottonNavButton = onView(allOf(withText(R.string.updates), isDisplayed())); + updatesBottonNavButton.perform(click()); + onView(withText(R.string.updates)).check(matches(isDisplayed())); + } + + @Test + public void startSwap() { + if (!BuildConfig.FLAVOR.startsWith("full")) { + return; + } + ViewInteraction nearbyBottonNavButton = onView( + allOf(withText(R.string.main_menu__swap_nearby), isDisplayed())); + nearbyBottonNavButton.perform(click()); + ViewInteraction findPeopleButton = onView( + allOf(withId(R.id.button), withText(R.string.nearby_splash__find_people_button), isDisplayed())); + findPeopleButton.perform(click()); + onView(withText(R.string.swap_send_fdroid)).check(matches(isDisplayed())); + } + + @Test + public void showCategories() { + if (!BuildConfig.FLAVOR.startsWith("full")) { + return; + } + onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click()); + onView(allOf(withText(R.string.main_menu__categories), isDisplayed())).perform(click()); + onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed())) + .perform(swipeDown()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeDown()) + .perform(swipeDown()) + .perform(swipeRight()) + .perform(swipeLeft()) + .perform(swipeLeft()) + .perform(swipeLeft()) + .perform(swipeLeft()) + .perform(click()); + } + + @Test + public void showLatest() throws InterruptedException { + if (!BuildConfig.FLAVOR.startsWith("full")) { + return; + } + onView(Matchers.instanceOf(BannerUpdatingRepos.class)).check(matches(not(isDisplayed()))); + onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click()); + onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click()); + onView(allOf(withId(R.id.swipe_to_refresh), isDisplayed())) + .perform(swipeDown()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeUp()) + .perform(swipeDown()) + .perform(swipeUp()) + .perform(swipeDown()) + .perform(swipeDown()) + .perform(swipeDown()) + .perform(swipeDown()) + .perform(click()); + } + + @Test + public void showSearch() { + onView(allOf(withText(R.string.menu_settings), isDisplayed())).perform(click()); + onView(withId(R.id.fab_search)).check(doesNotExist()); + if (!BuildConfig.FLAVOR.startsWith("full")) { + return; + } + onView(allOf(withText(R.string.main_menu__latest_apps), isDisplayed())).perform(click()); + onView(allOf(withId(R.id.fab_search), isDisplayed())).perform(click()); + onView(withId(R.id.sort)).check(matches(isDisplayed())); + onView(allOf(withId(R.id.search), isDisplayed())) + .perform(click()) + .perform(typeText("test")); + onView(allOf(withId(R.id.sort), isDisplayed())).perform(click()); + } +} \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 27d6f2408..d14e701a3 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -40,7 +40,7 @@ + value="org.fdroid.fdroid.Assert.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.core.IsNot.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, android.support.test.espresso.Espresso.*, android.support.test.espresso.assertion.ViewAssertions.*, android.support.test.espresso.matcher.ViewMatchers.*, android.support.test.espresso.action.ViewActions.*" />