diff --git a/lib/android/app/build.gradle b/lib/android/app/build.gradle index a2bdded3a6c..b94bed3c335 100644 --- a/lib/android/app/build.gradle +++ b/lib/android/app/build.gradle @@ -39,6 +39,8 @@ android { defaultConfig { minSdkVersion safeExtGetFallbackLowerBound('minSdkVersion', DEFAULT_MIN_SDK_VERSION) targetSdkVersion safeExtGetFallbackLowerBound('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -53,6 +55,15 @@ android { } testOptions { + managedDevices { + localDevices { + pixel3aapi34 { + device = "Pixel 3a" + apiLevel = 34 + systemImageSource = "aosp-atd" + } + } + } unitTests.includeAndroidResources = true unitTests.all { t -> maxHeapSize = "4g" @@ -102,6 +113,7 @@ dependencies { //noinspection GradleDynamicVersion implementation 'com.facebook.react:react-native:+' + if ("Playground".toLowerCase() == rootProject.name.toLowerCase()) { // tests only for our playground testImplementation 'junit:junit:4.13.2' @@ -112,5 +124,22 @@ dependencies { testImplementation 'org.mockito:mockito-inline:4.6.1' testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" + + // Core testing libraries + androidTestImplementation "androidx.test.ext:junit:1.2.1" + androidTestImplementation 'org.assertj:assertj-core:3.11.1' + + androidTestImplementation "androidx.test.espresso:espresso-core:3.6.1" + + androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.4" + androidTestImplementation 'org.opentest4j:opentest4j:1.2.0' + androidTestImplementation ("org.mockito.kotlin:mockito-kotlin:5.4.0") { + exclude group: 'org.mockito', module: 'mockito-core' + } + + androidTestImplementation "androidx.test.uiautomator:uiautomator:2.3.0" + + androidTestImplementation("com.facebook.react:hermes-android") + } } diff --git a/lib/android/app/src/androidTest/AndroidManifest.xml b/lib/android/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000000..205fd59d4b2 --- /dev/null +++ b/lib/android/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/BaseAndroidTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/BaseAndroidTest.kt new file mode 100644 index 00000000000..5d79034505f --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/BaseAndroidTest.kt @@ -0,0 +1,4 @@ +package com.reactnativenavigation + +abstract class BaseAndroidTest { +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestActivity.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestActivity.kt new file mode 100644 index 00000000000..7433935e8d9 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestActivity.kt @@ -0,0 +1,4 @@ +package com.reactnativenavigation + +class TestActivity : NavigationActivity() { +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestApplication.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestApplication.kt new file mode 100644 index 00000000000..0816d839a76 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestApplication.kt @@ -0,0 +1,45 @@ +package com.reactnativenavigation + +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.shell.MainReactPackage +import com.reactnativenavigation.react.NavigationPackage +import com.reactnativenavigation.react.NavigationReactNativeHost + +class TestApplication : NavigationApplication() { + + + override val reactNativeHost: ReactNativeHost + get() = object : NavigationReactNativeHost(this) { + override fun getJSMainModuleName(): String { + return "index" + } + + override fun getUseDeveloperSupport(): Boolean { + return false + } + + public override fun getPackages(): List { + val packages = listOf(MainReactPackage(null), NavigationPackage()) + return packages + } + + override val isHermesEnabled: Boolean + get() = true + + override val isNewArchEnabled: Boolean + get() = true + } + + override fun onCreate() { + super.onCreate() + load() + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this, reactNativeHost) + +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestUtils.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestUtils.java new file mode 100644 index 00000000000..09b7ec8b9fa --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/TestUtils.java @@ -0,0 +1,65 @@ +package com.reactnativenavigation; + +import android.app.Activity; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; + +import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock; +import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock; +import com.reactnativenavigation.mocks.TitleBarButtonCreatorMock; +import com.reactnativenavigation.mocks.TypefaceLoaderMock; +import com.reactnativenavigation.options.Options; +import com.reactnativenavigation.options.params.Bool; +import com.reactnativenavigation.utils.RenderChecker; +import com.reactnativenavigation.viewcontrollers.stack.StackPresenter; +import com.reactnativenavigation.react.events.EventEmitter; +import com.reactnativenavigation.utils.CompatUtils; +import com.reactnativenavigation.utils.ImageLoader; +import com.reactnativenavigation.utils.UiUtils; +import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry; +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; +import com.reactnativenavigation.viewcontrollers.stack.topbar.button.IconResolver; +import com.reactnativenavigation.viewcontrollers.stack.StackControllerBuilder; +import com.reactnativenavigation.viewcontrollers.stack.topbar.TopBarController; +import com.reactnativenavigation.views.stack.StackLayout; +import com.reactnativenavigation.views.stack.topbar.TopBar; + +import org.mockito.Mockito; + +public class TestUtils { + public static StackControllerBuilder newStackController(Activity activity) { + TopBarController topBarController = new TopBarController() { + @Override + protected TopBar createTopBar(@NonNull Context context, @NonNull StackLayout stackLayout) { + TopBar topBar = super.createTopBar(context, stackLayout); + topBar.layout(0, 0, 1000, UiUtils.getTopBarHeight(context)); + return topBar; + } + }; + return new StackControllerBuilder(activity, Mockito.mock(EventEmitter.class)) + .setId("stack" + CompatUtils.generateViewId()) + .setChildRegistry(new ChildControllersRegistry()) + .setTopBarController(topBarController) + .setStackPresenter(new StackPresenter(activity, new TitleBarReactViewCreatorMock(), + new TopBarBackgroundViewCreatorMock(), new TitleBarButtonCreatorMock(), + new IconResolver(activity, new ImageLoader()), new TypefaceLoaderMock(), new RenderChecker(), + new Options())) + .setInitialOptions(new Options()); + } + + public static void hideBackButton(ViewController viewController) { + viewController.options.topBar.buttons.back.visible = new Bool(false); + } + + public static T spyOn(T child) { + ViewGroup parent = (ViewGroup) child.getParent(); + int indexOf = parent.indexOfChild(child); + parent.removeView(child); + T spy = Mockito.spy(child); + parent.addView(spy, indexOf); + return spy; + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/fakes/IconResolverFake.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/fakes/IconResolverFake.kt new file mode 100644 index 00000000000..76f8b3ce0bd --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/fakes/IconResolverFake.kt @@ -0,0 +1,8 @@ +package com.reactnativenavigation.fakes + +import android.app.Activity +import com.reactnativenavigation.mocks.ImageLoaderMock +import com.reactnativenavigation.utils.ImageLoader +import com.reactnativenavigation.viewcontrollers.stack.topbar.button.IconResolver + +class IconResolverFake(activity: Activity, imageLoader: ImageLoader = ImageLoaderMock.mock()) : IconResolver(activity, imageLoader) \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/BackDrawable.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/BackDrawable.java new file mode 100644 index 00000000000..a541454a258 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/BackDrawable.java @@ -0,0 +1,30 @@ +package com.reactnativenavigation.mocks; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class BackDrawable extends Drawable { + @Override + public void draw(@NonNull Canvas canvas) { + + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return 0; + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/ImageLoaderMock.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/ImageLoaderMock.kt new file mode 100644 index 00000000000..8f4afe2c153 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/ImageLoaderMock.kt @@ -0,0 +1,49 @@ +package com.reactnativenavigation.mocks + +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.drawable.Drawable + +import com.reactnativenavigation.utils.ImageLoader +import com.reactnativenavigation.utils.ImageLoader.ImagesLoadingListener +import org.mockito.Mockito.doAnswer +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import java.util.* + +object ImageLoaderMock { + val mockDrawable: Drawable = object : Drawable() { + override fun draw(canvas: Canvas) {} + override fun setAlpha(alpha: Int) {} + override fun setColorFilter(colorFilter: ColorFilter?) {} + override fun getOpacity(): Int { + return 0 + } + } + private val backIcon: Drawable = BackDrawable() + + @JvmStatic + fun mock(): ImageLoader { + return this.mock(mockDrawable) + } + + @JvmStatic + fun mock(returnDrawable: Drawable = mockDrawable): ImageLoader { + val imageLoader = mock() + doAnswer { invocation -> + val urlCount = (invocation.arguments[1] as Collection<*>).size + val drawables = Collections.nCopies(urlCount, returnDrawable) + (invocation.arguments[2] as ImagesLoadingListener).onComplete(drawables) + null + }.`when`(imageLoader).loadIcons(any(), any(), any()) + + doAnswer { invocation -> + (invocation.arguments[2] as ImagesLoadingListener).onComplete(returnDrawable) + null + }.`when`(imageLoader).loadIcon(any(), any(), any()) + + whenever(imageLoader.getBackButtonIcon(any())).thenReturn(backIcon) + return imageLoader + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/SimpleViewController.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/SimpleViewController.java new file mode 100644 index 00000000000..5f5ace520c2 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/SimpleViewController.java @@ -0,0 +1,110 @@ +package com.reactnativenavigation.mocks; + +import static com.reactnativenavigation.utils.ObjectUtils.perform; + +import android.app.Activity; +import android.content.Context; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; + +import com.reactnativenavigation.options.Options; +import com.reactnativenavigation.react.ReactView; +import com.reactnativenavigation.viewcontrollers.child.ChildController; +import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry; +import com.reactnativenavigation.viewcontrollers.component.ComponentPresenterBase; +import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; +import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener; +import com.reactnativenavigation.views.component.ReactComponent; + +public class SimpleViewController extends ChildController { + private final ComponentPresenterBase presenter = new ComponentPresenterBase(); + + public SimpleViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Options options) { + this(activity, childRegistry, id, new Presenter(activity, new Options()), options); + } + + public SimpleViewController(Activity activity, ChildControllersRegistry childRegistry, String id, Presenter presenter, Options options) { + super(activity, childRegistry, id, presenter, options); + } + + @Override + public SimpleView createView() { + return new SimpleView(getActivity()); + } + + @Override + public void sendOnNavigationButtonPressed(String buttonId) { + getView().sendOnNavigationButtonPressed(buttonId); + } + + @Override + public void destroy() { + if (!isDestroyed()) performOnParentController(parent -> parent.onChildDestroyed(this)); + super.destroy(); + } + + @NonNull + @Override + public String toString() { + return "SimpleViewController " + getId(); + } + + @Override + public int getTopInset() { + int statusBarInset = resolveCurrentOptions().statusBar.isHiddenOrDrawBehind() ? 0 : 63; + return statusBarInset + perform(getParentController(), 0, p -> p.getTopInset(this)); + } + + @Override + public void applyBottomInset() { + if (view != null) presenter.applyBottomInset(view, getBottomInset()); + } + + @Override + public String getCurrentComponentName() { + return null; + } + + public static class SimpleView extends ReactView implements ReactComponent { + + public SimpleView(@NonNull Context context) { + super(context, "compId", "compName"); + } + + @Override + public boolean isRendered() { + return getChildCount() >= 1; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public ReactView asView() { + return this; + } + + @Override + public void destroy() { + + } + + @Override + public void sendOnNavigationButtonPressed(String buttonId) { + + } + + @Override + public ScrollEventListener getScrollEventListener() { + return null; + } + + @Override + public void dispatchTouchEventToJs(MotionEvent event) { + + } + } +} diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarButtonCreatorMock.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarButtonCreatorMock.java new file mode 100644 index 00000000000..18db78b3881 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarButtonCreatorMock.java @@ -0,0 +1,26 @@ +package com.reactnativenavigation.mocks; + +import android.app.Activity; + +import com.reactnativenavigation.options.ComponentOptions; +import com.reactnativenavigation.react.events.ComponentType; +import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarButtonCreator; +import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarReactButtonView; + +public class TitleBarButtonCreatorMock extends TitleBarButtonCreator { + public TitleBarButtonCreatorMock() { + } + + @Override + public TitleBarReactButtonView create(Activity activity, ComponentOptions component) { + return new TitleBarReactButtonView(activity, component) { + @Override + public void sendComponentStart(ComponentType type) { + } + + @Override + public void sendComponentStop(ComponentType type) { + } + }; + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java new file mode 100644 index 00000000000..13f41fbf666 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java @@ -0,0 +1,8 @@ +package com.reactnativenavigation.mocks; + +import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarReactViewCreator; + +public class TitleBarReactViewCreatorMock extends TitleBarReactViewCreator { + public TitleBarReactViewCreatorMock() { + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TopBarBackgroundViewCreatorMock.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TopBarBackgroundViewCreatorMock.java new file mode 100644 index 00000000000..e55768cc58d --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TopBarBackgroundViewCreatorMock.java @@ -0,0 +1,8 @@ +package com.reactnativenavigation.mocks; + +import com.reactnativenavigation.views.stack.topbar.TopBarBackgroundViewCreator; + +public class TopBarBackgroundViewCreatorMock extends TopBarBackgroundViewCreator { + public TopBarBackgroundViewCreatorMock() { + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.java new file mode 100644 index 00000000000..73078206c9d --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.java @@ -0,0 +1,34 @@ +package com.reactnativenavigation.mocks; + +import android.content.Context; +import android.graphics.Typeface; +import com.reactnativenavigation.options.parsers.TypefaceLoader; +import org.mockito.Mockito; + +import java.util.Map; + +public class TypefaceLoaderMock extends TypefaceLoader { + private Map mockTypefaces; + + public TypefaceLoaderMock() { + super(Mockito.mock(Context.class)); + } + + public TypefaceLoaderMock(Map mockTypefaces) { + this(); + this.mockTypefaces = mockTypefaces; + } + + @Override + public Typeface getDefaultTypeFace() { + return Typeface.DEFAULT; + } + + @Override + public Typeface getTypeFace(String fontFamilyName, String fontStyle, String fontWeight, Typeface defaultTypeFace) { + if (mockTypefaces != null && mockTypefaces.containsKey(fontFamilyName)) { + return mockTypefaces.get(fontFamilyName); + } + return defaultTypeFace; + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/utils/ButtonPresenterTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/utils/ButtonPresenterTest.kt new file mode 100644 index 00000000000..4fff18a2234 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/utils/ButtonPresenterTest.kt @@ -0,0 +1,379 @@ +package com.reactnativenavigation.utils + +import android.app.Activity +import android.app.Application +import android.content.res.Configuration +import android.graphics.Color +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter +import android.text.SpannableString +import android.view.Menu +import android.view.MenuItem +import android.widget.TextView +import androidx.appcompat.widget.ActionMenuView +import androidx.test.espresso.Espresso +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.reactnativenavigation.BaseAndroidTest +import com.reactnativenavigation.TestActivity +import com.reactnativenavigation.fakes.IconResolverFake +import com.reactnativenavigation.mocks.ImageLoaderMock.mock +import com.reactnativenavigation.options.ButtonOptions +import com.reactnativenavigation.options.IconBackgroundOptions +import com.reactnativenavigation.options.params.Bool +import com.reactnativenavigation.options.params.Colour +import com.reactnativenavigation.options.params.Number +import com.reactnativenavigation.options.params.Text +import com.reactnativenavigation.options.params.ThemeColour +import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonController +import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonPresenter +import com.reactnativenavigation.views.stack.topbar.titlebar.ButtonBar +import com.reactnativenavigation.views.stack.topbar.titlebar.IconBackgroundDrawable +import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarButtonCreator +import org.assertj.core.api.Java6Assertions +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import java.util.Objects + +@RunWith(AndroidJUnit4::class) +class ButtonPresenterTest : BaseAndroidTest() { + private lateinit var titleBar: ButtonBar + private lateinit var uut: ButtonPresenter + private lateinit var buttonController: ButtonController + private lateinit var button: ButtonOptions + private lateinit var activity: Activity + + @get:Rule + val rule = ActivityScenarioRule(TestActivity::class.java) + + @Before + fun beforeEach() { + rule.scenario.onActivity { activity: TestActivity -> + this.activity = + activity + titleBar = ButtonBar(activity) + activity.setContentView(titleBar) + button = createButton() + + val imageLoaderMock = + mock() + initUUt(imageLoaderMock) + } + } + + private fun initUUt(imageLoaderMock: ImageLoader) { + val iconResolver = IconResolverFake( + activity, imageLoaderMock + ) + uut = ButtonPresenter(activity, button, iconResolver) + buttonController = ButtonController( + activity, + uut, + button, + Mockito.mock(TitleBarButtonCreator::class.java), + Mockito.mock( + ButtonController.OnClickListener::class.java + ) + ) + } + + @Test + fun applyOptions_buttonIsAddedToMenu() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + addButtonAndApplyOptions() + Java6Assertions.assertThat(findButtonView().text.toString()) + .isEqualTo(BTN_TEXT) + } + } + + @Test + fun applyOptions_appliesColorOnButtonTextView() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + addButtonAndApplyOptions() + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor).isEqualTo(Color.RED) + } + + @Test + fun applyOptions_appliesColorOnButtonTextViewOnDarkMode() { + val application = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application + application.resources.configuration.uiMode = Configuration.UI_MODE_NIGHT_NO + button.color = ThemeColour(Colour(Color.RED), Colour(Color.BLACK)) + var menuItem: MenuItem? = null + InstrumentationRegistry.getInstrumentation().runOnMainSync { + menuItem = addButtonAndApplyOptions() + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor).isEqualTo(Color.RED) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + application.resources.configuration.uiMode = Configuration.UI_MODE_NIGHT_YES + uut.applyOptions(titleBar, menuItem!!) { buttonController.view } + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor).isEqualTo(Color.BLACK) + } + + @Test + fun apply_disabledColor() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + button.enabled = Bool(false) + addButtonAndApplyOptions() + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor) + .isEqualTo(ButtonPresenter.DISABLED_COLOR) + } + + @Test + fun applyColor_shouldChangeColor() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val menuItem = addMenuButton() + uut.applyOptions(titleBar, menuItem) { buttonController.view } + val color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + uut.applyColor(titleBar, menuItem, color) + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor).isEqualTo(Color.RED) + } + + @Test + fun applyBackgroundColor_shouldChangeBackgroundColor() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val mockD = Mockito.mock( + IconBackgroundDrawable::class.java + ) + initUUt(mock(mockD)) + button.enabled = Bool(true) + button.icon = Text("icon") + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + val iconBackground = IconBackgroundOptions() + iconBackground.color = ThemeColour( + Colour(Color.GREEN), + Colour(Color.GREEN) + ) + button.iconBackground = iconBackground + val menuItem = Mockito.spy(addMenuButton()) + uut.applyOptions(titleBar, menuItem) { buttonController.view } + + Java6Assertions.assertThat((menuItem.icon as IconBackgroundDrawable).backgroundColor) + .isEqualTo(Color.GREEN) + + uut.applyBackgroundColor( + titleBar, menuItem, + ThemeColour( + Colour(Color.BLACK), + Colour(Color.BLACK) + ) + ) + Java6Assertions.assertThat((menuItem.icon as IconBackgroundDrawable).backgroundColor) + .isEqualTo(Color.BLACK) + } + } + + @Test + fun applyOptions_shouldChangeIconColorTint() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val mockD = Mockito.mock( + IconBackgroundDrawable::class.java + ) + initUUt(mock(mockD)) + button.enabled = Bool(true) + button.icon = Text("icon") + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + val menuItem = Mockito.spy(addMenuButton()) + uut.applyOptions(titleBar, menuItem) { buttonController.view } + + val icon = menuItem.icon + Java6Assertions.assertThat( + icon + ).isNotNull() + Mockito.verify(icon)?.colorFilter = + PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN) + } + } + + @Test + fun applyOptions_shouldChangeIconDisabledColorTint() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val mockD = Mockito.mock( + IconBackgroundDrawable::class.java + ) + initUUt(mock(mockD)) + button.enabled = Bool(false) + button.icon = Text("icon") + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + button.disabledColor = ThemeColour( + Colour(Color.YELLOW), + Colour(Color.YELLOW) + ) + val menuItem = Mockito.spy(addMenuButton()) + uut.applyOptions(titleBar, menuItem) { buttonController.view } + + val icon = menuItem.icon + Java6Assertions.assertThat( + icon + ).isNotNull() + Mockito.verify(icon)?.colorFilter = + PorterDuffColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_IN) + } + } + + @Test + fun applyOptions_shouldChangeIconColorBackground() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val mockD = Mockito.mock( + IconBackgroundDrawable::class.java + ) + initUUt(mock(mockD)) + button.enabled = Bool(true) + button.icon = Text("icon") + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + val iconBackground = IconBackgroundOptions() + iconBackground.color = ThemeColour( + Colour(Color.GREEN), + Colour(Color.GREEN) + ) + button.iconBackground = iconBackground + val menuItem = Mockito.spy(addMenuButton()) + uut.applyOptions(titleBar, menuItem) { buttonController.view } + + val icon = menuItem.icon + Java6Assertions.assertThat( + icon + ).isNotNull() + Java6Assertions.assertThat( + icon + ).isInstanceOf( + IconBackgroundDrawable::class.java + ) + val modifed = icon as IconBackgroundDrawable? + Mockito.verify(modifed!!.getWrappedDrawable()).colorFilter = + PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN) + Java6Assertions.assertThat(modifed.backgroundColor) + .isEqualTo(Color.GREEN) + } + } + + @Test + fun applyOptions_shouldChangeIconDisabledColorBackground() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + val mockD = Mockito.mock( + IconBackgroundDrawable::class.java + ) + initUUt(mock(mockD)) + button.enabled = Bool(false) + button.icon = Text("icon") + button.color = + ThemeColour(Colour(Color.RED), Colour(Color.RED)) + button.disabledColor = ThemeColour( + Colour(Color.YELLOW), + Colour(Color.YELLOW) + ) + val iconBackground = IconBackgroundOptions() + iconBackground.color = ThemeColour( + Colour(Color.GREEN), + Colour(Color.GREEN) + ) + iconBackground.disabledColor = ThemeColour( + Colour(Color.CYAN), + Colour(Color.CYAN) + ) + button.iconBackground = iconBackground + val menuItem = Mockito.spy(addMenuButton()) + uut.applyOptions(titleBar, menuItem) { buttonController.view } + + val icon = menuItem.icon + Java6Assertions.assertThat( + icon + ).isNotNull() + Java6Assertions.assertThat( + icon + ).isInstanceOf( + IconBackgroundDrawable::class.java + ) + val modifed = icon as IconBackgroundDrawable? + Mockito.verify(modifed!!.getWrappedDrawable()).colorFilter = + PorterDuffColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_IN) + Java6Assertions.assertThat(modifed.backgroundColor) + .isEqualTo(Color.CYAN) + } + } + + @Test + fun applyColor_shouldChangeDisabledColor() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + button.enabled = Bool(false) + val menuItem = addMenuButton() + uut.applyOptions(titleBar, menuItem) { buttonController.view } + val disabledColor = ThemeColour( + Colour(Color.BLUE), + Colour(Color.BLUE) + ) + uut.applyDisabledColor(titleBar, menuItem, disabledColor) + } + Espresso.onIdle() + Java6Assertions.assertThat(findButtonView().currentTextColor).isEqualTo(Color.BLUE) + } + + @Test + fun apply_allCaps() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + button.allCaps = Bool(false) + addButtonAndApplyOptions() + Java6Assertions.assertThat(findButtonView().isAllCaps) + .isEqualTo(false) + } + } + + private fun addButtonAndApplyOptions(): MenuItem { + val menuItem = addMenuButton() + uut.applyOptions(titleBar, menuItem) { buttonController.view } + return menuItem + } + + private fun addMenuButton(): MenuItem { + return titleBar.addButton( + Menu.NONE, + 1, + 0, + SpannableString.valueOf(button.text["text"]) + ) ?: throw IllegalStateException("MenuItem should not be null") + } + + private fun findButtonView(): TextView { + return ViewUtils.findChildrenByClass( + Objects.requireNonNull( + ViewUtils.findChildByClass( + titleBar, + ActionMenuView::class.java + ) + ), + TextView::class.java + ) { child: Any? -> true }[0] as TextView + } + + private fun createButton(): ButtonOptions { + val b = ButtonOptions() + b.id = "btn1" + b.text = Text(BTN_TEXT) + b.showAsAction = Number(MenuItem.SHOW_AS_ACTION_ALWAYS) + return b + } + + companion object { + private const val BTN_TEXT = "button1" + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.kt new file mode 100644 index 00000000000..b97124c01ab --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.kt @@ -0,0 +1,42 @@ +package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes + +import androidx.test.espresso.Espresso +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.verify +import org.mockito.kotlin.any + +class AfterInitialTabTest : AttachModeTest() { + + @Before + override fun setup() { + super.setup() + uut = AfterInitialTab(parent, tabs, presenter, options) + } + + @Test + fun attach_initialTabIsAttached() { + uut.attach() + assertIsChild(parent, tab2) + } + + @Test + fun attach_otherTabsAreAttachedAfterInitialTab() { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + uut.attach() + + assertNotChildOf(parent, *otherTabs()) + + initialTab().onViewWillAppear() + } + Espresso.onIdle() + assertIsChild(parent, *otherTabs()) + } + + @Test + fun destroy() { + uut.destroy() + verify(initialTab()).removeOnAppearedListener(any()) + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.kt new file mode 100644 index 00000000000..cc1ea18ff5d --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.kt @@ -0,0 +1,98 @@ +package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes + +import android.view.View +import android.view.ViewGroup +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.reactnativenavigation.TestActivity +import com.reactnativenavigation.mocks.SimpleViewController +import com.reactnativenavigation.options.Options +import com.reactnativenavigation.options.params.Number +import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsPresenter +import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController +import com.reactnativenavigation.views.bottomtabs.BottomTabsBehaviour +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.Mockito.spy + +@RunWith(AndroidJUnit4::class) +abstract class AttachModeTest { + private val INITIAL_TAB = 1 + + private lateinit var childRegistry: ChildControllersRegistry + protected lateinit var parent: ViewGroup + protected lateinit var tab1: ViewController<*> + protected lateinit var tab2: ViewController<*> + protected lateinit var tabs: List> + protected lateinit var options: Options + protected lateinit var presenter: BottomTabsPresenter + protected lateinit var uut: AttachMode + + @get:Rule + val rule = ActivityScenarioRule(TestActivity::class.java) + + @Before + open fun setup() { + rule.scenario.onActivity { activity -> + childRegistry = ChildControllersRegistry() + parent = CoordinatorLayout(activity) + tabs = createTabs(activity) + } + options = Options() + options.bottomTabsOptions.currentTabIndex = Number(INITIAL_TAB) + presenter = Mockito.mock(BottomTabsPresenter::class.java) + } + + @Test + fun attach_layoutOptionsAreApplied() { + uut.attach(tab1) + val lp = tab1.getView().layoutParams as CoordinatorLayout.LayoutParams + assertThat(lp).isNotNull + assertThat(lp.behavior).isInstanceOf(BottomTabsBehaviour::class.java) + } + + @Test + fun attach_initialTabIsVisible() { + uut.attach(initialTab()) + assertThat(initialTab().getView().visibility).isEqualTo(View.VISIBLE) + } + + @Test + fun attach_otherTabsAreInvisibleWhenAttached() { + otherTabs().forEach { t -> uut.attach(t) } + otherTabs().forEach { t -> assertThat(t.getView().visibility).isEqualTo(View.INVISIBLE) } + } + + protected fun otherTabs(): Array> { + return tabs.filter { t -> t != initialTab() }.toTypedArray() + } + + protected fun initialTab(): ViewController<*> { + return tabs[INITIAL_TAB] + } + + private fun createTabs(activity: android.app.Activity): List> { + tab1 = SimpleViewController(activity, childRegistry, "child1", Options()) + tab2 = spy(SimpleViewController(activity, childRegistry, "child2", Options())) + val tab3 = SimpleViewController(activity, childRegistry, "child3", Options()) + return listOf(tab1, tab2, tab3) + } + + protected fun assertIsChild(parent: ViewGroup, vararg children: ViewController<*>) { + children.forEach { child -> + assertThat(child.getView().parent).isEqualTo(parent) + } + } + + protected fun assertNotChildOf(parent: ViewGroup, vararg children: ViewController<*>) { + children.forEach { child -> + assertThat(child.getView().parent).isNotEqualTo(parent) + } + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.kt new file mode 100644 index 00000000000..f2dd97f7955 --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.kt @@ -0,0 +1,32 @@ +package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes + +import org.junit.Before +import org.junit.Test + +class OnSwitchToTabTest : AttachModeTest() { + + @Before + override fun setup() { + super.setup() + uut = OnSwitchToTab(parent, tabs, presenter, options) + } + + @Test + fun attach_onlyInitialTabIsAttached() { + uut.attach() + assertIsChild(parent, initialTab()) + assertNotChildOf(parent, *otherTabs()) + } + + @Test + fun onTabSelected_initialTabIsNotHandled() { + uut.onTabSelected(initialTab()) + assertNotChildOf(parent, initialTab()) + } + + @Test + fun onTabSelected_otherTabIsAttached() { + uut.onTabSelected(tab1) + assertIsChild(parent, tab1) + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.kt new file mode 100644 index 00000000000..f3d900c64ee --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.kt @@ -0,0 +1,19 @@ +package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes + +import org.junit.Before +import org.junit.Test + +class TogetherTest : AttachModeTest() { + + @Before + override fun setup() { + super.setup() + uut = Together(parent, tabs, presenter, options) + } + + @Test + fun attach_allTabsAreAttached() { + uut.attach() + assertIsChild(parent, *tabs.toTypedArray()) + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java new file mode 100644 index 00000000000..73f8cef0faf --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java @@ -0,0 +1,102 @@ +package com.reactnativenavigation.viewcontrollers.child; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.core.app.ActivityScenario; + +import com.reactnativenavigation.BaseAndroidTest; +import com.reactnativenavigation.TestActivity; +import com.reactnativenavigation.mocks.SimpleViewController; +import com.reactnativenavigation.options.Options; +import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; +import com.reactnativenavigation.viewcontrollers.parent.ParentController; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@RunWith(AndroidJUnit4.class) +public class ChildControllerTest extends BaseAndroidTest { + private ChildController uut; + private ChildControllersRegistry childRegistry; + private Presenter presenter; + private Options resolvedOptions = new Options(); + + @Rule + public ActivityScenarioRule rule = new ActivityScenarioRule<>(TestActivity.class); + + @Before + public void beforeEach() { + rule.getScenario().onActivity(activity -> { + childRegistry = spy(new ChildControllersRegistry()); + presenter = Mockito.mock(Presenter.class); + uut = new SimpleViewController(activity, childRegistry, "childId", presenter, new Options()) { + @Override + public Options resolveCurrentOptions() { + return resolvedOptions; + } + }; + ParentController parent = Mockito.mock(ParentController.class); + Mockito.when(parent.resolveChildOptions(uut)).thenReturn(Options.EMPTY); + uut.setParentController(parent); + }); + } + + @Test + public void onViewAppeared() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> uut.onViewWillAppear()); + verify(childRegistry, times(1)).onViewAppeared(uut); + } + + @Test + public void onViewDisappear() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + uut.onViewWillAppear(); + uut.onViewDisappear(); + }); + verify(childRegistry, times(1)).onViewDisappear(uut); + } + + @Test + public void mergeOptions() { + try (ActivityScenario scenario = ActivityScenario.launch(TestActivity.class)) { + scenario.onActivity(activity -> { + activity.setContentView(uut.getView()); + Options options = new Options(); + uut.mergeOptions(options); + verify(presenter).mergeOptions(uut, options); + }); + } + } + + @Test + public void mergeOptions_emptyOptionsAreIgnored() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + uut.mergeOptions(Options.EMPTY); + verify(presenter, times(0)).mergeOptions(any(), any()); + }); + } + + @Test + public void mergeOptions_mergeWithParentViewController() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + Options options = new Options(); + uut.mergeOptions(options); + verify(uut.getParentController()).mergeChildOptions(options, uut); + }); + } + + @Test + public void destroy() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> uut.destroy()); + verify(childRegistry).onChildDestroyed(uut); + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java new file mode 100644 index 00000000000..c818e91219b --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java @@ -0,0 +1,67 @@ +package com.reactnativenavigation.viewcontrollers.child; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.reactnativenavigation.BaseAndroidTest; +import com.reactnativenavigation.TestActivity; +import com.reactnativenavigation.mocks.SimpleViewController; +import com.reactnativenavigation.options.Options; + +import org.assertj.core.api.Java6Assertions; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@RunWith(AndroidJUnit4ClassRunner.class) +public class ChildControllersRegistryTest extends BaseAndroidTest { + private ChildControllersRegistry uut; + private ChildController child1; + private ChildController child2; + + @Rule + public ActivityScenarioRule rule = new ActivityScenarioRule<>(TestActivity.class); + + + @Before + public void beforeEach() { + rule.getScenario().onActivity(activity -> { + uut = new ChildControllersRegistry(); + child1 = Mockito.spy(new SimpleViewController(activity, uut, "child1", new Options())); + child2 = Mockito.spy(new SimpleViewController(activity, uut, "child2", new Options())); + }); + } + + @Test + public void onViewAppeared() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> child1.onViewWillAppear()); + Mockito.verify(child1, Mockito.times(0)).onViewBroughtToFront(); + Java6Assertions.assertThat(uut.size()).isOne(); + } + + @Test + public void onViewDisappear() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + child1.onViewWillAppear(); + child2.onViewWillAppear(); + }); + Java6Assertions.assertThat(uut.size()).isEqualTo(2); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> child2.onViewDisappear()); + Mockito.verify(child1, Mockito.times(1)).onViewBroughtToFront(); + Java6Assertions.assertThat(uut.size()).isOne(); + } + + @Test + public void onChildDestroyed() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> child1.destroy()); + Java6Assertions.assertThat(uut.size()).isEqualTo(0); + } + + @Test + public void onViewDisappear_doesNotCrashIfNoViewsHaveAppeared() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> uut.onViewDisappear(child1)); + } +} diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/parent/ParentControllerTest.java b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/parent/ParentControllerTest.java new file mode 100644 index 00000000000..fb2337a059d --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/viewcontrollers/parent/ParentControllerTest.java @@ -0,0 +1,349 @@ +package com.reactnativenavigation.viewcontrollers.parent; + +import android.app.Activity; +import android.content.res.Configuration; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.reactnativenavigation.BaseAndroidTest; +import com.reactnativenavigation.TestActivity; +import com.reactnativenavigation.TestUtils; +import com.reactnativenavigation.mocks.SimpleViewController; +import com.reactnativenavigation.options.Options; +import com.reactnativenavigation.options.params.Text; +import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; +import com.reactnativenavigation.react.CommandListenerAdapter; +import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry; +import com.reactnativenavigation.viewcontrollers.stack.StackController; +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import androidx.annotation.NonNull; + +import static com.reactnativenavigation.utils.CollectionUtils.*; +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(AndroidJUnit4.class) +public class ParentControllerTest extends BaseAndroidTest { + private static final String INITIAL_TITLE = "initial title"; + private Activity activity; + private ChildControllersRegistry childRegistry; + private List> children; + private ParentController uut; + private Presenter presenter; + + @Rule + public ActivityScenarioRule rule = new ActivityScenarioRule<>(TestActivity.class); + + @Before + public void beforeEach() { + rule.getScenario().onActivity(activity -> { + this.activity = activity; + childRegistry = new ChildControllersRegistry(); + children = new ArrayList<>(); + Options initialOptions = new Options(); + initialOptions.topBar.title.text = new Text(INITIAL_TITLE); + presenter = spy(new Presenter(activity, new Options())); + uut = spy(new ParentController(activity, childRegistry, "uut", presenter, initialOptions) { + @Override + public ViewController getCurrentChild() { + return children.get(0); + } + + @NonNull + @Override + public ViewGroup createView() { + FrameLayout layout = new FrameLayout(activity); + for (ViewController child : children) { + child.setParentController(this); + layout.addView(child.getView()); + } + return layout; + } + + @Override + public void sendOnNavigationButtonPressed(String buttonId) { + } + + @NonNull + @Override + public Collection> getChildControllers() { + return children; + } + }); + }); + } + + @Test + public void onConfigurationChange_shouldCallConfigurationChangeForPresenterAndVisibleChild() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + SimpleViewController child1 = spy( + new SimpleViewController(activity, childRegistry, "child1", new Options())); + SimpleViewController child2 = spy( + new SimpleViewController(activity, childRegistry, "child2", new Options())); + children.add(child1); + children.add(child2); + Mockito.when(child1.isViewShown()).thenReturn(true); + Mockito.when(child2.isViewShown()).thenReturn(false); + uut.onConfigurationChanged(mock(Configuration.class)); + verify(presenter).onConfigurationChanged(any(), any()); + verify(child1).onConfigurationChanged(any()); + verify(child2, never()).onConfigurationChanged(any()); + }); + } + + @Test + public void onViewDidAppearShouldCallCurrentChildDidAppear() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + SimpleViewController child1 = spy( + new SimpleViewController(activity, childRegistry, "child1", new Options())); + SimpleViewController child2 = spy( + new SimpleViewController(activity, childRegistry, "child2", new Options())); + children.add(child1); + children.add(child2); + + uut.onViewDidAppear(); + + verify(child1).onViewDidAppear(); + verify(child2, never()).onViewDidAppear(); + }); + } + + @Test + public void onViewDisappearShouldCallCurrentChildDisAppear() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + SimpleViewController child1 = spy( + new SimpleViewController(activity, childRegistry, "child1", new Options())); + SimpleViewController child2 = spy( + new SimpleViewController(activity, childRegistry, "child2", new Options())); + children.add(child1); + children.add(child2); + + uut.onViewDisappear(); + + verify(child1).onViewDisappear(); + verify(child2, never()).onViewDisappear(); + }); + } + + @Test + public void holdsViewGroup() { + assertThat(uut.getView()).isInstanceOf(ViewGroup.class); + } + + @Test + public void mustHaveChildControllers() { + assertThat(uut.getChildControllers()).isNotNull(); + } + + @Test + public void findControllerById_ChildById() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options()); + SimpleViewController child2 = new SimpleViewController(activity, childRegistry, "child2", new Options()); + children.add(child1); + children.add(child2); + + assertThat(uut.findController("uut")).isEqualTo(uut); + assertThat(uut.findController("child1")).isEqualTo(child1); + }); + } + + @Test + public void findControllerById_Recursive() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + StackController stackController = TestUtils.newStackController(activity).build(); + stackController.ensureViewIsCreated(); + SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options()); + SimpleViewController child2 = new SimpleViewController(activity, childRegistry, "child2", new Options()); + stackController.push(child1, new CommandListenerAdapter()); + stackController.push(child2, new CommandListenerAdapter()); + children.add(stackController); + + assertThat(uut.findController("child2")).isEqualTo(child2); + }); + } + + @Test + public void destroy_DestroysChildren() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", new Options())); + children.add(child1); + + verify(child1, times(0)).destroy(); + uut.destroy(); + verify(child1, times(1)).destroy(); + }); + } + + @Test + public void optionsAreClearedWhenChildIsAppeared() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + StackController stackController = spy(TestUtils.newStackController(activity).build()); + stackController.ensureViewIsCreated(); + SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options()); + stackController.push(child1, new CommandListenerAdapter()); + + child1.onViewWillAppear(); + verify(stackController, times(1)).clearOptions(); + }); + } + + @Test + public void mergeOptions_optionsAreMergedWhenChildAppears() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + Options options = new Options(); + options.topBar.title.text = new Text("new title"); + ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", options)); + children.add(child1); + uut.ensureViewIsCreated(); + + child1.ensureViewIsCreated(); + child1.onViewWillAppear(); + ArgumentCaptor optionsCaptor = ArgumentCaptor.forClass(Options.class); + verify(uut, times(1)).clearOptions(); + verify(uut, times(1)).applyChildOptions(optionsCaptor.capture(), eq(child1)); + assertThat(optionsCaptor.getValue().topBar.title.text.get()).isEqualTo("new title"); + }); + } + + @Test + public void mergeOptions_initialParentOptionsAreNotMutatedWhenChildAppears() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + Options options = new Options(); + options.topBar.title.text = new Text("new title"); + ViewController child1 = spy(new SimpleViewController(activity, childRegistry, "child1", options)); + children.add(child1); + + uut.ensureViewIsCreated(); + + child1.ensureViewIsCreated(); + child1.onViewWillAppear(); + assertThat(uut.initialOptions.topBar.title.text.get()).isEqualTo(INITIAL_TITLE); + }); + } + + @Test + public void resolveCurrentOptions_returnOptionsIfNoChildren() { + assertThat(uut.getChildControllers().size()).isZero(); + assertThat(uut.resolveCurrentOptions()).isEqualTo(uut.initialOptions); + } + + @Test + public void resolveCurrentOptions_mergesWithCurrentChild() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + ViewController child1 = Mockito.mock(ViewController.class); + when(child1.getView()).thenReturn(new FrameLayout(activity)); + Options copiedChildOptions = spy(new Options()); + Options childOptions = spy(new Options() { + @Override + public Options copy() { + return copiedChildOptions; + } + }); + when(child1.resolveCurrentOptions()).thenReturn(childOptions); + + children.add(child1); + + uut.ensureViewIsCreated(); + assertThat(uut.getCurrentChild()).isEqualTo(child1); + uut.resolveCurrentOptions(); + verify(child1).resolveCurrentOptions(); + verify(copiedChildOptions).withDefaultOptions(uut.initialOptions); + }); + } + + @Test + public void resolveCurrentOptions_withDefaultOptions() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + SimpleViewController child1 = new SimpleViewController(activity, childRegistry, "child1", new Options()); + children.add(child1); + uut.ensureViewIsCreated(); + + Options defaultOptions = new Options(); + Options currentOptions = spy(new Options()); + ParentController spy = spy(uut); + Mockito.when(spy.resolveCurrentOptions()).thenReturn(currentOptions); + spy.resolveCurrentOptions(defaultOptions); + verify(currentOptions).withDefaultOptions(defaultOptions); + }); + } + + @Test + public void applyTopInset() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + children.addAll(createChildren()); + uut.applyTopInset(); + forEach(children, c -> verify(c).applyTopInset()); + }); + } + + @Test + public void getTopInset() { + assertThat(uut.getTopInset()).isZero(); + } + + @Test + public void getTopInsetForChild() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + ParentController parent = Mockito.mock(ParentController.class); + Mockito.when(parent.resolveChildOptions(uut)).thenReturn(Options.EMPTY); + + when(parent.getTopInset(any())).thenReturn(123); + uut.setParentController(parent); + + assertThat(uut.getTopInset(Mockito.mock(ViewController.class))).isEqualTo(123); + }); + } + + @Test + public void applyBottomInset() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + children.addAll(createChildren()); + uut.applyBottomInset(); + forEach(children, c -> verify(c).applyBottomInset()); + }); + } + + @Test + public void getBottomInsetForChild() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + ParentController parent = Mockito.mock(ParentController.class); + Mockito.when(parent.resolveChildOptions(uut)).thenReturn(Options.EMPTY); + + when(parent.getBottomInset(any())).thenReturn(123); + uut.setParentController(parent); + + assertThat(uut.getBottomInset(Mockito.mock(ViewController.class))).isEqualTo(123); + }); + } + + private List> createChildren() { + return Arrays.asList( + spy(new SimpleViewController(activity, childRegistry, "child1", new Options())), + spy(new SimpleViewController(activity, childRegistry, "child2", new Options()))); + } +} \ No newline at end of file diff --git a/lib/android/app/src/androidTest/java/com/reactnativenavigation/views/TitleSubTitleLayoutTest.kt b/lib/android/app/src/androidTest/java/com/reactnativenavigation/views/TitleSubTitleLayoutTest.kt new file mode 100644 index 00000000000..f369f38c0bc --- /dev/null +++ b/lib/android/app/src/androidTest/java/com/reactnativenavigation/views/TitleSubTitleLayoutTest.kt @@ -0,0 +1,51 @@ +package com.reactnativenavigation.views + +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.reactnativenavigation.TestActivity +import com.reactnativenavigation.views.stack.topbar.titlebar.TitleSubTitleLayout +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +private const val UUT_WIDTH = 1000 +private const val UUT_HEIGHT = 100 + +@RunWith(AndroidJUnit4::class) +class TitleSubTitleLayoutTest { + private val testId = "mock-testId" + + private lateinit var uut: TitleSubTitleLayout + + @get:Rule + val rule = ActivityScenarioRule(TestActivity::class.java) + + @Before + fun setup() { + rule.scenario.onActivity { activity -> + uut = TitleSubTitleLayout(activity) + activity.setContentView(FrameLayout(activity).apply { + addView(uut, ViewGroup.LayoutParams(UUT_WIDTH, UUT_HEIGHT)) + }) + } + } + + @Test + fun shouldSetTestIdCanonically() { + uut.setTestId(testId) + assertThat(uut.getTitleTxtView().tag).isEqualTo("$testId.title") + assertThat(uut.getSubTitleTxtView().tag).isEqualTo("$testId.subtitle") + } + + @Test + fun shouldClearTestId() { + uut.setTestId(testId) + uut.setTestId("") + assertThat(uut.getTitleTxtView().tag).isNull() + assertThat(uut.getSubTitleTxtView().tag).isNull() + } +} \ No newline at end of file diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/presentation/PresenterTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/presentation/PresenterTest.java index c41739cb792..41863210747 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/presentation/PresenterTest.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/presentation/PresenterTest.java @@ -25,7 +25,7 @@ import org.junit.Test; import org.mockito.Mockito; -@Ignore("New architecture - WIP") +@Ignore("New architecture - failed to fix") public class PresenterTest extends BaseTest { private Presenter uut; private Activity activity; diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.java deleted file mode 100644 index 2314519d9bc..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AfterInitialTabTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes; - - -import org.junit.Ignore; -import org.junit.Test; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - -@Ignore("New architecture - WIP") -public class AfterInitialTabTest extends AttachModeTest { - - @Override - public void beforeEach() { - super.beforeEach(); - uut = new AfterInitialTab(parent, tabs, presenter, options); - } - - @Test - public void attach_initialTabIsAttached() { - uut.attach(); - assertIsChild(parent, tab2); - } - - @Test - public void attach_otherTabsAreAttachedAfterInitialTab() { - uut.attach(); - assertNotChildOf(parent, otherTabs()); - - initialTab().onViewWillAppear(); - idleMainLooper(); - assertIsChild(parent, otherTabs()); - } - - @Test - public void destroy() { - uut.destroy(); - verify(initialTab()).removeOnAppearedListener(any()); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java deleted file mode 100644 index 7d708a549e6..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes; - -import android.app.Activity; -import android.view.View; -import android.view.ViewGroup; - -import com.reactnativenavigation.BaseTest; -import com.reactnativenavigation.mocks.SimpleViewController; -import com.reactnativenavigation.options.Options; -import com.reactnativenavigation.options.params.Number; -import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabsPresenter; -import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry; -import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; -import com.reactnativenavigation.views.bottomtabs.BottomTabsBehaviour; - -import org.junit.Test; -import org.mockito.Mockito; - -import java.util.Arrays; -import java.util.List; - -import androidx.coordinatorlayout.widget.CoordinatorLayout; - -import static com.reactnativenavigation.utils.CollectionUtils.*; -import static org.assertj.core.api.Java6Assertions.assertThat; -import static org.mockito.Mockito.spy; - -public abstract class AttachModeTest extends BaseTest { - private static final int INITIAL_TAB = 1; - - private Activity activity; - private ChildControllersRegistry childRegistry; - protected ViewGroup parent; - ViewController tab1; - ViewController tab2; - List> tabs; - protected Options options; - protected BottomTabsPresenter presenter; - protected AttachMode uut; - - @Override - public void beforeEach() { - super.beforeEach(); - activity = newActivity(); - childRegistry = new ChildControllersRegistry(); - parent = new CoordinatorLayout(activity); - tabs = createTabs(); - options = new Options(); - options.bottomTabsOptions.currentTabIndex = new Number(INITIAL_TAB); - presenter = Mockito.mock(BottomTabsPresenter.class); - } - - @Test - public void attach_layoutOptionsAreApplied() { - uut.attach(tab1); - CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) tab1.getView().getLayoutParams(); - assertThat(lp).isNotNull(); - assertThat(lp.getBehavior()).isInstanceOf(BottomTabsBehaviour.class); - } - - @Test - public void attach_initialTabIsVisible() { - uut.attach(initialTab()); - assertThat(initialTab().getView().getVisibility()).isEqualTo(View.VISIBLE); - } - - @Test - public void attach_otherTabsAreInvisibleWhenAttached() { - forEach(otherTabs(), t -> uut.attach(t)); - forEach(otherTabs(), t -> assertThat(t.getView().getVisibility()).isEqualTo(View.INVISIBLE)); - } - - ViewController[] otherTabs() { - return filter(tabs, t -> t != initialTab()).toArray(new ViewController[0]); - } - - ViewController initialTab() { - return tabs.get(INITIAL_TAB); - } - - private List> createTabs() { - tab1 = new SimpleViewController(activity, childRegistry, "child1", new Options()); - tab2 = spy(new SimpleViewController(activity, childRegistry, "child2", new Options())); - ViewController tab3 = new SimpleViewController(activity, childRegistry, "child3", new Options()); - return Arrays.asList(tab1, tab2, tab3); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.java deleted file mode 100644 index 1ee3a0192e8..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTabTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes; - -import org.junit.*; - -@Ignore("New architecture - WIP") -public class OnSwitchToTabTest extends AttachModeTest { - - @Override - public void beforeEach() { - super.beforeEach(); - uut = new OnSwitchToTab(parent, tabs, presenter, options); - } - - @Test - public void attach_onlyInitialTabIsAttached() { - uut.attach(); - assertIsChild(parent, initialTab()); - assertNotChildOf(parent, otherTabs()); - } - - @Test - public void onTabSelected_initialTabIsNotHandled() { - uut.onTabSelected(initialTab()); - assertNotChildOf(parent, initialTab()); - } - - @Test - public void onTabSelected_otherTabIsAttached() { - uut.onTabSelected(tab1); - assertIsChild(parent, tab1); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.java deleted file mode 100644 index 4ef04650247..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/TogetherTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.modes; - -import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; - -import org.junit.*; - -@Ignore("New architecture - WIP") -public class TogetherTest extends AttachModeTest { - - @Override - public void beforeEach() { - super.beforeEach(); - uut = new Together(parent, tabs, presenter, options); - } - - @Test - public void attach_allTabsAreAttached() { - uut.attach(); - assertIsChild(parent, tabs.toArray(new ViewController[0])); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java deleted file mode 100644 index 7205e4b73b7..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.child; - -import com.reactnativenavigation.BaseTest; -import com.reactnativenavigation.mocks.SimpleViewController; -import com.reactnativenavigation.options.Options; -import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; -import com.reactnativenavigation.viewcontrollers.parent.ParentController; - -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.Mockito; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -@Ignore("New architecture - WIP") -public class ChildControllerTest extends BaseTest { - - private ChildController uut; - private ChildControllersRegistry childRegistry; - private Presenter presenter; - private Options resolvedOptions = new Options(); - - @Override - public void beforeEach() { - super.beforeEach(); - childRegistry = spy(new ChildControllersRegistry()); - presenter = Mockito.mock(Presenter.class); - uut = new SimpleViewController(newActivity(), childRegistry, "childId", presenter, new Options()) { - @Override - public Options resolveCurrentOptions() { - return resolvedOptions; - } - }; - ParentController parent = Mockito.mock(ParentController.class); - Mockito.when(parent.resolveChildOptions(uut)).thenReturn(Options.EMPTY); - uut.setParentController(parent); - } - - @Test - public void onViewAppeared() { - uut.onViewWillAppear(); - verify(childRegistry, times(1)).onViewAppeared(uut); - } - - @Test - public void onViewDisappear() { - uut.onViewWillAppear(); - - uut.onViewDisappear(); - verify(childRegistry, times(1)).onViewDisappear(uut); - } - - @Test - public void mergeOptions() { - newActivity().setContentView(uut.getView()); - - Options options = new Options(); - uut.mergeOptions(options); - verify(presenter).mergeOptions(uut, options); - } - - @Test - public void mergeOptions_emptyOptionsAreIgnored() { - uut.mergeOptions(Options.EMPTY); - verify(presenter, times(0)).mergeOptions(any(), any()); - } - - @Test - public void mergeOptions_mergeWithParentViewController() { - Options options = new Options(); - uut.mergeOptions(options); - verify(uut.getParentController()).mergeChildOptions(options, uut); - } - - @Test - public void destroy() { - uut.destroy(); - verify(childRegistry).onChildDestroyed(uut); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java deleted file mode 100644 index c9a2a204ef5..00000000000 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.child; - -import android.app.Activity; - -import com.reactnativenavigation.BaseTest; -import com.reactnativenavigation.mocks.SimpleViewController; -import com.reactnativenavigation.options.Options; - -import org.junit.Ignore; -import org.junit.Test; - -import static org.assertj.core.api.Java6Assertions.assertThat; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@Ignore("New architecture - WIP") -public class ChildControllersRegistryTest extends BaseTest { - private ChildControllersRegistry uut; - private ChildController child1; - private ChildController child2; - - @Override - public void beforeEach() { - super.beforeEach(); - Activity activity = newActivity(); - uut = new ChildControllersRegistry(); - child1 = spy(new SimpleViewController(activity, uut, "child1", new Options())); - child2 = spy(new SimpleViewController(activity, uut, "child2", new Options())); - } - - @Test - public void onViewAppeared() { - child1.onViewWillAppear(); - verify(child1, times(0)).onViewBroughtToFront(); - assertThat(uut.size()).isOne(); - } - - @Test - public void onViewDisappear() { - child1.onViewWillAppear(); - child2.onViewWillAppear(); - assertThat(uut.size()).isEqualTo(2); - child2.onViewDisappear(); - verify(child1, times(1)).onViewBroughtToFront(); - assertThat(uut.size()).isOne(); - } - - @Test - public void onChildDestroyed() { - child1.destroy(); - assertThat(uut.size()).isEqualTo(0); - } - - @Test - public void onViewDisappear_doesNotCrashIfNoViewsHaveAppeared() { - uut.onViewDisappear(child1); - } -} diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/views/TitleAndButtonsContainerTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/views/TitleAndButtonsContainerTest.kt index 0f09278b197..4846fa48d49 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/views/TitleAndButtonsContainerTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/views/TitleAndButtonsContainerTest.kt @@ -30,7 +30,7 @@ import kotlin.test.assertFalse private const val UUT_WIDTH = 1000 private const val UUT_HEIGHT = 100 -@Ignore("New architecture - WIP") +@Ignore("New architecture - failed to fix") class TitleAndButtonsContainerTest : BaseTest() { lateinit var uut: TitleAndButtonsContainer private lateinit var activity: Activity diff --git a/package-lock.json b/package-lock.json index 9c4d21a603e..0efff00ef6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15486,7 +15486,7 @@ }, "node_modules/npm/node_modules/lodash._baseindexof": { "version": "3.1.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -15502,19 +15502,19 @@ }, "node_modules/npm/node_modules/lodash._bindcallback": { "version": "3.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._cacheindexof": { "version": "3.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/lodash._createcache": { "version": "3.1.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -15529,7 +15529,7 @@ }, "node_modules/npm/node_modules/lodash._getnative": { "version": "3.9.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, @@ -15547,7 +15547,7 @@ }, "node_modules/npm/node_modules/lodash.restparam": { "version": "3.6.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT" }, diff --git a/playground/android/gradle.properties b/playground/android/gradle.properties index 33663d6115c..5b8b5878d26 100644 --- a/playground/android/gradle.properties +++ b/playground/android/gradle.properties @@ -22,4 +22,6 @@ android.useAndroidX=true android.jetifier.ignorelist=bcprov hermesEnabled=true newArchEnabled=true -FLIPPER_VERSION=0.191.0 \ No newline at end of file +FLIPPER_VERSION=0.191.0 + +android.experimental.androidTest.numManagedDeviceShards=3 diff --git a/scripts/test-unit.js b/scripts/test-unit.js index 214728ada25..50a097fb87d 100644 --- a/scripts/test-unit.js +++ b/scripts/test-unit.js @@ -20,6 +20,7 @@ function runAndroidUnitTests() { // exec.execSync(`echo y | ${sdkmanager} --update && echo y | ${sdkmanager} --licenses`); } exec.execSync(`cd playground/android && ./gradlew ${conf}`); + exec.execSync(`cd playground/android && ./gradlew :react-native-navigation:pixel3aapi34DebugAndroidTest`); } function runIosUnitTests() {