From e0598a656c9e605fd4db6e5d121ade712e0808f2 Mon Sep 17 00:00:00 2001 From: Deepu Ganapathiyadan Date: Tue, 8 Sep 2020 15:46:20 +0530 Subject: [PATCH] Add tests --- android/lib/build.gradle | 12 +- .../lib/src/androidTest/AndroidManifest.xml | 9 + .../ern/api/impl/BasicNavigationApiTest.java | 409 ++++++++++++++++++ .../res/layout/activity_sample_main.xml | 9 + .../src/androidTest/res/values/strings.xml | 4 + .../api/impl/core/ElectrodeBaseFragment.java | 4 + 6 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 android/lib/src/androidTest/AndroidManifest.xml create mode 100644 android/lib/src/androidTest/java/com/ern/api/impl/BasicNavigationApiTest.java create mode 100644 android/lib/src/androidTest/res/layout/activity_sample_main.xml create mode 100644 android/lib/src/androidTest/res/values/strings.xml diff --git a/android/lib/build.gradle b/android/lib/build.gradle index 4711fa1e..e8ca96d6 100644 --- a/android/lib/build.gradle +++ b/android/lib/build.gradle @@ -16,6 +16,9 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + multiDexEnabled true + } } lintOptions { abortOnError false @@ -27,7 +30,10 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' api ('com.walmartlabs.ern:container-movies-reloaded:1.0.0') {changing=true} - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + androidTestImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + androidTestImplementation 'com.android.support:multidex:1.0.3' + androidTestImplementation 'androidx.test:core:1.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test:runner:1.3.0' + androidTestImplementation 'com.google.truth:truth:1.0.1' } diff --git a/android/lib/src/androidTest/AndroidManifest.xml b/android/lib/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000..5bb72390 --- /dev/null +++ b/android/lib/src/androidTest/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/android/lib/src/androidTest/java/com/ern/api/impl/BasicNavigationApiTest.java b/android/lib/src/androidTest/java/com/ern/api/impl/BasicNavigationApiTest.java new file mode 100644 index 00000000..0028386c --- /dev/null +++ b/android/lib/src/androidTest/java/com/ern/api/impl/BasicNavigationApiTest.java @@ -0,0 +1,409 @@ +package com.ern.api.impl; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ActivityScenario; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; + +import com.ern.api.impl.navigation.ElectrodeBaseActivity; +import com.ern.api.impl.navigation.MiniAppNavigationFragment; +import com.ernnavigationApi.ern.api.EnNavigationApi; +import com.ernnavigationApi.ern.model.ErnNavRoute; +import com.ernnavigationApi.ern.model.NavigationBar; +import com.walmartlabs.electrode.reactnative.bridge.ElectrodeBridgeResponseListener; +import com.walmartlabs.electrode.reactnative.bridge.FailureMessage; +import com.walmartlabs.electrode.reactnative.bridge.None; +import com.walmartlabs.electrode.reactnative.bridge.helpers.Logger; +import com.walmartlabs.ern.container.ElectrodeReactContainer; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Objects; +import java.util.concurrent.CountDownLatch; + +import static com.ern.api.impl.BasicNavigationApiTest.SampleActivity.ROOT_COMPONENT_NAME; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class BasicNavigationApiTest { + + private static final String TITLE_ROOT_PAGE = ApplicationProvider.getApplicationContext().getString(com.walmartlabs.ern.navigation.test.R.string.root_page_title); + private static final String TITLE_PAGE_1 = "page 1"; + private static final String COMPONENT_PAGE_1 = "Component1"; + + @Before + public void setUp() { + Logger.overrideLogLevel(Logger.LogLevel.VERBOSE); + } + + @Rule + public ActivityScenarioRule rule = new ActivityScenarioRule(SampleActivity.class); + + @Test + public void testRootComponentRendering() { + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_ROOT_PAGE); + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + MiniAppNavigationFragment miniAppFragment = (MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0); + assertThat(miniAppFragment.getReactComponentName()).isEqualTo(ROOT_COMPONENT_NAME); + } + }); + } + + @Test + public void testNavigate() { + final CountDownLatch latch = new CountDownLatch(1); + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + //Navigate to second page and ensure that the nav bar title is updated. + EnNavigationApi.requests().navigate(new ErnNavRoute.Builder(COMPONENT_PAGE_1).navigationBar(new NavigationBar.Builder(TITLE_PAGE_1).build()).build(), new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + latch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the navigation request to complete + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_PAGE_1); + //Since we performed a navigation there should be two fragments in the stack, 1. Root component and 2. Navigated component + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(2); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + assertThat(((MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0)).getReactComponentName()).isEqualTo(COMPONENT_PAGE_1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + } + }); + } + + @Test + public void testBackgroundNavigate() { + final CountDownLatch latch = new CountDownLatch(1); + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + + // Move to background + scenario.moveToState(Lifecycle.State.CREATED); + + // Navigate to second page and ensure that the nav bar title is updated. + EnNavigationApi.requests().navigate(new ErnNavRoute.Builder(COMPONENT_PAGE_1).navigationBar(new NavigationBar.Builder(TITLE_PAGE_1).build()).build(), new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + latch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the navigation request to complete + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + + //Ensure that the page is not navigated while backgrounded + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_ROOT_PAGE); + assertThat(activity.isBackgrounded).isTrue(); + } + }); + + scenario.moveToState(Lifecycle.State.RESUMED); + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.isForegrounded).isTrue(); + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_PAGE_1); + //Since we performed a navigation there should be two fragments in the stack, 1. Root component and 2. Navigated component + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(2); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + assertThat(((MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0)).getReactComponentName()).isEqualTo(COMPONENT_PAGE_1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + } + }); + } + + @Test + public void testUpdate() { + final String UPDATED_TITLE = "Page 0 - Updated"; + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_ROOT_PAGE); + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + MiniAppNavigationFragment miniAppFragment = (MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0); + assertThat(miniAppFragment.getReactComponentName()).isEqualTo(ROOT_COMPONENT_NAME); + } + }); + + final CountDownLatch latch = new CountDownLatch(1); + + EnNavigationApi.requests().update(new ErnNavRoute.Builder("blah").navigationBar(new NavigationBar.Builder(UPDATED_TITLE).build()).build(), new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + latch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the update request to complete + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(UPDATED_TITLE); + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + MiniAppNavigationFragment miniAppFragment = (MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0); + assertThat(miniAppFragment.getReactComponentName()).isEqualTo(ROOT_COMPONENT_NAME); + + //TODO: Validate Menu Items. + } + }); + } + + @Test + public void testBack() { + final CountDownLatch latch = new CountDownLatch(1); + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + + //Navigate to second page and ensure that the nav bar title is updated. + EnNavigationApi.requests().navigate(new ErnNavRoute.Builder(COMPONENT_PAGE_1).navigationBar(new NavigationBar.Builder(TITLE_PAGE_1).build()).build(), new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + latch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the navigation request to complete + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(TITLE_PAGE_1); + //Since we performed a navigation there should be two fragments in the stack, 1. Root component and 2. Navigated component + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(2); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + assertThat(((MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0)).getReactComponentName()).isEqualTo(COMPONENT_PAGE_1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + } + }); + + //Navigate back to FirstPage + final CountDownLatch backLatch = new CountDownLatch(1); + EnNavigationApi.requests().back(new ErnNavRoute.Builder(ROOT_COMPONENT_NAME).navigationBar(new NavigationBar.Builder(COMPONENT_PAGE_1).build()).build(), new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + backLatch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the back request to complete + try { + backLatch.await(); + } catch (InterruptedException e) { + fail(); + } + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.getSupportActionBar()).isNotNull(); + assertThat(activity.getSupportActionBar().getTitle()).isEqualTo(rootPageTitle()); + //Since we performed a navigation there should be two fragments in the stack, 1. Root component and 2. Navigated component + assertThat(activity.getSupportFragmentManager().getBackStackEntryCount()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().size()).isEqualTo(1); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + assertThat(((MiniAppNavigationFragment) activity.getSupportFragmentManager().getFragments().get(0)).getReactComponentName()).isEqualTo(ROOT_COMPONENT_NAME); + assertThat(activity.getSupportFragmentManager().getFragments().get(0)).isInstanceOf(MiniAppNavigationFragment.class); + } + }); + } + + @Test + public void testFinish() { + final CountDownLatch latch = new CountDownLatch(1); + Assert.assertNotNull(rule); + ActivityScenario scenario = rule.getScenario(); + Assert.assertNotNull(scenario); + EnNavigationApi.requests().finish(null, new ElectrodeBridgeResponseListener() { + @Override + public void onSuccess(@Nullable None responseData) { + latch.countDown(); + } + + @Override + public void onFailure(@NonNull FailureMessage failureMessage) { + fail(failureMessage.getMessage()); + } + }); + + //Wait for the finish request to complete + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + + scenario.onActivity(new ActivityScenario.ActivityAction() { + @Override + public void perform(SampleActivity activity) { + assertThat(activity.isFinishing()).isTrue(); + } + }); + } + + private String rootPageTitle() { + return ApplicationProvider.getApplicationContext().getResources().getString(com.walmartlabs.ern.navigation.test.R.string.root_page_title); + } + + public static class SampleActivity extends ElectrodeBaseActivity { + public static final String ROOT_COMPONENT_NAME = "Root"; + public boolean isBackgrounded; + public boolean isForegrounded; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ElectrodeReactContainer.initialize(getApplication(), new ElectrodeReactContainer.Config()); + } + + @Override + protected void onResume() { + super.onResume(); + isBackgrounded = false; + isForegrounded = true; + } + + @Override + protected void onPause() { + super.onPause(); + isBackgrounded = true; + isForegrounded = false; + } + + @Override + protected int title() { + return com.walmartlabs.ern.navigation.test.R.string.root_page_title; + } + + @Override + protected int mainLayout() { + return com.walmartlabs.ern.navigation.test.R.layout.activity_sample_main; + } + + @NonNull + @Override + protected String getRootComponentName() { + return ROOT_COMPONENT_NAME; + } + + @Override + protected int getFragmentContainerId() { + return com.walmartlabs.ern.navigation.test.R.id.sample_fragment_container; + } + + @Override + public View createReactNativeView(@NonNull String componentName, @Nullable Bundle props) { + //Returns a dummy view. + return ((LayoutInflater) Objects.requireNonNull(getSystemService(Context.LAYOUT_INFLATER_SERVICE))).inflate(com.walmartlabs.ern.navigation.test.R.layout.activity_sample_main, null); + } + + @Override + public boolean backToMiniApp(@Nullable String tag, @Nullable Bundle data) { + //Set back the title when going back to root fragment + if (ROOT_COMPONENT_NAME.equals(tag)) { + Objects.requireNonNull(getSupportActionBar()).setTitle(getString(title())); + } + return super.backToMiniApp(tag, data); + } + } +} diff --git a/android/lib/src/androidTest/res/layout/activity_sample_main.xml b/android/lib/src/androidTest/res/layout/activity_sample_main.xml new file mode 100644 index 00000000..ef858784 --- /dev/null +++ b/android/lib/src/androidTest/res/layout/activity_sample_main.xml @@ -0,0 +1,9 @@ + + + + diff --git a/android/lib/src/androidTest/res/values/strings.xml b/android/lib/src/androidTest/res/values/strings.xml new file mode 100644 index 00000000..1c1cfb5b --- /dev/null +++ b/android/lib/src/androidTest/res/values/strings.xml @@ -0,0 +1,4 @@ + + + page 0 + diff --git a/android/lib/src/main/java/com/ern/api/impl/core/ElectrodeBaseFragment.java b/android/lib/src/main/java/com/ern/api/impl/core/ElectrodeBaseFragment.java index 6f670e7a..61653afa 100644 --- a/android/lib/src/main/java/com/ern/api/impl/core/ElectrodeBaseFragment.java +++ b/android/lib/src/main/java/com/ern/api/impl/core/ElectrodeBaseFragment.java @@ -57,4 +57,8 @@ public void onDestroyView() { mElectrodeReactFragmentDelegate.onDestroyView(); super.onDestroyView(); } + + public String getReactComponentName() { + return mElectrodeReactFragmentDelegate.getReactComponentName(); + } }