-
Notifications
You must be signed in to change notification settings - Fork 24.7k
[e2e-testing][Appium] Adding support for android:id #9942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1a69e13
d613eda
3bf8965
2d64675
b06afbb
650fe68
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,8 @@ | |
import com.facebook.react.views.textinput.ReactTextChangedEvent; | ||
import com.facebook.react.views.textinput.ReactTextInputEvent; | ||
|
||
import static com.facebook.react.common.ViewMethodsUtil.reactTagFor; | ||
|
||
/** | ||
* Test to verify that TextInput renders correctly | ||
*/ | ||
|
@@ -114,15 +116,15 @@ public void testMetionsInputColors() throws Throwable { | |
|
||
eventDispatcher.dispatchEvent( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why change these? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simulates the behavior of |
||
new ReactTextChangedEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
newText.toString(), | ||
(int) PixelUtil.toDIPFromPixel(contentWidth), | ||
(int) PixelUtil.toDIPFromPixel(contentHeight), | ||
reactEditText.incrementAndGetEventCounter())); | ||
|
||
eventDispatcher.dispatchEvent( | ||
new ReactTextInputEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
newText.toString(), | ||
"", | ||
start, | ||
|
@@ -146,15 +148,15 @@ public void testMetionsInputColors() throws Throwable { | |
|
||
eventDispatcher.dispatchEvent( | ||
new ReactTextChangedEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
newText.toString(), | ||
(int) PixelUtil.toDIPFromPixel(contentWidth), | ||
(int) PixelUtil.toDIPFromPixel(contentHeight), | ||
reactEditText.incrementAndGetEventCounter())); | ||
|
||
eventDispatcher.dispatchEvent( | ||
new ReactTextInputEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
moreText, | ||
"", | ||
start, | ||
|
@@ -178,15 +180,15 @@ public void testMetionsInputColors() throws Throwable { | |
|
||
eventDispatcher.dispatchEvent( | ||
new ReactTextChangedEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
newText.toString(), | ||
(int) PixelUtil.toDIPFromPixel(contentWidth), | ||
(int) PixelUtil.toDIPFromPixel(contentHeight), | ||
reactEditText.incrementAndGetEventCounter())); | ||
|
||
eventDispatcher.dispatchEvent( | ||
new ReactTextInputEvent( | ||
reactEditText.getId(), | ||
reactTagFor(reactEditText), | ||
moreText, | ||
"", | ||
start, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,6 +88,7 @@ | |
import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_START; | ||
import static com.facebook.react.bridge.ReactMarkerConstants.SETUP_REACT_CONTEXT_END; | ||
import static com.facebook.react.bridge.ReactMarkerConstants.SETUP_REACT_CONTEXT_START; | ||
import static com.facebook.react.common.ViewMethodsUtil.reactTagFor; | ||
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; | ||
|
||
/** | ||
|
@@ -797,7 +798,7 @@ private void attachMeasuredRootViewToInstance( | |
|
||
// Reset view content as it's going to be populated by the application content from JS | ||
rootView.removeAllViews(); | ||
rootView.setId(View.NO_ID); | ||
rootView.setTag(View.NO_ID); | ||
|
||
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); | ||
int rootTag = uiManagerModule.addMeasuredRootView(rootView); | ||
|
@@ -818,7 +819,7 @@ private void detachViewFromInstance( | |
CatalystInstance catalystInstance) { | ||
UiThreadUtil.assertOnUiThread(); | ||
catalystInstance.getJSModule(AppRegistry.class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a fan of adding complexity here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
.unmountApplicationComponentAtRootTag(rootView.getId()); | ||
.unmountApplicationComponentAtRootTag(reactTagFor(rootView)); | ||
} | ||
|
||
private void tearDownReactContext(ReactContext reactContext) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.facebook.react.common; | ||
|
||
import android.view.View; | ||
|
||
import com.facebook.react.common.annotations.VisibleForTesting; | ||
|
||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
public class TestIdUtil { | ||
private static final ConcurrentHashMap<String, Integer> mTestIds = new ConcurrentHashMap<>(); | ||
// Integer values in R.class are typically large. To avoid colliding with R.class we | ||
// use smaller values for ids when no resource id exists. | ||
private static final int mStartingInternalId = 1; | ||
private static final AtomicInteger mInternalId = new AtomicInteger(mStartingInternalId); | ||
|
||
/** | ||
* Looks for defined resource IDs in R.class by the name of testId and if a matching resource ID is | ||
* found it is passed to the view's setId method. If the given testId cannot be found in R.class, | ||
* an increment value is assigned instead. | ||
*/ | ||
public static <T extends View> void setTestId(T view, String testId) { | ||
int mappedTestId; | ||
if (!mTestIds.containsKey(testId)) { | ||
mappedTestId = view.getResources().getIdentifier(testId, "id", view.getContext().getPackageName()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do the resource lookup? If you remove this branch and just use the map, there's no need to define ids in the xml file, correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ids should be in the xml file so R.class is generated correctly; otherwise, uiautomatorviewer and appium can't associate it to the |
||
final boolean idNotFoundInResources = mappedTestId <= 0; | ||
if (idNotFoundInResources) { | ||
mappedTestId = mInternalId.getAndIncrement(); | ||
} | ||
mTestIds.put(testId, mappedTestId); | ||
} else { | ||
mappedTestId = mTestIds.get(testId); | ||
} | ||
|
||
if (mappedTestId != 0 && view.getId() != mappedTestId) { | ||
view.setId(mappedTestId); | ||
} | ||
} | ||
|
||
/** | ||
* Used for e2e tests that do not yet have testIDs stored in ids.xml. It is strongly | ||
* advised that you reference ids that have been generated in R.class to avoid collisions and | ||
* to properly support UIAutomatorViewer. | ||
*/ | ||
@VisibleForTesting | ||
public static int getTestId(String testId) { | ||
return mTestIds.containsKey(testId) ? mTestIds.get(testId) : View.NO_ID; | ||
} | ||
|
||
@VisibleForTesting | ||
public static void resetStateInTest() { | ||
mTestIds.clear(); | ||
mInternalId.set(mStartingInternalId); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.facebook.react.common; | ||
|
||
import android.view.View; | ||
|
||
public class ViewMethodsUtil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Android has a |
||
|
||
/** | ||
* Returns the react tag for the view. If no react tag has been set then {@link View#NO_ID} is | ||
* returned. | ||
*/ | ||
public static int reactTagFor(View view) { | ||
return view == null || view.getTag() == null ? | ||
View.NO_ID : | ||
(int) view.getTag(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ | |
import android.view.ViewGroup; | ||
import android.view.ViewParent; | ||
|
||
import static com.facebook.react.common.ViewMethodsUtil.reactTagFor; | ||
|
||
/** | ||
* This class coordinates JSResponder commands for {@link UIManagerModule}. It should be set as | ||
* OnInterceptTouchEventListener for all newly created native views that implements | ||
|
@@ -70,7 +72,7 @@ public boolean onInterceptTouchEvent(ViewGroup v, MotionEvent event) { | |
// Therefore since "UP" event is the last event in a gesture, we should just let it reach the | ||
// original target that is a child view of {@param v}. | ||
// http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent) | ||
return v.getId() == currentJSResponder; | ||
return reactTagFor(v) == currentJSResponder; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm thinking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea, |
||
} | ||
return false; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting approach!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I couldn't think of a better one. The resource ids need to be created at compile time in order for uiautomatorviewer to recognize them.