From fe5455b87c8f0014769b72cf4adc538dc14d3a7c Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Thu, 4 May 2023 07:56:09 -0700 Subject: [PATCH] Back out "Convert RootViewTest to Kotlin" (#37249) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37249 Original commit changeset: e0cf65012665 Original Phabricator Diff: D45526517 I'm reverting this change as the history got lost in this Kotlin conversion. I'm going to re-push it using `hg mv`. Changelog: [Internal] [Changed] - Back out "[RN][Android] Convert RootViewTest to Kotlin" Reviewed By: cipolleschi Differential Revision: D45564898 fbshipit-source-id: b144f688cfa612f0d22d65cadfd766f73996371c --- .../java/com/facebook/react/RootViewTest.java | 266 ++++++++++++++++++ .../java/com/facebook/react/RootViewTest.kt | 224 --------------- 2 files changed, 266 insertions(+), 224 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java delete mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java new file mode 100644 index 00000000000..87c5bfe69ad --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.graphics.Insets; +import android.graphics.Rect; +import android.view.MotionEvent; +import android.view.WindowInsets; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactTestHelper; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.common.SystemClock; +import com.facebook.react.uimanager.DisplayMetricsHolder; +import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.events.Event; +import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.RCTEventEmitter; +import java.util.Date; +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 org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.rule.PowerMockRule; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@PrepareForTest({Arguments.class, SystemClock.class}) +@RunWith(RobolectricTestRunner.class) +@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "androidx.*", "android.*"}) +public class RootViewTest { + + @Rule public PowerMockRule rule = new PowerMockRule(); + + private ReactContext mReactContext; + private CatalystInstance mCatalystInstanceMock; + + @Before + public void setUp() { + final long ts = SystemClock.uptimeMillis(); + PowerMockito.mockStatic(Arguments.class); + PowerMockito.when(Arguments.createArray()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyArray(); + } + }); + PowerMockito.when(Arguments.createMap()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyMap(); + } + }); + PowerMockito.mockStatic(SystemClock.class); + PowerMockito.when(SystemClock.uptimeMillis()) + .thenAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return ts; + } + }); + + mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance(); + mReactContext = spy(new ReactApplicationContext(RuntimeEnvironment.application)); + mReactContext.initializeWithInstance(mCatalystInstanceMock); + DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(mReactContext); + + UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class); + when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)) + .thenReturn(uiManagerModuleMock); + } + + @Test + public void testTouchEmitter() { + ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); + when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext); + + UIManagerModule uiManager = mock(UIManagerModule.class); + EventDispatcher eventDispatcher = mock(EventDispatcher.class); + RCTEventEmitter eventEmitterModuleMock = mock(RCTEventEmitter.class); + when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)).thenReturn(uiManager); + when(uiManager.getEventDispatcher()).thenReturn(eventDispatcher); + + int rootViewId = 7; + + ReactRootView rootView = new ReactRootView(mReactContext); + rootView.setId(rootViewId); + rootView.setRootViewTag(rootViewId); + rootView.startReactApplication(instanceManager, ""); + rootView.simulateAttachForTesting(); + + long ts = SystemClock.currentTimeMillis(); + + // Test ACTION_DOWN event + rootView.onTouchEvent(MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0, 0, 0)); + + ArgumentCaptor downEventCaptor = ArgumentCaptor.forClass(Event.class); + verify(eventDispatcher).dispatchEvent(downEventCaptor.capture()); + verifyNoMoreInteractions(eventDispatcher); + + downEventCaptor.getValue().dispatch(eventEmitterModuleMock); + + ArgumentCaptor downActionTouchesArgCaptor = + ArgumentCaptor.forClass(JavaOnlyArray.class); + verify(eventEmitterModuleMock) + .receiveTouches( + eq("topTouchStart"), downActionTouchesArgCaptor.capture(), any(JavaOnlyArray.class)); + verifyNoMoreInteractions(eventEmitterModuleMock); + + assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1); + assertThat(downActionTouchesArgCaptor.getValue().getMap(0)) + .isEqualTo( + JavaOnlyMap.of( + "pageX", + 0., + "pageY", + 0., + "locationX", + 0., + "locationY", + 0., + "target", + rootViewId, + "timestamp", + (double) ts, + "identifier", + 0., + "targetSurface", + -1)); + + // Test ACTION_UP event + reset(eventEmitterModuleMock, eventDispatcher); + + ArgumentCaptor upEventCaptor = ArgumentCaptor.forClass(Event.class); + ArgumentCaptor upActionTouchesArgCaptor = + ArgumentCaptor.forClass(JavaOnlyArray.class); + + rootView.onTouchEvent(MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0, 0, 0)); + verify(eventDispatcher).dispatchEvent(upEventCaptor.capture()); + verifyNoMoreInteractions(eventDispatcher); + + upEventCaptor.getValue().dispatch(eventEmitterModuleMock); + verify(eventEmitterModuleMock) + .receiveTouches( + eq("topTouchEnd"), upActionTouchesArgCaptor.capture(), any(WritableArray.class)); + verifyNoMoreInteractions(eventEmitterModuleMock); + + assertThat(upActionTouchesArgCaptor.getValue().size()).isEqualTo(1); + assertThat(upActionTouchesArgCaptor.getValue().getMap(0)) + .isEqualTo( + JavaOnlyMap.of( + "pageX", + 0., + "pageY", + 0., + "locationX", + 0., + "locationY", + 0., + "target", + rootViewId, + "timestamp", + (double) ts, + "identifier", + 0., + "targetSurface", + -1)); + + // Test other action + reset(eventDispatcher); + rootView.onTouchEvent( + MotionEvent.obtain(50, new Date().getTime(), MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0)); + verifyNoMoreInteractions(eventDispatcher); + } + + @Test + public void testRemountApplication() { + ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); + + ReactRootView rootView = new ReactRootView(mReactContext); + + rootView.startReactApplication(instanceManager, ""); + rootView.unmountReactApplication(); + rootView.startReactApplication(instanceManager, ""); + } + + @Test + public void testCheckForKeyboardEvents() { + ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); + Activity mActivity = Robolectric.buildActivity(Activity.class).create().get(); + + when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext); + + ReactRootView rootView = + new ReactRootView(mActivity) { + @Override + public void getWindowVisibleDisplayFrame(Rect outRect) { + if (outRect.bottom == 0) { + outRect.bottom += 100; + outRect.right += 370; + } else { + outRect.bottom += 370; + } + } + + @Override + public WindowInsets getRootWindowInsets() { + return new WindowInsets.Builder() + .setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 370)) + .setVisible(WindowInsets.Type.ime(), true) + .build(); + } + }; + + rootView.startReactApplication(instanceManager, ""); + rootView.simulateCheckForKeyboardForTesting(); + + WritableMap params = Arguments.createMap(); + WritableMap endCoordinates = Arguments.createMap(); + double screenHeight = 470.0; + double keyboardHeight = 100.0; + params.putDouble("duration", 0.0); + endCoordinates.putDouble("width", screenHeight - keyboardHeight); + endCoordinates.putDouble("screenX", 0.0); + endCoordinates.putDouble("height", screenHeight - keyboardHeight); + endCoordinates.putDouble("screenY", keyboardHeight); + params.putMap("endCoordinates", endCoordinates); + params.putString("easing", "keyboard"); + + verify(mReactContext, Mockito.times(1)).emitDeviceEvent("keyboardDidShow", params); + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt deleted file mode 100644 index 9be2b225b03..00000000000 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react - -import android.app.Activity -import android.graphics.Insets -import android.graphics.Rect -import android.view.MotionEvent -import android.view.WindowInsets -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.CatalystInstance -import com.facebook.react.bridge.JavaOnlyArray -import com.facebook.react.bridge.JavaOnlyMap -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContext -import com.facebook.react.bridge.ReactTestHelper -import com.facebook.react.bridge.WritableArray -import com.facebook.react.common.SystemClock -import com.facebook.react.uimanager.DisplayMetricsHolder -import com.facebook.react.uimanager.UIManagerModule -import com.facebook.react.uimanager.events.Event -import com.facebook.react.uimanager.events.EventDispatcher -import com.facebook.react.uimanager.events.RCTEventEmitter -import java.util.Date -import org.assertj.core.api.Assertions.* -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers -import org.mockito.Mockito.* -import org.powermock.api.mockito.PowerMockito.mockStatic -import org.powermock.api.mockito.PowerMockito.`when` as whenever -import org.powermock.core.classloader.annotations.PowerMockIgnore -import org.powermock.core.classloader.annotations.PrepareForTest -import org.powermock.modules.junit4.rule.PowerMockRule -import org.robolectric.Robolectric -import org.robolectric.RobolectricTestRunner -import org.robolectric.RuntimeEnvironment - -@PrepareForTest(Arguments::class, SystemClock::class) -@RunWith(RobolectricTestRunner::class) -@PowerMockIgnore("org.mockito.*", "org.robolectric.*", "androidx.*", "android.*") -class RootViewTest { - @get:Rule var rule = PowerMockRule() - - private lateinit var reactContext: ReactContext - private lateinit var catalystInstanceMock: CatalystInstance - - @Before - fun setUp() { - val ts = SystemClock.uptimeMillis() - mockStatic(SystemClock::class.java) - mockStatic(Arguments::class.java) - whenever(Arguments.createArray()).thenAnswer { JavaOnlyArray() } - whenever(Arguments.createMap()).thenAnswer { JavaOnlyMap() } - whenever(SystemClock.uptimeMillis()).thenAnswer { ts } - - catalystInstanceMock = ReactTestHelper.createMockCatalystInstance() - reactContext = spy(ReactApplicationContext(RuntimeEnvironment.application)) - reactContext.initializeWithInstance(catalystInstanceMock) - - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext) - val uiManagerModuleMock = mock(UIManagerModule::class.java) - whenever(catalystInstanceMock.getNativeModule(UIManagerModule::class.java)) - .thenReturn(uiManagerModuleMock) - } - - @Test - fun testTouchEmitter() { - val instanceManager = mock(ReactInstanceManager::class.java) - whenever(instanceManager.currentReactContext).thenReturn(reactContext) - val uiManager = mock(UIManagerModule::class.java) - val eventDispatcher = mock(EventDispatcher::class.java) - val eventEmitterModuleMock = mock(RCTEventEmitter::class.java) - whenever(catalystInstanceMock.getNativeModule(UIManagerModule::class.java)) - .thenReturn(uiManager) - whenever(uiManager.eventDispatcher).thenReturn(eventDispatcher) - - // RootView IDs is React Native follow the 11, 21, 31, ... progression. - val rootViewId = 11 - val rootView = ReactRootView(reactContext) - rootView.id = rootViewId - rootView.rootViewTag = rootViewId - rootView.startReactApplication(instanceManager, "") - rootView.simulateAttachForTesting() - val ts = SystemClock.currentTimeMillis() - - // Test ACTION_DOWN event - rootView.onTouchEvent(MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) - - val downEventCaptor = ArgumentCaptor.forClass(Event::class.java) - verify(eventDispatcher).dispatchEvent(downEventCaptor.capture()) - verifyNoMoreInteractions(eventDispatcher) - downEventCaptor.value.dispatch(eventEmitterModuleMock) - val downActionTouchesArgCaptor = ArgumentCaptor.forClass(JavaOnlyArray::class.java) - verify(eventEmitterModuleMock) - .receiveTouches( - ArgumentMatchers.eq("topTouchStart"), - downActionTouchesArgCaptor.capture(), - ArgumentMatchers.any(JavaOnlyArray::class.java)) - verifyNoMoreInteractions(eventEmitterModuleMock) - assertThat(downActionTouchesArgCaptor.value.size()).isEqualTo(1) - assertThat(downActionTouchesArgCaptor.value.getMap(0)) - .isEqualTo( - JavaOnlyMap.of( - "pageX", - 0.0, - "pageY", - 0.0, - "locationX", - 0.0, - "locationY", - 0.0, - "target", - rootViewId, - "timestamp", - ts.toDouble(), - "identifier", - 0.0, - "targetSurface", - -1)) - - // Test ACTION_UP event - reset(eventEmitterModuleMock, eventDispatcher) - val upEventCaptor = ArgumentCaptor.forClass(Event::class.java) - val upActionTouchesArgCaptor = ArgumentCaptor.forClass(JavaOnlyArray::class.java) - - rootView.onTouchEvent(MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0f, 0f, 0)) - - verify(eventDispatcher).dispatchEvent(upEventCaptor.capture()) - verifyNoMoreInteractions(eventDispatcher) - upEventCaptor.value.dispatch(eventEmitterModuleMock) - verify(eventEmitterModuleMock) - .receiveTouches( - ArgumentMatchers.eq("topTouchEnd"), - upActionTouchesArgCaptor.capture(), - ArgumentMatchers.any(WritableArray::class.java)) - verifyNoMoreInteractions(eventEmitterModuleMock) - assertThat(upActionTouchesArgCaptor.value.size()).isEqualTo(1) - assertThat(upActionTouchesArgCaptor.value.getMap(0)) - .isEqualTo( - JavaOnlyMap.of( - "pageX", - 0.0, - "pageY", - 0.0, - "locationX", - 0.0, - "locationY", - 0.0, - "target", - rootViewId, - "timestamp", - ts.toDouble(), - "identifier", - 0.0, - "targetSurface", - -1)) - - // Test other action - reset(eventDispatcher) - - rootView.onTouchEvent( - MotionEvent.obtain(50, Date().time, MotionEvent.ACTION_HOVER_MOVE, 0f, 0f, 0)) - - verifyNoMoreInteractions(eventDispatcher) - } - - @Test - fun testRemountApplication() { - val instanceManager = mock(ReactInstanceManager::class.java) - val rootView = ReactRootView(reactContext) - rootView.startReactApplication(instanceManager, "") - rootView.unmountReactApplication() - rootView.startReactApplication(instanceManager, "") - } - - @Test - fun testCheckForKeyboardEvents() { - val instanceManager = mock(ReactInstanceManager::class.java) - val activity = Robolectric.buildActivity(Activity::class.java).create().get() - whenever(instanceManager.currentReactContext).thenReturn(reactContext) - val rootView: ReactRootView = - object : ReactRootView(activity) { - override fun getWindowVisibleDisplayFrame(outRect: Rect) { - if (outRect.bottom == 0) { - outRect.bottom += 100 - outRect.right += 370 - } else { - outRect.bottom += 370 - } - } - - override fun getRootWindowInsets() = - WindowInsets.Builder() - .setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 370)) - .setVisible(WindowInsets.Type.ime(), true) - .build() - } - - rootView.startReactApplication(instanceManager, "") - rootView.simulateCheckForKeyboardForTesting() - - val params = Arguments.createMap() - val endCoordinates = Arguments.createMap() - val screenHeight = 470.0 - val keyboardHeight = 100.0 - params.putDouble("duration", 0.0) - endCoordinates.putDouble("width", screenHeight - keyboardHeight) - endCoordinates.putDouble("screenX", 0.0) - endCoordinates.putDouble("height", screenHeight - keyboardHeight) - endCoordinates.putDouble("screenY", keyboardHeight) - params.putMap("endCoordinates", endCoordinates) - params.putString("easing", "keyboard") - verify(reactContext, times(1)).emitDeviceEvent("keyboardDidShow", params) - } -}