Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UI tests with DirectionsRoute test fixture #1548

Merged
merged 1 commit into from
Nov 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import android.content.res.Configuration;
import android.support.test.espresso.ViewAction;

import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.services.android.navigation.testapp.R;
import com.mapbox.services.android.navigation.testapp.test.TestNavigationActivity;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;

import org.junit.Test;
Expand All @@ -19,6 +21,7 @@
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static junit.framework.Assert.assertFalse;
import static testapp.action.NavigationViewAction.invoke;
import static testapp.action.OrientationChangeAction.orientationLandscape;
import static testapp.action.OrientationChangeAction.orientationPortrait;

Expand All @@ -36,6 +39,15 @@ public void onOrientationLandscape_navigationContinuesRunning() {
}
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});

changeOrientation(orientationLandscape());
}

Expand All @@ -46,6 +58,15 @@ public void onOrientationPortrait_navigationContinuesRunning() {
}
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});

changeOrientation(orientationPortrait());
}

Expand All @@ -56,6 +77,15 @@ public void onOrientationChange_recenterBtnStateIsRestore() {
}
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});

onView(withId(R.id.routeOverviewBtn)).perform(click());
changeOrientation(orientationLandscape());
onView(withId(R.id.recenterBtn)).check(matches(isDisplayed()));
Expand All @@ -68,6 +98,15 @@ public void onOrientationChange_cameraTrackingIsRestore() {
}
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});

onView(withId(R.id.navigationMapView)).perform(swipeUp());
changeOrientation(orientationLandscape());

Expand All @@ -83,6 +122,15 @@ public void onOrientationChange_waynameVisibilityIsRestored() {
}
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});

onView(withId(R.id.navigationMapView)).perform(swipeUp());
changeOrientation(orientationLandscape());

Expand Down
19 changes: 19 additions & 0 deletions app/src/androidTest/java/testapp/NavigationViewTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package testapp;

import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.services.android.navigation.testapp.test.TestNavigationActivity;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.map.NavigationMapboxMap;
import com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation;

Expand All @@ -9,6 +11,7 @@
import testapp.activity.BaseNavigationActivityTest;

import static junit.framework.Assert.assertNotNull;
import static testapp.action.NavigationViewAction.invoke;

public class NavigationViewTest extends BaseNavigationActivityTest {

Expand All @@ -21,6 +24,14 @@ protected Class getActivityClass() {
public void onInitialization_navigationMapboxMapIsNotNull() {
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});
NavigationMapboxMap navigationMapboxMap = getNavigationView().retrieveNavigationMapboxMap();

assertNotNull(navigationMapboxMap);
Expand All @@ -30,6 +41,14 @@ public void onInitialization_navigationMapboxMapIsNotNull() {
public void onNavigationStart_mapboxNavigationIsNotNull() {
validateTestSetup();

invoke(getNavigationView(), (uiController, navigationView) -> {
DirectionsRoute testRoute = DirectionsRoute.fromJson(loadJsonFromAsset("lancaster-1.json"));
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(testRoute)
.build();

navigationView.startNavigation(options);
});
MapboxNavigation mapboxNavigation = getNavigationView().retrieveMapboxNavigation();

assertNotNull(mapboxNavigation);
Expand Down
48 changes: 48 additions & 0 deletions app/src/androidTest/java/testapp/action/NavigationViewAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package testapp.action;

import android.support.annotation.NonNull;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;

import com.mapbox.services.android.navigation.ui.v5.NavigationView;

import org.hamcrest.Matcher;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;

public class NavigationViewAction implements ViewAction {

private OnInvokeActionListener invokeViewAction;
private NavigationView navigationView;

private NavigationViewAction(OnInvokeActionListener invokeViewAction, NavigationView navigationView) {
this.invokeViewAction = invokeViewAction;
this.navigationView = navigationView;
}

@Override
public Matcher<View> getConstraints() {
return isDisplayed();
}

@Override
public String getDescription() {
return getClass().getSimpleName();
}

@Override
public void perform(UiController uiController, View view) {
invokeViewAction.onInvokeAction(uiController, navigationView);
}

public static void invoke(NavigationView navigationView, OnInvokeActionListener invokeViewAction) {
onView(withId(android.R.id.content)).perform(new NavigationViewAction(invokeViewAction, navigationView));
}

public interface OnInvokeActionListener {
void onInvokeAction(@NonNull UiController uiController, @NonNull NavigationView navigationView);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.test.espresso.IdlingRegistry;
Expand All @@ -17,6 +18,9 @@
import org.junit.Before;
import org.junit.Rule;

import java.io.IOException;
import java.io.InputStream;

import testapp.utils.OnNavigationReadyIdlingResource;
import timber.log.Timber;

Expand All @@ -29,23 +33,32 @@ public abstract class BaseNavigationActivityTest {

@Rule
public ActivityTestRule<Activity> rule = new ActivityTestRule<>(getActivityClass());

private NavigationView navigationView;
private AssetManager assetManager;
private OnNavigationReadyIdlingResource idlingResource;

@Before
public void beforeTest() {
try {
idlingResource = new OnNavigationReadyIdlingResource(rule.getActivity());
Activity activity = rule.getActivity();
idlingResource = new OnNavigationReadyIdlingResource(activity);
IdlingRegistry.getInstance().register(idlingResource);
checkViewIsDisplayed(R.id.navigationView);
navigationView = idlingResource.getNavigationView();
assetManager = activity.getAssets();
} catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
Timber.e("Idling resource timed out. Could not validate if navigation is ready.");
throw new RuntimeException("Could not start test for " + getActivityClass().getSimpleName() + ".\n"
+ "The ViewHierarchy doesn't contain a view with resource id = R.id.navigationView");
}
}

@After
public void afterTest() {
IdlingRegistry.getInstance().unregister(idlingResource);
}

protected void validateTestSetup() {
Assert.assertTrue("Device is not connected to the Internet.", isConnected(rule.getActivity()));
checkViewIsDisplayed(R.id.navigationView);
Expand All @@ -57,6 +70,21 @@ protected NavigationView getNavigationView() {

protected abstract Class getActivityClass();

protected String loadJsonFromAsset(String filename) {
try {
InputStream is = assetManager.open(filename);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
return new String(buffer, "UTF-8");

} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}

private void checkViewIsDisplayed(int id) {
onView(withId(id)).check(matches(isDisplayed()));
}
Expand All @@ -67,9 +95,4 @@ private boolean isConnected(Context context) {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

@After
public void afterTest() {
IdlingRegistry.getInstance().unregister(idlingResource);
}
}
Original file line number Diff line number Diff line change
@@ -1,51 +1,26 @@
package testapp.utils;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.os.Handler;
import android.os.Looper;
import android.support.test.espresso.IdlingResource;

import com.google.gson.GsonBuilder;
import com.mapbox.api.directions.v5.DirectionsAdapterFactory;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.services.android.navigation.testapp.R;
import com.mapbox.services.android.navigation.ui.v5.NavigationView;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;

import java.lang.reflect.Field;
public class OnNavigationReadyIdlingResource implements IdlingResource, OnNavigationReadyCallback {

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class OnNavigationReadyIdlingResource implements IdlingResource, Callback<DirectionsResponse>,
OnNavigationReadyCallback {

private static final String NAVIGATION_VIEW = "navigationView";
private static final String TEST_ROUTE_JSON = "test_route_json";
private static final int FIRST_ROUTE = 0;
private boolean isNavigationReady;
private NavigationView navigationView;
private DirectionsRoute testRoute;
private ResourceCallback resourceCallback;
private SharedPreferences preferences;
private IdlingResource.ResourceCallback resourceCallback;
private boolean isNavigationReady;
private final Handler handler = new Handler(Looper.getMainLooper());

public OnNavigationReadyIdlingResource(Activity activity) {
try {
Field field = activity.getClass().getDeclaredField(NAVIGATION_VIEW);
field.setAccessible(true);
navigationView = (NavigationView) field.get(activity);
preferences = PreferenceManager.getDefaultSharedPreferences(activity);
fetchRoute(activity);
} catch (Exception err) {
throw new RuntimeException(err);
}
handler.post(() -> {
navigationView = activity.findViewById(R.id.navigationView);
navigationView.initialize(OnNavigationReadyIdlingResource.this);
});
}

@Override
Expand All @@ -67,53 +42,15 @@ public NavigationView getNavigationView() {
return navigationView;
}

@Override
public void onResponse(@NonNull Call<DirectionsResponse> call, @NonNull Response<DirectionsResponse> response) {
testRoute = response.body().routes().get(FIRST_ROUTE);
storeRouteForRotation(testRoute);
navigationView.initialize(this);
}

@Override
public void onFailure(@NonNull Call<DirectionsResponse> call, @NonNull Throwable throwable) {
throw new RuntimeException(throwable);
}

@Override
public void onNavigationReady(boolean isRunning) {
navigationView.startNavigation(buildTestNavigationViewOptions());
transitionToIdle();
}

private void fetchRoute(Context context) {
Point origin = Point.fromLngLat(-77.033987, 38.900123);
Point destination = Point.fromLngLat(-77.044818, 38.848942);
NavigationRoute.builder(context)
.accessToken(Mapbox.getAccessToken())
.origin(origin)
.destination(destination)
.build().getRoute(this);
}

private void storeRouteForRotation(DirectionsRoute route) {
SharedPreferences.Editor editor = preferences.edit();
String testRouteJson = new GsonBuilder()
.registerTypeAdapterFactory(DirectionsAdapterFactory.create()).create().toJson(route);
editor.putString(TEST_ROUTE_JSON, testRouteJson);
editor.apply();
}

private NavigationViewOptions buildTestNavigationViewOptions() {
return NavigationViewOptions.builder()
.directionsRoute(testRoute)
.shouldSimulateRoute(true)
.build();
}

private void transitionToIdle() {
isNavigationReady = true;
if (resourceCallback != null) {
resourceCallback.onTransitionToIdle();
}
}
}
}
Loading