test support studio androidtestimplementation android android-espresso

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)));