/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react; import java.util.Date; import android.util.DisplayMetrics; import android.view.MotionEvent; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.ReactTestHelper; import com.facebook.react.bridge.SimpleArray; import com.facebook.react.bridge.SimpleMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.events.Event; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.RCTEventEmitter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.Rule; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.modules.junit4.rule.PowerMockRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @PrepareForTest(Arguments.class) @RunWith(RobolectricTestRunner.class) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) public class RootViewTest { @Rule public PowerMockRule rule = new PowerMockRule(); private ReactContext mReactContext; private CatalystInstance mCatalystInstanceMock; @Before public void setUp() { PowerMockito.mockStatic(Arguments.class); PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return new SimpleArray(); } }); PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return new SimpleMap(); } }); mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance(); mReactContext = new ReactApplicationContext(RuntimeEnvironment.application); mReactContext.initializeWithInstance(mCatalystInstanceMock); DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics(); DisplayMetricsHolder.setDisplayMetrics(displayMetrics); 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.startReactApplication(instanceManager, ""); rootView.simulateAttachForTesting(); long ts = new Date().getTime(); // 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(SimpleArray.class); verify(eventEmitterModuleMock).receiveTouches( eq("topTouchStart"), downActionTouchesArgCaptor.capture(), any(SimpleArray.class)); verifyNoMoreInteractions(eventEmitterModuleMock); assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1); assertThat(downActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo( SimpleMap.of( "pageX", 0., "pageY", 0., "locationX", 0., "locationY", 0., "target", rootViewId, "timeStamp", (double) ts, "identifier", 0.)); // Test ACTION_UP event reset(eventEmitterModuleMock, eventDispatcher); ArgumentCaptor upEventCaptor = ArgumentCaptor.forClass(Event.class); ArgumentCaptor upActionTouchesArgCaptor = ArgumentCaptor.forClass(SimpleArray.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( SimpleMap.of( "pageX", 0., "pageY", 0., "locationX", 0., "locationY", 0., "target", rootViewId, "timeStamp", (double) ts, "identifier", 0.)); // Test other action reset(eventDispatcher); rootView.onTouchEvent( MotionEvent.obtain(50, new Date().getTime(), MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0)); verifyNoMoreInteractions(eventDispatcher); } }