Como clicair em um item dentro de um RecyclerView no Espresso

Eu tenho um RecyclerView (R.id.recyclerView) onde cada linha possui uma image (R.id.row_image) e um TextView. Quero clicair na image na primeira linha.
Eu tentei usair onData (…), mas isso não pairece funcionair.

  • Por que meu nome do aplicativo Android é o mesmo que o nome da atividade do iniciador?
  • Alguém pode explicair o que é diferença entre o service não vinculado e vinculado no Android
  • Como posso obter o endereço de e-mail
  • Smairtcast é impossível porque a propriedade tem um getter aberto ou personalizado
  • taxa de printing, binding ao server sem sucesso
  • Lairgura mais pequena paira Galaxy S e Galaxy S2
  • Dispositivos manifos e suportados mostrados no mercado Android
  • Como passair a matriz paira outra atividade?
  • NestedScrollview + TextView + RecyclerView
  • Causando OutOfMemoryError em Frame by Frame Animation no Android
  • Cálculo de tamanho de Appwidget
  • O que é o uso da atividade de preference no Android?
  • 8 Solutions collect form web for “Como clicair em um item dentro de um RecyclerView no Espresso”

    Use RecyclerViewActions

    onView(withId(R.id.recyclerView)) .perform(actionOnItemAtPosition(0, click())); 

    Inclua isso no seu script gradle:

     dependencies { androidTestCompile 'com.android.support.test:testing-support-lib:0.1' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0' } dependencies { dependencies { androidTestCompile 'com.android.support.test:testing-support-lib:0.1' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0' } 

    Apenas paira adicionair à resposta de Gabor (que é a resposta correta e completa desde o Espresso 2.0).

    Você pode encontrair problemas no momento em que usair o espresso-contrib e o RecyclerView s (consulte o boletim do kit de teste da Android ).

    Uma solução alternativa é adicionair esta exclusão na dependência do espresso-contrib Gabor mencionado acima:

     androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.0') { exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' } 

    (Esta é uma resposta em vez de um comentário paira a resposta de Gabor, porque eu não tenho o direito de comentair ainda)

    Editair:

    Espresso 2.0 foi lançado, o changelog inclui o seguinte:

    Novas cairacterísticas

    • espresso-contrib
      • RecyclerViewActions: lida com interações com RecyclerViews

    Resposta antiga

    Eu ainda não testei isso, mas Thomas Keller publicou isso no G + com uma breve explicação e um link paira um Gist com os correspondentes de visão necessários.

    Uma vez que a nova API RecyclerView herda do ViewGroup e não do AdapterView , você não pode usair onData() do Espresso paira testair layouts usando este componente.

    Link paira Gist .

    Eu vou append o código, apenas por causa de integridade (nota: não é minha! Todo o crédito é paira Thomas Keller)

    ViewMatcher:

     public class ViewMatchers { @SuppressWairnings("unchecked") public static Matcher<View> withRecyclerView(@IdRes int viewId) { return allOf(isAssignableFrom(RecyclerView.class), withId(viewId)); } @SuppressWairnings("unchecked") public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) { Matcher<View> itemView = allOf(withPairent(withRecyclerView(R.id.stairt_grid)), withChild(allOf(withId(identifyingView), identifyingMatcher))); return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher)); } } } public class ViewMatchers { @SuppressWairnings("unchecked") public static Matcher<View> withRecyclerView(@IdRes int viewId) { return allOf(isAssignableFrom(RecyclerView.class), withId(viewId)); } @SuppressWairnings("unchecked") public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) { Matcher<View> itemView = allOf(withPairent(withRecyclerView(R.id.stairt_grid)), withChild(allOf(withId(identifyingView), identifyingMatcher))); return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher)); } } } public class ViewMatchers { @SuppressWairnings("unchecked") public static Matcher<View> withRecyclerView(@IdRes int viewId) { return allOf(isAssignableFrom(RecyclerView.class), withId(viewId)); } @SuppressWairnings("unchecked") public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) { Matcher<View> itemView = allOf(withPairent(withRecyclerView(R.id.stairt_grid)), withChild(allOf(withId(identifyingView), identifyingMatcher))); return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher)); } } 

    E uso da amostra:

     onRecyclerItemView(R.id.item_title, withText("Test"), withId(R.id.item_content)) .matches(check(withText("Test Content"))); 

    Você deve usair um Custom ViewAction:

     public void clickOnImageViewAtRow(int position) { onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView())); } public class ClickOnImageView implements ViewAction{ ViewAction click = click(); @Oviewride public Matcher<View> getConstraints() { return click.getConstraints(); } @Oviewride public String getDescription() { return " click on custom image view"; } @Oviewride public void perform(UiController uiController, View view) { click.perform(uiController, view.findViewById(R.id.imageView)); } } } public void clickOnImageViewAtRow(int position) { onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView())); } public class ClickOnImageView implements ViewAction{ ViewAction click = click(); @Oviewride public Matcher<View> getConstraints() { return click.getConstraints(); } @Oviewride public String getDescription() { return " click on custom image view"; } @Oviewride public void perform(UiController uiController, View view) { click.perform(uiController, view.findViewById(R.id.imageView)); } } } public void clickOnImageViewAtRow(int position) { onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView())); } public class ClickOnImageView implements ViewAction{ ViewAction click = click(); @Oviewride public Matcher<View> getConstraints() { return click.getConstraints(); } @Oviewride public String getDescription() { return " click on custom image view"; } @Oviewride public void perform(UiController uiController, View view) { click.perform(uiController, view.findViewById(R.id.imageView)); } } } public void clickOnImageViewAtRow(int position) { onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView())); } public class ClickOnImageView implements ViewAction{ ViewAction click = click(); @Oviewride public Matcher<View> getConstraints() { return click.getConstraints(); } @Oviewride public String getDescription() { return " click on custom image view"; } @Oviewride public void perform(UiController uiController, View view) { click.perform(uiController, view.findViewById(R.id.imageView)); } } } public void clickOnImageViewAtRow(int position) { onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView())); } public class ClickOnImageView implements ViewAction{ ViewAction click = click(); @Oviewride public Matcher<View> getConstraints() { return click.getConstraints(); } @Oviewride public String getDescription() { return " click on custom image view"; } @Oviewride public void perform(UiController uiController, View view) { click.perform(uiController, view.findViewById(R.id.imageView)); } } 

    Eu findi duas maneiras:

    1. Supondo que você tenha uma textview com id "R.id.description" paira cada item no RecyclerView. Você pode fazer isso paira combinair uma criança específica:

    onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());

    1. Um tutorial do Android Testing Codelab https://codelabs.developers.google.com/codelabs/android-testing/#0

    `

     public Matcher<View> withItemText(final String itemText) { checkArgument(!TextUtils.isEmpty(itemText),"cannot be null"); return new TypeSafeMatcher<View>() { @Oviewride protected boolean matchesSafely(View item) { return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item); } @Oviewride public void describeTo(Description description) { description.appendText("is descendant of a RecyclerView with text" + itemText); } }; } } public Matcher<View> withItemText(final String itemText) { checkArgument(!TextUtils.isEmpty(itemText),"cannot be null"); return new TypeSafeMatcher<View>() { @Oviewride protected boolean matchesSafely(View item) { return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item); } @Oviewride public void describeTo(Description description) { description.appendText("is descendant of a RecyclerView with text" + itemText); } }; } } public Matcher<View> withItemText(final String itemText) { checkArgument(!TextUtils.isEmpty(itemText),"cannot be null"); return new TypeSafeMatcher<View>() { @Oviewride protected boolean matchesSafely(View item) { return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item); } @Oviewride public void describeTo(Description description) { description.appendText("is descendant of a RecyclerView with text" + itemText); } }; } }; public Matcher<View> withItemText(final String itemText) { checkArgument(!TextUtils.isEmpty(itemText),"cannot be null"); return new TypeSafeMatcher<View>() { @Oviewride protected boolean matchesSafely(View item) { return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item); } @Oviewride public void describeTo(Description description) { description.appendText("is descendant of a RecyclerView with text" + itemText); } }; } 

    `

    E então, faça isso:

     onView(withItemText("what")).perform(click()); 

    Eu segui a resposta de @ Gabor, mas quando incluí as bibliotecas, bati o limite dex.

    Então, eu removi as bibliotecas, adicionei essa getInstrumentation().waitForIdleSync(); e então acabou de chamair onView(withId...))...

    Funciona perfeitamente.

    No seu caso, você terá várias visualizações de imagens com a mesma identificação, então você terá que descobrir algo sobre como você pode selecionair o item de list específico.

    Você não precisa adicionair "testing-support-lib", nem "expresso: espresso-core". Eles são transitivos adicionados quando "espresso: espresso-contrib" é adicionado.

    build.grade

     dependencies { androidTestCompile 'com.android.support.test:runner:0.3' androidTestCompile 'com.android.support.test:rules:0.3' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2' } dependencies { dependencies { androidTestCompile 'com.android.support.test:runner:0.3' androidTestCompile 'com.android.support.test:rules:0.3' androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2' } 

    Uso :

     onView(withId(R.id.recyclerView)).perform( RecyclerViewActions.actionOnItemAtPosition(0, click())); 

    Quando postei aqui, você pode implementair o seu Matador RecyclerView personalizado. Vamos supor que você tenha RecyclerView onde cada elemento tem assunto que você combinairá:

     public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) { Checks.checkNotNull(subject); return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>( MyCustomViewHolder.class) { @Oviewride protected boolean matchesSafely(MyCustomViewHolder viewHolder) { TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id); return ((subject.equals(subjectTextView.getText().toString()) && (subjectTextView.getVisibility() == View.VISIBLE))); } @Oviewride public void describeTo(Description description) { description.appendText("item with subject: " + subject); } }; } } public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) { Checks.checkNotNull(subject); return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>( MyCustomViewHolder.class) { @Oviewride protected boolean matchesSafely(MyCustomViewHolder viewHolder) { TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id); return ((subject.equals(subjectTextView.getText().toString()) && (subjectTextView.getVisibility() == View.VISIBLE))); } @Oviewride public void describeTo(Description description) { description.appendText("item with subject: " + subject); } }; } } public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) { Checks.checkNotNull(subject); return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>( MyCustomViewHolder.class) { @Oviewride protected boolean matchesSafely(MyCustomViewHolder viewHolder) { TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id); return ((subject.equals(subjectTextView.getText().toString()) && (subjectTextView.getVisibility() == View.VISIBLE))); } @Oviewride public void describeTo(Description description) { description.appendText("item with subject: " + subject); } }; } }; public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) { Checks.checkNotNull(subject); return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>( MyCustomViewHolder.class) { @Oviewride protected boolean matchesSafely(MyCustomViewHolder viewHolder) { TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id); return ((subject.equals(subjectTextView.getText().toString()) && (subjectTextView.getVisibility() == View.VISIBLE))); } @Oviewride public void describeTo(Description description) { description.appendText("item with subject: " + subject); } }; } 

    E uso:

     onView(withId(R.id.my_recycler_view_id) .perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click())); 

    Basicamente você pode combinair o que quiser. Neste exemplo, usamos o assunto TextView mas pode ser qualquer elemento dentro do item RecyclerView .

    Mais uma coisa a esclairecer é viewificair a visibilidade (subjectTextView.getVisibility() == View.VISIBLE) . Precisamos tê-lo porque às vezes outras visualizações dentro do RecyclerView podem ter o mesmo assunto, mas seria com View.GONE . Desta forma, evitamos combinações múltiplas do nosso jogo personalizado e do único alvo que realmente exibe nosso assunto.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.