0

LinearLayout (ProductList) est dynamiquement peuplé avec des vues de l'enfant lors de l'exécution, comme ci-dessous:Espresso AmbiguousViewMatcherException lorsque vous essayez de cliquer sur une icône (TextView)

@ViewById(R.id.ll_products) 
LinearLayout productList; 

public void createProductList() { 
    productList.addView(getView(mobilePhone)) 
    productList.addView(getView(internet)) 
    productList.addView(getView(television)) 
} 

public View getView(Product product) { 
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    TextView layout = (LinearLayout) inflater.inflate(R.layout.row_product, null); 
    TextView productIcon = (TextView) layout.findViewById(R.id.tv_product_row_icon); 
    productIcon.setText(product.getProductIcon()); 
    productName.setText(product.getName()); 
} 

est délibérément ProductList LinearLayout, pas ListView.

La liste de produits comporte trois produits - chaque produit a une icône (les duplications sont possibles).

Je voudrais enregistrer un scénario où je clique sur l'icône un deuxième produit. Comment un tel scénario évite-t-il AmbiguousViewMatcherException?

Malheureusement, le code suivant ne fonctionne pas - trois R.id.tv_product_row_icon sera trouvé ...

ViewInteraction appCompatTextView = onView(withId(R.id.tv_product_row_icon)); 
    appCompatTextView.perform(scrollTo(), click()); 

Comment spécifier que la deuxième icône à cliquer?

Répondre

2

Malheureusement, vous devrez créer un Matcher personnalisé pour un tel cas.

Ce qui suit correspond à l'index spécifié View avec:

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

Utilisation appropriée pour votre cas:

Matcher<View> secondIconMatcher = allOf(withId(R.id.tv_product_row_icon)); 
onView(withIndex(secondIconMatcher , 1)).perform(click()); 
+0

Il fonctionne très bien! Merci! Cependant, j'ai un cas où j'ai 5 icônes - la dernière icône est visible sur l'écran seulement après le défilement. Lorsque j'utilise votre solution, j'obtiens une exception - NoMatchingViewException: Aucune vue dans la hiérarchie trouvée correspondante: avec l'index: <4>. Une idée de ce qui pourrait causer cela? –

+1

Vous avez répondu à votre question par vous-même - la vue n'est pas visible à l'écran. La solution est de faire correspondre si la vue est visible: 'onView (matcher) .check (correspond (isDisplayed()));' à l'intérieur du bloc try-catch. Si une exception est levée, la vue parente doit être défilée. –