support - ui automator android studio
en Espresso, cómo elegir uno que tenga la misma identificación para evitar AmbiguousViewMatcherException (6)
Teniendo gridView que tiene algunas imágenes. La celda de gridView sale del mismo diseño predefinido, que tiene la misma id y desc.
R.id.item_image == 2131493330
onView(withId(is(R.id.item_image))).perform(click());
Dado que todas las celdas de la cuadrícula tienen el mismo ID, obtuvo la AmbiguousViewMatcherException
. ¿Cómo simplemente recoger uno o alguno de ellos? ¡Gracias!
android.support.test.espresso.AmbiguousViewMatcherException: ''with id: is <2131493330>'' coincide con varias vistas en la jerarquía. Las vistas de problemas están marcadas con ''**** MATCHES ****'' a continuación.
+ -------------> ImageView {id = 2131493330, res-name = item_image, desc = Image, visibilidad = VISIBLE, ancho = 262, altura = 262, has-focus = falso, tiene -focusable = false, has-window-focus = true, is-clickable = false, is-enabled = true, is-focus = false, is-focusable = false, is-layout-request = false, is-selected = false , root-is-layout-required = false, has-input-connection = false, x = 0.0, y = 0.0} **** MATCHES ****
+ -------------> ImageView {id = 2131493330, res-name = item_image, desc = Image, visibilidad = VISIBLE, ancho = 262, altura = 262, has-focus = falso, tiene -focusable = false, has-window-focus = true, is-clickable = false, is-enabled = true, is-focus = false, is-focusable = false, is-layout-request = false, is-selected = false , root-is-layout-required = false, has-input-connection = false, x = 0.0, y = 0.0} **** MATCHES **** |
Casos:
onView( withId( R.id.songListView ) ).perform( RealmRecyclerViewActions.scrollTo( Matchers.first(Matchers.withTextLabeled( "Love Song"))) );
onView( Matchers.first(withText( "Love Song")) ).perform( click() );
dentro de mi Matchers.class
public static Matcher<View> first(Matcher<View> expected ){
return new TypeSafeMatcher<View>() {
private boolean first = false;
@Override
protected boolean matchesSafely(View item) {
if( expected.matches(item) && !first ){
return first = true;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("Matcher.first( " + expected.toString() + " )" );
}
};
}
Creé un ViewMatcher que coincide con la primera vista que encuentra. Tal vez sea útil para alguien. Por ejemplo, cuando no tiene un AdapterView para usar onData () en.
/**
* Created by stost on 15.05.14.
* Matches any view. But only on first match()-call.
*/
public class FirstViewMatcher extends BaseMatcher<View> {
public static boolean matchedBefore = false;
public FirstViewMatcher() {
matchedBefore = false;
}
@Override
public boolean matches(Object o) {
if (matchedBefore) {
return false;
} else {
matchedBefore = true;
return true;
}
}
@Override
public void describeTo(Description description) {
description.appendText(" is the first view that comes along ");
}
@Factory
public static <T> Matcher<View> firstView() {
return new FirstViewMatcher();
}
}
Úsalo así:
onView(FirstViewMatcher.firstView()).perform(click());
Debería usar onData()
para operar en GridView
:
onData(withId(R.id.item_image))
.inAdapterView(withId(R.id.grid_adapter_id))
.atPosition(0)
.perform(click());
Este código hará clic en la imagen dentro del primer elemento en GridView
Intenté la respuesta de @FrostRocket ya que parecía más prometedora, pero necesitaba agregar algunas personalizaciones:
public static Matcher<View> withIndex(final Matcher<View> matcher, final int index) {
return new TypeSafeMatcher<View>() {
int currentIndex;
int viewObjHash;
@SuppressLint("DefaultLocale") @Override
public void describeTo(Description description) {
description.appendText(String.format("with index: %d ", index));
matcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
if (matcher.matches(view) && currentIndex++ == index) {
viewObjHash = view.hashCode();
}
return view.hashCode() == viewObjHash;
}
};
}
Me sorprendió que no pudiera encontrar una solución simplemente proporcionando un índice junto con un comparador (es decir, withText, withId). La respuesta aceptada solo resuelve el problema cuando se trata de onData y ListViews.
Si tiene más de una vista en la pantalla con el mismo resId / text / contentDesc, puede elegir la que desee sin causar una excepción ambigua de VisMatcher utilizando este comparador personalizado:
public static Matcher<View> withIndex(final Matcher<View> matcher, final int index) {
return new TypeSafeMatcher<View>() {
int currentIndex = 0;
@Override
public void describeTo(Description description) {
description.appendText("with index: ");
description.appendValue(index);
matcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
return matcher.matches(view) && currentIndex++ == index;
}
};
}
Por ejemplo:
onView(withIndex(withId(R.id.my_view), 2)).perform(click());
realizará una acción de clic en la tercera instancia de R.id.my_view.
No está completamente relacionado con la situación de la vista de cuadrícula, pero puede usar todos los allOf
Hamcrest para combinar múltiples condiciones:
import static org.hamcrest.CoreMatchers.allOf;
onView(allOf(withId(R.id.login_password),
withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
.check(matches(isCompletelyDisplayed()))
.check(matches(withHint(R.string.password_placeholder)));