Commit 12dff6de authored by d4vidi's avatar d4vidi

Add java-code tests

parent 35a89f7e
......@@ -16,13 +16,18 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests.returnDefaultValues = true
}
}
dependencies {
// Google's GCM.
compile "com.google.android.gms:play-services-gcm:9.4.0"
compile 'com.google.android.gms:play-services-gcm:9.4.0'
compile 'com.facebook.react:react-native:+'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.+'
}
......@@ -10,7 +10,7 @@ public class AppLaunchHelper {
private static final String LAUNCH_FLAG_KEY_NAME = "launchedFromNotification";
public static Intent getLaunchIntent(Context appContext) {
public Intent getLaunchIntent(Context appContext) {
try {
// The desired behavior upon notification opening is as follows:
// - If app is in foreground (and possibly has several activities in stack), simply keep it as-is in foreground.
......@@ -32,14 +32,14 @@ public class AppLaunchHelper {
}
}
public static boolean isLaunchIntentsActivity(Activity activity) {
public boolean isLaunchIntentsActivity(Activity activity) {
final Intent helperIntent = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName());
final String activityName = activity.getComponentName().getClassName();
final String launchIntentActivityName = helperIntent.getComponent().getClassName();
return activityName.equals(launchIntentActivityName);
}
public static boolean isLaunchIntent(Intent intent) {
public boolean isLaunchIntent(Intent intent) {
return intent.getBooleanExtra(LAUNCH_FLAG_KEY_NAME, false);
}
}
......@@ -7,6 +7,8 @@ import android.util.Log;
import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.wix.reactnativenotifications.core.notification.PushNotification;
import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
public class ProxyService extends IntentService {
......@@ -24,5 +26,8 @@ public class ProxyService extends IntentService {
if (pushNotification != null) {
pushNotification.onOpened();
}
final IPushNotificationsDrawer pushNotificationDrawer = PushNotificationsDrawer.get(this);
pushNotificationDrawer.onNotificationOpened();
}
}
package com.wix.reactnativenotifications.core;
import android.content.Context;
import android.os.Bundle;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class ReactContextAdapter {
public ReactContext getRunningReactContext(Context context) {
final ReactNativeHost rnHost = ((ReactApplication) context.getApplicationContext()).getReactNativeHost();
if (!rnHost.hasInstance()) {
return null;
}
final ReactInstanceManager instanceManager = rnHost.getReactInstanceManager();
final ReactContext reactContext = instanceManager.getCurrentReactContext();
if (reactContext == null || !reactContext.hasActiveCatalystInstance()) {
return null;
}
return reactContext;
}
public void sendEventToJS(String eventName, Bundle data, Context context) {
final ReactContext reactContext = getRunningReactContext(context);
if (reactContext != null) {
sendEventToJS(eventName, data, reactContext);
}
}
public void sendEventToJS(String eventName, WritableMap data, Context context) {
final ReactContext reactContext = getRunningReactContext(context);
if (reactContext != null) {
sendEventToJS(eventName, data, reactContext);
}
}
public void sendEventToJS(String eventName, Bundle data, ReactContext reactContext) {
sendEventToJS(eventName, Arguments.fromBundle(data), reactContext);
}
public void sendEventToJS(String eventName, WritableMap data, ReactContext reactContext) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, data);
}
}
......@@ -3,8 +3,9 @@ package com.wix.reactnativenotifications.core.notification;
import android.content.Context;
import android.os.Bundle;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
public interface INotificationsApplication {
IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade facade);
IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade defaultFacade, AppLaunchHelper defaultAppLaunchHelper);
}
......@@ -20,7 +20,7 @@ import com.wix.reactnativenotifications.core.AppLifecycleFacade.AppVisibilityLis
import com.wix.reactnativenotifications.core.InitialNotification;
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
import com.wix.reactnativenotifications.core.ProxyService;
import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
import com.wix.reactnativenotifications.core.ReactContextAdapter;
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME;
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
......@@ -29,6 +29,8 @@ public class PushNotification implements IPushNotification {
final protected Context mContext;
final protected AppLifecycleFacade mAppLifecycleFacade;
final protected AppLaunchHelper mAppLaunchHelper;
final protected ReactContextAdapter mReactContextAdapter;
final protected PushNotificationProps mNotificationProps;
final protected AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() {
@Override
......@@ -42,18 +44,24 @@ public class PushNotification implements IPushNotification {
}
};
protected PushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade) {
mContext = context;
mAppLifecycleFacade = appLifecycleFacade;
mNotificationProps = createProps(bundle);
public static IPushNotification get(Context context, Bundle bundle, AppLifecycleFacade facade) {
return PushNotification.get(context, bundle, facade, new AppLaunchHelper());
}
public static IPushNotification get(Context context, Bundle bundle, AppLifecycleFacade facade) {
public static IPushNotification get(Context context, Bundle bundle, AppLifecycleFacade facade, AppLaunchHelper appLaunchHelper) {
Context appContext = context.getApplicationContext();
if (appContext instanceof INotificationsApplication) {
return ((INotificationsApplication) appContext).getPushNotification(context, bundle, facade);
return ((INotificationsApplication) appContext).getPushNotification(context, bundle, facade, appLaunchHelper);
}
return new PushNotification(context, bundle, facade);
return new PushNotification(context, bundle, facade, appLaunchHelper, new ReactContextAdapter());
}
protected PushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, ReactContextAdapter reactContextAdapter) {
mContext = context;
mAppLifecycleFacade = appLifecycleFacade;
mAppLaunchHelper = appLaunchHelper;
mReactContextAdapter = reactContextAdapter;
mNotificationProps = createProps(bundle);
}
@Override
......@@ -65,7 +73,6 @@ public class PushNotification implements IPushNotification {
@Override
public void onOpened() {
digestNotification();
PushNotificationsDrawer.get(mContext).onNotificationOpened();
}
@Override
......@@ -91,7 +98,7 @@ public class PushNotification implements IPushNotification {
return;
}
final ReactContext reactContext = getRunningReactContext();
final ReactContext reactContext = mReactContextAdapter.getRunningReactContext(mContext);
if (reactContext.getCurrentActivity() == null) {
setAsInitialNotification();
}
......@@ -161,46 +168,16 @@ public class PushNotification implements IPushNotification {
return (int) System.currentTimeMillis();
}
protected ReactContext getRunningReactContext() {
final ReactNativeHost rnHost = ((ReactApplication) mContext.getApplicationContext()).getReactNativeHost();
if (!rnHost.hasInstance()) {
return null;
}
final ReactInstanceManager instanceManager = rnHost.getReactInstanceManager();
final ReactContext reactContext = instanceManager.getCurrentReactContext();
if (reactContext == null || !reactContext.hasActiveCatalystInstance()) {
return null;
}
return reactContext;
}
private void notifyReceivedToJS() {
notifyJS(NOTIFICATION_RECEIVED_EVENT_NAME, null);
mReactContextAdapter.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mContext);
}
private void notifyOpenedToJS() {
notifyOpenedToJS(null);
}
private void notifyOpenedToJS(ReactContext reactContext) {
notifyJS(NOTIFICATION_OPENED_EVENT_NAME, reactContext);
}
private void notifyJS(String eventName, ReactContext reactContext) {
if (reactContext == null) {
reactContext = getRunningReactContext();
}
if (reactContext != null) {
final WritableMap notificationAsMap = Arguments.fromBundle(mNotificationProps.asBundle());
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, notificationAsMap);
}
mReactContextAdapter.sendEventToJS(NOTIFICATION_OPENED_EVENT_NAME, mNotificationProps.asBundle(), mContext);
}
protected void launchOrResumeApp() {
final Intent intent = AppLaunchHelper.getLaunchIntent(mContext);
final Intent intent = mAppLaunchHelper.getLaunchIntent(mContext);
mContext.startActivity(intent);
}
}
......@@ -10,18 +10,24 @@ import com.wix.reactnativenotifications.core.InitialNotification;
public class PushNotificationsDrawer implements IPushNotificationsDrawer {
final protected Context mContext;
final protected AppLaunchHelper mAppLaunchHelper;
public PushNotificationsDrawer(Context context) {
mContext = context;
public static IPushNotificationsDrawer get(Context context) {
return PushNotificationsDrawer.get(context, new AppLaunchHelper());
}
public static IPushNotificationsDrawer get(Context context) {
public static IPushNotificationsDrawer get(Context context, AppLaunchHelper appLaunchHelper) {
final Context appContext = context.getApplicationContext();
if (appContext instanceof INotificationsDrawerApplication) {
return ((INotificationsDrawerApplication) appContext).getPushNotificationsDrawer(context);
}
return new PushNotificationsDrawer(context);
return new PushNotificationsDrawer(context, appLaunchHelper);
}
protected PushNotificationsDrawer(Context context, AppLaunchHelper appLaunchHelper) {
mContext = context;
mAppLaunchHelper = appLaunchHelper;
}
@Override
......@@ -36,8 +42,8 @@ public class PushNotificationsDrawer implements IPushNotificationsDrawer {
@Override
public void onNewActivity(Activity activity) {
if (AppLaunchHelper.isLaunchIntentsActivity(activity) &&
!AppLaunchHelper.isLaunchIntent(activity.getIntent())) {
if (mAppLaunchHelper.isLaunchIntentsActivity(activity) &&
!mAppLaunchHelper.isLaunchIntent(activity.getIntent())) {
InitialNotification.clear();
}
}
......
package com.wix.reactnativenotifications.core.notification;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.bridge.ReactContext;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.AppLifecycleFacade.AppVisibilityListener;
import com.wix.reactnativenotifications.core.ReactContextAdapter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
public class PushNotificationTest {
@Mock private ReactContext mReactContext;
@Mock private Context mContext;
@Mock private Bundle mDefaultBundle;
@Mock private Intent mLaunchIntent;
@Mock private AppLifecycleFacade mAppLifecycleFacade;
@Mock private AppLaunchHelper mAppLaunchHelper;
@Mock private ReactContextAdapter mReactContextAdapter;
@Before
public void setup() throws Exception {
when(mDefaultBundle.getString(eq("title"))).thenReturn("Notification-title");
when(mDefaultBundle.getString(eq("body"))).thenReturn("Notification-body");
when(mDefaultBundle.clone()).thenReturn(mDefaultBundle);
when(mAppLaunchHelper.getLaunchIntent(eq(mContext))).thenReturn(mLaunchIntent);
when(mReactContextAdapter.getRunningReactContext(mContext)).thenReturn(mReactContext);
}
@Test
public void onOpened_noReactContext_launchApp() throws Exception {
when(mAppLifecycleFacade.isReactInitialized()).thenReturn(false);
final PushNotification uut = createUUT();
uut.onOpened();
verify(mContext).startActivity(eq(mLaunchIntent));
}
@Test
public void onOpened_appInvisible_resumeAppWaitForVisibility() throws Exception {
when(mAppLifecycleFacade.isReactInitialized()).thenReturn(true);
when(mAppLifecycleFacade.isAppVisible()).thenReturn(false);
final PushNotification uut = createUUT();
uut.onOpened();
verify(mContext).startActivity(any(Intent.class));
verify(mAppLifecycleFacade).addVisibilityListener(any(AppVisibilityListener.class));
}
@Test
public void onOpened_appGoesVisible_resumeAppAndNotifyJs() throws Exception {
// Arrange
when(mAppLifecycleFacade.isReactInitialized()).thenReturn(true);
when(mAppLifecycleFacade.isAppVisible()).thenReturn(false);
// Act
final PushNotification uut = createUUT();
uut.onOpened();
// Hijack and invoke visibility listener
ArgumentCaptor<AppVisibilityListener> listenerCaptor = ArgumentCaptor.forClass(AppVisibilityListener.class);
verify(mAppLifecycleFacade).addVisibilityListener(listenerCaptor.capture());
AppVisibilityListener listener = listenerCaptor.getValue();
listener.onAppVisible();
// Assert
verify(mReactContextAdapter).sendEventToJS(eq("notificationOpened"), eq(mDefaultBundle), eq(mContext));
}
@Test
public void onOpened_appVisible_notifyJS() throws Exception {
when(mAppLifecycleFacade.isReactInitialized()).thenReturn(true);
when(mAppLifecycleFacade.isAppVisible()).thenReturn(true);
final PushNotification uut = createUUT();
uut.onOpened();
verify(mContext, never()).startActivity(any(Intent.class));
verify(mReactContextAdapter).sendEventToJS(eq("notificationOpened"), eq(mDefaultBundle), eq(mContext));
}
protected PushNotification createUUT() {
return new PushNotification(mContext, mDefaultBundle, mAppLifecycleFacade, mAppLaunchHelper, mReactContextAdapter);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment