Bug/androidtests (#466)

* Fixed issue with selecting tabs

* Fixed issue with switching host on other thread than UI thread

* Fixed concurrent modification exception in JSONConnectionHandlerManager

* Fixed issue with drawer not closing

* Fixes issue with running method only supported on API 21 and higher
This commit is contained in:
Martijn Brekhof 2017-10-10 12:06:10 +02:00 committed by Synced Synapse
parent 108fb88b9f
commit 9e65350b5a
8 changed files with 111 additions and 72 deletions

View File

@ -207,36 +207,54 @@ public class EspressoTestUtils {
return activity[0];
}
/**
* Clicks on tab that contains the text given by stringResourceId.
* If the click fails tries again after a swipe left. If the click fails
* after that try once more after swiping right two times. The first swipe right
* is performed to negate the previous swipe left.
* @param stringResourceId text displayed in Tab that should be clicked
*/
public static void clickTab(int stringResourceId) {
try {
onView(withText(stringResourceId)).perform(click());
} catch (Exception e1) {
try {
onView(withId(R.id.pager_tab_strip)).perform(swipeLeft());
onView(withText(stringResourceId)).perform(click());
} catch (Exception e2) {
onView(withId(R.id.pager_tab_strip)).perform(swipeRight());
onView(withId(R.id.pager_tab_strip)).perform(swipeRight());
onView(withText(stringResourceId)).perform(click());
}
}
}
/**
* Clicks the album tab in the music activity
*/
public static void clickAlbumsTab() {
onView(withId(R.id.pager_tab_strip)).perform(swipeLeft());
onView(withText(R.string.albums)).perform(click());
clickTab(R.string.albums);
}
/**
* Clicks the artists tab in the music activity
*/
public static void clickArtistsTab() {
onView(withId(R.id.pager_tab_strip)).perform(swipeRight());
onView(withText(R.string.artists)).perform(click());
clickTab(R.string.artists);
}
/**
* Clicks the genres tab in the music activity
*/
public static void clickGenresTab() {
onView(withId(R.id.pager_tab_strip)).perform(swipeLeft());
onView(withText(R.string.genres)).perform(click());
clickTab(R.string.genres);
}
/**
* Clicks the music videos tab in the music activity
*/
public static void clickMusicVideosTab() {
onView(withId(R.id.pager_tab_strip)).perform(swipeLeft());
onView(withText(R.string.videos)).perform(click());
clickTab(R.string.videos);
}
/**

View File

@ -16,26 +16,27 @@
package org.xbmc.kore.testhelpers;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.support.test.rule.ActivityTestRule;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import org.junit.internal.runners.statements.RunAfters;
import org.xbmc.kore.R;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.host.HostManager;
import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.testutils.Database;
import org.xbmc.kore.utils.LogUtils;
import java.lang.reflect.Method;
import static org.xbmc.kore.ui.generic.NavigationDrawerFragment.PREF_USER_LEARNED_DRAWER;
public class Utils {
private static final String TAG = LogUtils.makeLogTag(Utils.class);
@ -43,16 +44,11 @@ public class Utils {
private static final float DISABLED = 0.0f;
private static final float DEFAULT = 1.0f;
private static boolean isInitialized;
private static HostInfo hostInfo;
private static Context context;
public static void closeDrawer(final ActivityTestRule<?> activityTestRule) throws Throwable {
activityTestRule.runOnUiThread(new Runnable() {
public static void closeDrawer(final Activity activity) throws Throwable {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
DrawerLayout drawerLayout = (DrawerLayout) activityTestRule.getActivity().findViewById(R.id.drawer_layout);
DrawerLayout drawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
drawerLayout.closeDrawers();
}
});
@ -73,43 +69,43 @@ public class Utils {
}
}
public static void initialize(ActivityTestRule<?> activityTestRule, HostInfo info) throws Throwable {
if (isInitialized)
return;
public static void switchHost(final Context context, Activity activity, final HostInfo hostInfo) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
HostManager.getInstance(context).switchHost(hostInfo);
}
});
}
hostInfo = info;
context = activityTestRule.getActivity();
public static void clearSharedPreferences(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.commit();
}
disableAnimations();
public static void setLearnedAboutDrawerPreference(Context context, boolean learned) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(PREF_USER_LEARNED_DRAWER, true);
editor.commit();
}
public static void setupMediaProvider(Context context) {
MediaProvider mediaProvider = new MediaProvider();
mediaProvider.setContext(context);
mediaProvider.onCreate();
Database.fill(hostInfo, context, context.getContentResolver());
HostManager.getInstance(context).switchHost(hostInfo);
Utils.closeDrawer(activityTestRule);
isInitialized = true;
}
public static void cleanup() {
Database.flush(context.getContentResolver(), hostInfo);
enableAnimations();
isInitialized = false;
}
private static void disableAnimations() {
public static void disableAnimations(Context context) {
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
if (permStatus == PackageManager.PERMISSION_GRANTED) {
setSystemAnimationsScale(DISABLED);
}
}
private static void enableAnimations() {
public static void enableAnimations(Context context) {
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
if (permStatus == PackageManager.PERMISSION_GRANTED) {
setSystemAnimationsScale(DEFAULT);

View File

@ -16,8 +16,10 @@
package org.xbmc.kore.tests.ui;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@ -31,7 +33,9 @@ import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.host.HostManager;
import org.xbmc.kore.jsonrpc.HostConnection;
import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.testhelpers.LoaderIdlingResource;
import org.xbmc.kore.testhelpers.Utils;
import org.xbmc.kore.testutils.Database;
@ -58,6 +62,8 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
private static PlayerHandler playerHandler;
private static ApplicationHandler applicationHandler;
private HostInfo hostInfo;
@BeforeClass
public static void setupMockTCPServer() throws Throwable {
playerHandler = new PlayerHandler();
@ -75,31 +81,38 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
activityTestRule = getActivityTestRule();
// final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
final Context context = activityTestRule.getActivity();
//Note: as the activity is not yet available in @BeforeClass we need
// to add the handler here
if (addonsHandler == null) {
addonsHandler = new AddonsHandler(activityTestRule.getActivity());
addonsHandler = new AddonsHandler(context);
manager.addHandler(addonsHandler);
}
HostInfo hostInfo = Database.addHost(activityTestRule.getActivity(), server.getHostName(),
HostConnection.PROTOCOL_TCP, HostInfo.DEFAULT_HTTP_PORT,
server.getPort());
hostInfo = Database.addHost(context, server.getHostName(),
HostConnection.PROTOCOL_TCP, HostInfo.DEFAULT_HTTP_PORT,
server.getPort());
Utils.initialize(activityTestRule, hostInfo);
Utils.clearSharedPreferences(context);
//Prevent drawer from opening when we start a new activity
Utils.setLearnedAboutDrawerPreference(context, true);
loaderIdlingResource = new LoaderIdlingResource(activityTestRule.getActivity().getSupportLoaderManager());
Espresso.registerIdlingResources(loaderIdlingResource);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activityTestRule.getActivity());
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.commit();
Utils.disableAnimations(context);
//Relaunch the activity for the changes (Host selections, preference reset) to take effect
Utils.setupMediaProvider(context);
Database.fill(hostInfo, context, context.getContentResolver());
Utils.switchHost(context, activityTestRule.getActivity(), hostInfo);
//Relaunch the activity for the changes (Host selection and database fill) to take effect
activityTestRule.launchActivity(new Intent());
Utils.closeDrawer(activityTestRule);
}
@After
@ -110,7 +123,9 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
applicationHandler.reset();
playerHandler.reset();
Utils.cleanup();
Context context = activityTestRule.getActivity();
Database.flush(context.getContentResolver(), hostInfo);
Utils.enableAnimations(context);
}
@AfterClass

View File

@ -16,6 +16,8 @@
package org.xbmc.kore.tests.ui.addons;
import android.content.Intent;
import android.os.SystemClock;
import android.support.test.rule.ActivityTestRule;
import android.widget.TextView;
@ -27,6 +29,7 @@ import org.xbmc.kore.testhelpers.EspressoTestUtils;
import org.xbmc.kore.testhelpers.Utils;
import org.xbmc.kore.tests.ui.AbstractTestClass;
import org.xbmc.kore.tests.ui.BaseMediaActivityTests;
import org.xbmc.kore.ui.sections.addon.AddonsActivity;
import org.xbmc.kore.ui.sections.video.MoviesActivity;
import static android.support.test.espresso.Espresso.onView;
@ -71,9 +74,9 @@ public class AddonsActivityTests extends BaseMediaActivityTests<MoviesActivity>
@Override
public void setUp() throws Throwable {
super.setUp();
//Start the AddonsActivity from the MoviesActivity
Utils.openDrawer(getActivityTestRule());
EspressoTestUtils.clickAdapterViewItem(7, R.id.navigation_drawer);
Intent intent = new Intent(getActivity(), AddonsActivity.class);
getActivity().startActivity(intent);
}
/**

View File

@ -16,6 +16,7 @@
package org.xbmc.kore.tests.ui.movies;
import android.os.SystemClock;
import android.support.test.rule.ActivityTestRule;
import android.widget.TextView;
@ -80,7 +81,7 @@ public class MoviesActivityTests extends BaseMediaActivityTests<MoviesActivity>
public void restoreActionBarTitleOnConfigurationStateChanged() {
EspressoTestUtils.selectListItemRotateDeviceAndCheckActionbarTitle(0, R.id.list,
"#Rookie93 Marc Marquez: Beyond the Smile",
mActivityRule.getActivity());
getActivity());
}
/**
@ -94,6 +95,6 @@ public class MoviesActivityTests extends BaseMediaActivityTests<MoviesActivity>
@Test
public void restoreActionBarTitleOnReturningFromMovie() {
selectListItemPressBackAndCheckActionbarTitle(0, R.id.list,
mActivityRule.getActivity().getString(R.string.movies));
getActivity().getString(R.string.movies));
}
}

View File

@ -74,7 +74,7 @@ public class NavigationDrawerFragment extends Fragment {
* Per the design guidelines, you should show the drawer on launch until the user manually
* expands it. This shared preference tracks this.
*/
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
public static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
public static final int ACTIVITY_HOSTS = 0,
ACTIVITY_REMOTE = 1,

View File

@ -27,6 +27,7 @@ import org.xbmc.kore.ui.AbstractFragment;
import org.xbmc.kore.ui.BaseMediaActivity;
import org.xbmc.kore.ui.sections.remote.RemoteActivity;
import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.Utils;
/**
* Controls the presentation of Addons information (list, details)
@ -127,8 +128,9 @@ public class AddonsActivity extends BaseMediaActivity
;
addonDetailsFragment.setDataHolder(vh.dataHolder);
vh.dataHolder.setSquarePoster(true);
vh.dataHolder.setPosterTransitionName(vh.artView.getTransitionName());
if(Utils.isLollipopOrLater()) {
vh.dataHolder.setPosterTransitionName(vh.artView.getTransitionName());
}
showFragment(addonDetailsFragment, vh.artView, vh.dataHolder);
updateActionBar(getActionBarTitle(), true);

View File

@ -120,15 +120,17 @@ public class JSONConnectionHandlerManager implements MockTcpServer.TcpServerConn
@Override
public String getResponse() {
StringBuffer stringBuffer = new StringBuffer();
//Handle responses
Collection<ArrayList<JsonResponse>> jsonResponses = clientResponses.values();
for(ArrayList<JsonResponse> arrayList : jsonResponses) {
for (JsonResponse response : arrayList) {
stringBuffer.append(response.toJsonString() + "\n");
synchronized (clientResponses) {
//Handle responses
Collection<ArrayList<JsonResponse>> jsonResponses = clientResponses.values();
for (ArrayList<JsonResponse> arrayList : jsonResponses) {
for (JsonResponse response : arrayList) {
stringBuffer.append(response.toJsonString() + "\n");
}
}
clientResponses.clear();
}
clientResponses.clear();
//Handle notifications
for(ConnectionHandler handler : handlers) {
@ -168,7 +170,9 @@ public class JSONConnectionHandlerManager implements MockTcpServer.TcpServerConn
ArrayList<JsonResponse> responses = clientResponses.get(String.valueOf(id));
if (responses == null) {
responses = new ArrayList<>();
clientResponses.put(String.valueOf(id), responses);
synchronized (clientResponses) {
clientResponses.put(String.valueOf(id), responses);
}
}
responses.addAll(jsonResponses);
}