package com.zedeff.twittererer.ui.activities; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SdkSuppress; import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.By; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiSelector; import android.support.test.uiautomator.Until; import com.zedeff.twittererer.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import static android.support.test.InstrumentationRegistry.getInstrumentation; import static org.hamcrest.core.IsNull.notNullValue; import static org.junit.Assert.assertThat; /** * These tests use UI Automator as the Twitter authentication mechanism cannot be tested with Espresso * * * Prerequisites: * * Make sure the test device has the official Twitter app installed * Register a Twitter test user so we can log in with that user * * Also works in an emulator with an ARM CPU (max API 23 for now, see below) * Install the Twitter app from: http://www.androiddrawer.com/25966/download-twitter-2-app-apk/ * Note: the above Twitter app apk (6.16.0) does not work with x86 CPU based emulator images * * Note: make sure all accessibility services are turned off (e.g.: LastPass) otherwise you get this * http://stackoverflow.com/questions/27132799/java-lang-securityexception-permission-denial-getintentsender-when-using-uia */ @RunWith(AndroidJUnit4.class) @SdkSuppress(minSdkVersion = 18) public class LoginActivityTest { private static final String APP_PACKAGE = "com.zedeff.twittererer"; private static final int TIMEOUT = 5000; private static final String LOGIN_BUTTON_TEXT = "Log in with Twitter"; private UiDevice device; @Before public void startMainActivityFromHomeScreen() { device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); // Start from the home screen device.pressHome(); // Wait for launcher final String launcherPackage = getLauncherPackageName(); assertThat(launcherPackage, notNullValue()); device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIMEOUT); // Launch the app Context context = InstrumentationRegistry.getContext(); final Intent intent = context.getPackageManager().getLaunchIntentForPackage(APP_PACKAGE); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances context.startActivity(intent); // Wait for the app to appear device.wait(Until.hasObject(By.pkg(APP_PACKAGE).depth(0)), TIMEOUT); } @Test public void loginSuccessful() throws UiObjectNotFoundException { UiObject loginButton = device.findObject(new UiSelector().text(LOGIN_BUTTON_TEXT)); loginButton.clickAndWaitForNewWindow(TIMEOUT); // TODO: this fails to find the text on API 24+ (Android 7+) for some reason UiObject allowButton = device.findObject(new UiSelector().text("Allow")); allowButton.clickAndWaitForNewWindow(TIMEOUT); UiObject activityTitle = device.findObject(new UiSelector() .text(getInstrumentation().getTargetContext().getString(R.string.title_activity_twitter_feed))); assertThat(activityTitle, notNullValue()); } @Test public void loginCancelled() throws UiObjectNotFoundException { UiObject loginButton = device.findObject(new UiSelector().text(LOGIN_BUTTON_TEXT)); loginButton.clickAndWaitForNewWindow(TIMEOUT); // TODO: this fails to find the text on API 24+ (Android 7+) for some reason UiObject allowButton = device.findObject(new UiSelector().text("Cancel")); allowButton.clickAndWaitForNewWindow(TIMEOUT); loginButton = device.findObject(new UiSelector().text(LOGIN_BUTTON_TEXT)); assertThat(loginButton, notNullValue()); } /** * Uses package manager to find the package name of the device launcher. Usually this package * is "com.android.launcher" but can be different at times. This is a generic solution which * works on all platforms.` */ private String getLauncherPackageName() { // Create launcher Intent final Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); // Use PackageManager to get the launcher package name PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); return resolveInfo.activityInfo.packageName; } }